Commit 13913ed3 authored by Przemyslaw Gorszkowski's avatar Przemyslaw Gorszkowski Committed by Erik Verbruggen
Browse files

C++: fix support for typedef of templated typedefs



Fix:
* code completion
* follow symbols
* find usages

Task-number: QTCREATORBUG-8375
Change-Id: I6f35e809ba15f224c5a6d9b2fcfc18dbfba55411
Reviewed-by: default avatarSergey Shambir <sergey.shambir.auto@gmail.com>
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent 357ffaa8
......@@ -719,10 +719,43 @@ ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
if (name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) {
flush();
if (name->isTemplateNameId()) {
// if it is a base specialization, the 'name' could be an instantiation
QMap<const TemplateNameId *, ClassOrNamespace *>::iterator it
= _instantiations.find(name->asTemplateNameId());
if (it != _instantiations.end())
return it.value();
}
foreach (Symbol *s, symbols()) {
if (Class *klass = s->asClass()) {
if (klass->identifier() && klass->identifier()->isEqualTo(name->identifier()))
return this;
// it can be a typedef
const unsigned memberClassCount = klass->memberCount();
for (unsigned i = 0; i < memberClassCount; ++i) {
Symbol *memberClassAsSymbol = klass->memberAt(i);
if (Declaration *declaration = memberClassAsSymbol->asDeclaration()) {
if (declaration->isTypedef()
&& name->identifier()->isEqualTo(declaration->name()->identifier
())) {
if (NamedType *namedType = declaration->type()->asNamedType()) {
QSet<ClassOrNamespace *> innerProcessed;
const Name *namedTypeName = namedType->name();
const QualifiedNameId *q = namedTypeName->asQualifiedNameId();
if (q && name->isEqualTo(q->base())
&& name->isEqualTo(q->name())) {
return lookupType_helper_inParent(name, &innerProcessed,
searchInEnclosingScope,
origin);
}
return lookupType_helper(namedTypeName, &innerProcessed,
true, origin);
}
}
}
}
}
}
......@@ -746,6 +779,9 @@ ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
}
foreach (ClassOrNamespace *u, usings()) {
// usings are not instantiated for templates
if (_templateId && u->_templateId)
continue;
if (ClassOrNamespace *r = u->lookupType_helper(name,
processed,
/*searchInEnclosingScope =*/ false,
......@@ -754,8 +790,21 @@ ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
}
}
if (_parent && searchInEnclosingScope)
return _parent->lookupType_helper(name, processed, searchInEnclosingScope, origin);
return lookupType_helper_inParent(name, processed, searchInEnclosingScope, origin);
}
return 0;
}
ClassOrNamespace *ClassOrNamespace::lookupType_helper_inParent(const Name *name, QSet<ClassOrNamespace *> *processed,
bool searchInEnclosingScope, ClassOrNamespace *origin)
{
if (_parent && searchInEnclosingScope) {
// for templates _parent is a base specialization,
// so we should take here rather _parent of this base specialization
ClassOrNamespace *parent = _templateId ? _parent->_parent : _parent;
if (parent)
return parent->lookupType_helper(name, processed, searchInEnclosingScope, origin);
}
return 0;
......@@ -959,7 +1008,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
oo.showReturnTypes = true;
oo.showTemplateParameters = true;
qDebug()<<"cloned"<<oo(clone->type());
if (Class *klass = s->asClass()) {
if (Class *klass = clone->asClass()) {
const unsigned klassMemberCount = klass->memberCount();
for (unsigned i = 0; i < klassMemberCount; ++i){
Symbol *klassMemberAsSymbol = klass->memberAt(i);
......
......@@ -111,6 +111,9 @@ private:
ClassOrNamespace *lookupType_helper(const Name *name, QSet<ClassOrNamespace *> *processed,
bool searchInEnclosingScope, ClassOrNamespace *origin);
ClassOrNamespace *lookupType_helper_inParent(const Name *name, QSet<ClassOrNamespace *> *processed,
bool searchInEnclosingScope, ClassOrNamespace *origin);
ClassOrNamespace *nestedType(const Name *name, ClassOrNamespace *origin);
void instantiateNestedClasses(ClassOrNamespace *enclosingTemplateClass,
......
......@@ -690,8 +690,15 @@ bool ResolveExpression::visit(CallAST *ast)
}
} else if (Function *funTy = ty->asFunctionType()) {
if (maybeValidPrototype(funTy, actualArgumentCount))
addResult(funTy->returnType().simplified(), scope);
if (maybeValidPrototype(funTy, actualArgumentCount)) {
LookupItem item;
item.setType(funTy->returnType().simplified());
item.setScope(scope);
// we have to remember a binding because it can be a template instantiation
item.setBinding(result.binding());
_results.append(item);
}
} else if (Class *classTy = ty->asClassType()) {
// Constructor call
......
......@@ -1882,3 +1882,77 @@ void CppToolsPlugin::test_completion_QTCREATORBUG9098()
QVERIFY(completions.contains(QLatin1String("c")));
QVERIFY(completions.contains(QLatin1String("B")));
}
void CppToolsPlugin::test_completion_typedef_of_templated_typedef_QTCREATORBUG8375()
{
TestData data;
data.srcText =
"struct Foo\n"
"{ void bar(); };\n"
"struct A\n"
"{ typedef Foo AFoo; };\n"
"template <class T>\n"
"struct B\n"
"{ typedef typename T::AFoo BFoo; };\n"
"struct C : public B<A>\n"
"{\n"
" void test()\n"
" {\n"
" BFoo foo;\n"
" @\n"
" // padding so we get the scope right\n"
" }\n"
"};\n"
;
setup(&data);
Utils::ChangeSet change;
QString txt = QLatin1String("foo.");
change.insert(data.pos, txt);
QTextCursor cursor(data.doc);
change.apply(&cursor);
data.pos += txt.length();
QStringList completions = getCompletions(data);
QCOMPARE(completions.size(), 2);
QVERIFY(completions.contains(QLatin1String("Foo")));
QVERIFY(completions.contains(QLatin1String("bar")));
}
void CppToolsPlugin::test_completion_typedef_with_the_same_base_name_and_new_type_name()
{
TestData data;
data.srcText =
"namespace A\n"
"{\n"
"struct A { int aa; };\n"
"}\n"
"struct S\n"
"{\n"
" typedef A::A A;\n"
" A a;\n"
"};\n"
"void fun()\n"
"{\n"
" S s;\n"
" @\n"
" // padding so we get the scope right\n"
"};\n"
;
setup(&data);
Utils::ChangeSet change;
QString txt = QLatin1String("s.a.");
change.insert(data.pos, txt);
QTextCursor cursor(data.doc);
change.apply(&cursor);
data.pos += txt.length();
QStringList completions = getCompletions(data);
QCOMPARE(completions.size(), 2);
QVERIFY(completions.contains(QLatin1String("A")));
QVERIFY(completions.contains(QLatin1String("aa")));
}
......@@ -124,6 +124,8 @@ private slots:
void test_completion_typedef_using_templates2();
void test_completion_namespace_alias_with_many_namespace_declarations();
void test_completion_QTCREATORBUG9098();
void test_completion_typedef_of_templated_typedef_QTCREATORBUG8375();
void test_completion_typedef_with_the_same_base_name_and_new_type_name();
void test_format_pointerdeclaration_in_simpledeclarations();
void test_format_pointerdeclaration_in_simpledeclarations_data();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment