diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index c20e85459ee..ef259bb2545 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -752,6 +752,12 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac const TemplateNameId *templId = name->asTemplateNameId(); if (templId) { + // for "using" we should use the real one ClassOrNamespace(it should be the first + // one item from usings list) + // we indicate that it is a 'using' by checking number of symbols(it should be 0) + if (reference->symbols().count() == 0 && reference->usings().count() != 0) + reference = reference->_usings[0]; + // if it is a TemplateNameId it could be a specialization(full or partial) or // instantiation of one of the specialization(reference->_specialization) or // base class(reference) diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 23c9b201b86..db69deb0ed8 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -835,8 +835,9 @@ public: void resolve(FullySpecifiedType *type, Scope **scope, ClassOrNamespace *binding) { QSet visited; + _binding = binding; while (NamedType *namedTy = getNamedType(*type)) { - QList namedTypeItems = getNamedTypeItems(namedTy->name(), *scope, binding); + QList namedTypeItems = getNamedTypeItems(namedTy->name(), *scope, _binding); #ifdef DEBUG_LOOKUP qDebug() << "-- we have" << namedTypeItems.size() << "candidates"; @@ -908,7 +909,7 @@ private: } bool findTypedef(const QList& namedTypeItems, FullySpecifiedType *type, - Scope **scope, QSet& visited) const + Scope **scope, QSet& visited) { bool foundTypedef = false; foreach (const LookupItem &it, namedTypeItems) { @@ -921,6 +922,7 @@ private: // continue working with the typedefed type and scope *type = declaration->type(); *scope = it.scope(); + _binding = it.binding(); foundTypedef = true; break; } @@ -930,6 +932,8 @@ private: } const LookupContext &_context; + // binding has to be remembered in case of resolving typedefs for templates + ClassOrNamespace *_binding; }; ClassOrNamespace *ResolveExpression::baseExpression(const QList &baseResults, diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index 34ea48fee28..6e35e263dab 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -1646,3 +1646,108 @@ void CppToolsPlugin::test_completion_template_specialization_with_pointer() QVERIFY(completions.contains(QLatin1String("Template"))); QVERIFY(completions.contains(QLatin1String("pointer"))); } + +void CppToolsPlugin::test_completion_typedef_using_templates1() +{ + TestData data; + data.srcText = "\n" + "namespace NS1\n" + "{\n" + "template\n" + "struct NS1Struct\n" + "{\n" + " typedef T *pointer;\n" + " pointer bar;\n" + "};\n" + "}\n" + "namespace NS2\n" + "{\n" + "using NS1::NS1Struct;\n" + "\n" + "template \n" + "struct NS2Struct\n" + "{\n" + " typedef NS1Struct NS1StructTypedef;\n" + " typedef typename NS1StructTypedef::pointer pointer;\n" + " pointer p;\n" + "};\n" + "}\n" + "struct Foo\n" + "{\n" + " int bar;\n" + "};\n" + "void fun()\n" + "{\n" + " NS2::NS2Struct s;\n" + " @\n" + " // padding so we get the scope right\n" + "}\n" + ; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("s.p->"); + 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_using_templates2() +{ + TestData data; + data.srcText = "\n" + "namespace NS1\n" + "{\n" + "template\n" + "struct NS1Struct\n" + "{\n" + " typedef T *pointer;\n" + " pointer bar;\n" + "};\n" + "}\n" + "namespace NS2\n" + "{\n" + "using NS1::NS1Struct;\n" + "\n" + "template \n" + "struct NS2Struct\n" + "{\n" + " typedef NS1Struct NS1StructTypedef;\n" + " typedef typename NS1StructTypedef::pointer pointer;\n" + " pointer p;\n" + "};\n" + "}\n" + "struct Foo\n" + "{\n" + " int bar;\n" + "};\n" + "void fun()\n" + "{\n" + " NS2::NS2Struct::pointer p;\n" + " @\n" + " // padding so we get the scope right\n" + "}\n" + ; + setup(&data); + + Utils::ChangeSet change; + QString txt = QLatin1String("p->"); + 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"))); +} diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index fd9f18b7e8c..fcb4d417e32 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -124,6 +124,8 @@ private slots: void test_completion_typedef_is_inside_function_before_declaration_block(); void test_completion_resolve_complex_typedef_with_template(); void test_completion_template_specialization_with_pointer(); + void test_completion_typedef_using_templates1(); + void test_completion_typedef_using_templates2(); void test_format_pointerdeclaration_in_simpledeclarations(); void test_format_pointerdeclaration_in_simpledeclarations_data();