diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index dde50df687f772a0f29bc34e9572bb3e61f67fe0..6df4b43cf36e93435fd48d6237427319e4d12180 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -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); diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h index 3dbe525766a3c4656660ff0a1a51eeea9fd108c9..d1e64cdd87f5be723ac9ffa0274e47f9dc9c70e2 100644 --- a/src/libs/cplusplus/LookupContext.h +++ b/src/libs/cplusplus/LookupContext.h @@ -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, diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 029bcee00d43092ed6eb6d16d3e36aa26325cef1..8a72fc1fc2a70ff8f1c9872dad05a925edcc9c55 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -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 diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index b8ee95f7c04a879581c8f3f4cd4c94cc39cc6535..70a5469b1234d911f8d3d29213bea818dedbf89c 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -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"))); +} + diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index 10975a53013d09e1f02aed4de8a230a5041c2670..3bfb64688be07da66b8081259e612802eeeb84df 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -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();