diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h index b203caa97a9..bf76e9a22a1 100644 --- a/src/plugins/cppeditor/cppeditorplugin.h +++ b/src/plugins/cppeditor/cppeditorplugin.h @@ -151,6 +151,8 @@ private slots: void test_quickfix_AddIncludeForUndefinedIdentifier_onSimpleName(); void test_quickfix_AddIncludeForUndefinedIdentifier_onNameOfQualifiedName(); void test_quickfix_AddIncludeForUndefinedIdentifier_onBaseOfQualifiedName(); + void test_quickfix_AddIncludeForUndefinedIdentifier_onTemplateName(); + void test_quickfix_AddIncludeForUndefinedIdentifier_onTemplateNameInsideArguments(); void test_quickfix_AddIncludeForUndefinedIdentifier_inserting_ignoremoc(); void test_quickfix_AddIncludeForUndefinedIdentifier_inserting_sortingTop(); void test_quickfix_AddIncludeForUndefinedIdentifier_inserting_sortingMiddle(); diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index 2f0b55a467e..7a5594344bb 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -2325,6 +2325,84 @@ void CppEditorPlugin::test_quickfix_AddIncludeForUndefinedIdentifier_onBaseOfQua QuickFixTestCase::run(testFiles, &factory, TestIncludePaths::globalIncludePath()); } +void CppEditorPlugin::test_quickfix_AddIncludeForUndefinedIdentifier_onTemplateName() +{ + QList testFiles; + + QByteArray original; + QByteArray expected; + + // Header File + original = "namespace N { template class Foo {}; }\n"; + expected = original; + testFiles << QuickFixTestDocument::create(TestIncludePaths::directoryOfTestFile().toUtf8() + + "/afile.h", original, expected); + + // Source File + original = + "#include \"header.h\"\n" + "\n" + "void f()\n" + "{\n" + " @N::Foo foo;\n" + "}\n" + ; + expected = + "#include \"afile.h\"\n" + "#include \"header.h\"\n" + "\n" + "void f()\n" + "{\n" + " N::Foo foo;\n" + "}\n" + ; + testFiles << QuickFixTestDocument::create(TestIncludePaths::directoryOfTestFile().toUtf8() + + "/afile.cpp", original, expected); + + // Do not use the test factory, at least once we want to go through the "full stack". + AddIncludeForUndefinedIdentifier factory; + QuickFixTestCase::run(testFiles, &factory, TestIncludePaths::globalIncludePath()); +} + +void CppEditorPlugin::test_quickfix_AddIncludeForUndefinedIdentifier_onTemplateNameInsideArguments() +{ + QList testFiles; + + QByteArray original; + QByteArray expected; + + // Header File + original = "namespace N { template class Foo {}; }\n"; + expected = original; + testFiles << QuickFixTestDocument::create(TestIncludePaths::directoryOfTestFile().toUtf8() + + "/afile.h", original, expected); + + // Source File + original = + "#include \"header.h\"\n" + "\n" + "void f()\n" + "{\n" + " N::Bar<@Foo> foo;\n" + "}\n" + ; + expected = + "#include \"afile.h\"\n" + "#include \"header.h\"\n" + "\n" + "void f()\n" + "{\n" + " N::Bar foo;\n" + "}\n" + ; + testFiles << QuickFixTestDocument::create(TestIncludePaths::directoryOfTestFile().toUtf8() + + "/afile.cpp", original, expected); + + // Do not use the test factory, at least once we want to go through the "full stack". + AddIncludeForUndefinedIdentifier factory; + QuickFixTestCase::run(testFiles, &factory, TestIncludePaths::globalIncludePath()); +} + /// Check: Ignore *.moc includes void CppEditorPlugin::test_quickfix_AddIncludeForUndefinedIdentifier_inserting_ignoremoc() { diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 97bc4cb3cec..829045f83ac 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -1910,6 +1910,10 @@ NameAST *nameUnderCursor(const QList &path) AST * const ast = path.at(i); if (SimpleNameAST *simpleName = ast->asSimpleName()) { nameAst = simpleName; + } else if (TemplateIdAST *templateId = ast->asTemplateId()) { + nameAst = templateId; + } else if (nameAst && ast->asNamedTypeSpecifier()) { + break; // Stop at "Foo" for "N::Bar<@Foo>" } else if (QualifiedNameAST *qualifiedName = ast->asQualifiedName()) { nameAst = qualifiedName; break; @@ -1937,15 +1941,28 @@ bool canLookup(const CppQuickFixInterface &interface, const NameAST *nameAst) return !existingResults.isEmpty(); } -QString unqualifiedName(const Name *name) +QString templateNameAsString(const TemplateNameId *templateName) +{ + const Identifier *id = templateName->identifier(); + return QString::fromUtf8(id->chars(), id->size()); +} + +// For templates, simply the name is returned, without '<...>'. +QString unqualifiedNameForLocator(const Name *name) { QTC_ASSERT(name, return QString()); const Overview oo; - if (const QualifiedNameId *qualifiedName = name->asQualifiedNameId()) - return oo.prettyName(qualifiedName->name()); - else + if (const QualifiedNameId *qualifiedName = name->asQualifiedNameId()) { + const Name *name = qualifiedName->name(); + if (const TemplateNameId *templateName = name->asTemplateNameId()) + return templateNameAsString(templateName); return oo.prettyName(name); + } else if (const TemplateNameId *templateName = name->asTemplateNameId()) { + return templateNameAsString(templateName); + } else { + return oo.prettyName(name); + } } } // anonymous namespace @@ -1964,7 +1981,7 @@ void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interfa if (canLookup(interface, nameAst)) return; // There are results, so include isn't needed - const QString className = unqualifiedName(nameAst->name); + const QString className = unqualifiedNameForLocator(nameAst->name); if (className.isEmpty()) return;