diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 8edd3b30ca6..e474287d199 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -789,15 +789,37 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac return instantiation; } + if (allBases.isEmpty() || allBases.size() == knownUsings.size()) + return reference; + + QList fullyQualifiedNameForReferenceClass = + LookupContext::fullyQualifiedName(referenceClass); // Find the missing bases for regular (non-template) types. // Ex.: class A : public B::Type {}; foreach (const Name *baseName, allBases) { ClassOrNamespace *binding = this; if (const QualifiedNameId *qBaseName = baseName->asQualifiedNameId()) { + QList fullyQualifiedNameForBaseClass; + addNames(baseName, &fullyQualifiedNameForBaseClass); + if (compareFullyQualifiedName(fullyQualifiedNameForReferenceClass, + fullyQualifiedNameForBaseClass)) { + continue; + } + if (const Name *qualification = qBaseName->base()) binding = lookupType(qualification); + else if (binding->parent() != 0) + //if this is global identifier we take global namespace + //Ex: class A{}; namespace NS { class A: public ::A{}; } + binding = binding->globalNamespace(); + else + //if we are in the global scope + continue; baseName = qBaseName->name(); } + else if (compareName(name, baseName)) { + continue; + } if (binding) { ClassOrNamespace * baseBinding = binding->lookupType(baseName); @@ -806,7 +828,6 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac } } - return reference; } diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index a6681bb3981..08e14bd67a6 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -231,7 +231,7 @@ void CppToolsPlugin::test_completion_template_1() QVERIFY(!completions.contains("func")); } -void CppToolsPlugin::test_completion_template_as_base() +void CppToolsPlugin::test_completion() { QFETCH(QByteArray, code); QFETCH(QStringList, expectedCompletions); @@ -253,6 +253,11 @@ void CppToolsPlugin::test_completion_template_as_base() QCOMPARE(actualCompletions, expectedCompletions); } +void CppToolsPlugin::test_completion_template_as_base() +{ + test_completion(); +} + void CppToolsPlugin::test_completion_template_as_base_data() { QTest::addColumn("code"); @@ -399,3 +404,271 @@ void CppToolsPlugin::test_completion_template_as_base_data() completions.append("otherMember"); QTest::newRow("case: base as template name in non-template") << code << completions; } + +void CppToolsPlugin::test_completion_use_global_identifier_as_base_class() +{ + test_completion(); +} + +void CppToolsPlugin::test_completion_use_global_identifier_as_base_class_data() +{ + QTest::addColumn("code"); + QTest::addColumn("expectedCompletions"); + + QByteArray code; + QStringList completions; + + code = "\n" + "struct Global\n" + "{\n" + " int int_global;\n" + "};\n" + "\n" + "struct Final : ::Global\n" + "{\n" + " int int_final;\n" + "};\n" + "\n" + "Final c;\n" + "@\n" + "// padding so we get the scope right\n"; + + completions.append("int_global"); + completions.append("int_final"); + completions.append("Final"); + completions.append("Global"); + QTest::newRow("case: derived as global and base as global") << code << completions; + + completions.clear(); + + code = "\n" + "struct Global\n" + "{\n" + " int int_global;\n" + "};\n" + "\n" + "namespace NS\n" + "{\n" + "struct Final : ::Global\n" + "{\n" + " int int_final;\n" + "};\n" + "}\n" + "\n" + "NS::Final c;\n" + "@\n" + "// padding so we get the scope right\n"; + + completions.append("int_global"); + completions.append("int_final"); + completions.append("Final"); + completions.append("Global"); + QTest::newRow("case: derived is inside namespace, base as global") + << code << completions; + + completions.clear(); + + //this test does not work due to the bug QTCREATORBUG-7912 + + +// code = "\n" +// "struct Global\n" +// "{\n" +// " int int_global;\n" +// "};\n" +// "\n" +// "template \n" +// "struct Enclosing\n" +// "{\n" +// "struct Final : ::Global\n" +// "{\n" +// " int int_final;\n" +// "};\n" +// "}\n" +// "\n" +// "Enclosing::Final c;\n" +// "@\n" +// "// padding so we get the scope right\n"; + +// completions.append("int_global"); +// completions.append("int_final"); +// completions.append("Final"); +// completions.append("Global"); +// QTest::newRow("case: derived is enclosed by template, base as global") +// << code << completions; + +// completions.clear(); +} + +void CppToolsPlugin::test_completion_base_class_has_name_the_same_as_derived() +{ + test_completion(); +} + +void CppToolsPlugin::test_completion_base_class_has_name_the_same_as_derived_data() +{ + QTest::addColumn("code"); + QTest::addColumn("expectedCompletions"); + + QByteArray code; + QStringList completions; + + code = "\n" + "struct A : A\n" + "{\n" + " int int_a;\n" + "};\n" + "\n" + "A c;\n" + "@\n" + "// padding so we get the scope right\n"; + + completions.append("int_a"); + completions.append("A"); + QTest::newRow("case: base class is derived class") << code << completions; + + completions.clear(); + + code = "\n" + "namespace NS\n" + "{\n" + "struct A : A\n" + "{\n" + " int int_a;\n" + "};\n" + "}\n" + "\n" + "NS::A c;\n" + "@\n" + "// padding so we get the scope right\n"; + + completions.append("int_a"); + completions.append("A"); + QTest::newRow("case: base class is derived class. class is in namespace") + << code << completions; + + completions.clear(); + + code = "\n" + "namespace NS\n" + "{\n" + "struct A : NS::A\n" + "{\n" + " int int_a;\n" + "};\n" + "}\n" + "\n" + "NS::A c;\n" + "@\n" + "// padding so we get the scope right\n"; + + completions.append("int_a"); + completions.append("A"); + QTest::newRow("case: base class is derived class. class is in namespace. " + "use scope operator for base class") << code << completions; + + completions.clear(); + + code = "\n" + "namespace NS1\n" + "{\n" + "struct A\n" + "{\n" + " int int_ns1_a;\n" + "};\n" + "}\n" + "namespace NS2\n" + "{\n" + "struct A : NS1::A\n" + "{\n" + " int int_ns2_a;\n" + "};\n" + "}\n" + "\n" + "NS2::A c;\n" + "@\n" + "// padding so we get the scope right\n"; + + completions.append("int_ns1_a"); + completions.append("int_ns2_a"); + completions.append("A"); + QTest::newRow("case: base class has the same name as derived but in different namespace") + << code << completions; + + completions.clear(); + + code = "\n" + "struct Enclosing\n" + "{\n" + "struct A\n" + "{\n" + " int int_enclosing_a;\n" + "};\n" + "};\n" + "namespace NS2\n" + "{\n" + "struct A : Enclosing::A\n" + "{\n" + " int int_ns2_a;\n" + "};\n" + "}\n" + "\n" + "NS2::A c;\n" + "@\n" + "// padding so we get the scope right\n"; + + completions.append("int_enclosing_a"); + completions.append("int_ns2_a"); + completions.append("A"); + QTest::newRow("case: base class has the same name as derived(in namespace) " + "but is nested by different class") << code << completions; + + completions.clear(); + + code = "\n" + "struct EnclosingBase\n" + "{\n" + "struct A\n" + "{\n" + " int int_enclosing_base_a;\n" + "};\n" + "};\n" + "struct EnclosingDerived\n" + "{\n" + "struct A : EnclosingBase::A\n" + "{\n" + " int int_enclosing_derived_a;\n" + "};\n" + "};\n" + "\n" + "EnclosingDerived::A c;\n" + "@\n" + "// padding so we get the scope right\n"; + + completions.append("int_enclosing_base_a"); + completions.append("int_enclosing_derived_a"); + completions.append("A"); + QTest::newRow("case: base class has the same name as derived(nested) " + "but is nested by different class") << code << completions; + + completions.clear(); + + code = "\n" + "template \n" + "struct A : A\n" + "{\n" + " int int_a;\n" + "};\n" + "\n" + "A c;\n" + "@\n" + "// padding so we get the scope right\n"; + + completions.append("int_a"); + completions.append("A"); + QTest::newRow("case: base class is derived class. class is a template") + << code << completions; + + completions.clear(); + +} diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index ba88d11896e..554a1877832 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -77,6 +77,7 @@ private slots: void switchHeaderSource(); #ifdef WITH_TESTS + // codegen tests void test_codegen_public_in_empty_class(); void test_codegen_public_in_nonempty_class(); @@ -95,6 +96,13 @@ private slots: void test_completion_template_1(); void test_completion_template_as_base(); void test_completion_template_as_base_data(); + void test_completion_use_global_identifier_as_base_class(); + void test_completion_use_global_identifier_as_base_class_data(); + void test_completion_base_class_has_name_the_same_as_derived(); + void test_completion_base_class_has_name_the_same_as_derived_data(); + +private: + void test_completion(); #endif private: