diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -21,6 +21,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/Support/Casting.h" @@ -81,9 +82,10 @@ if (llvm::isa_and_present(ND)) return ND; // This is the underlying decl used by TemplateSpecializationType, can be - // null when type is dependent if so fallback to primary template. + // null when type is dependent or not resolved to a pattern yet. + // If so, fallback to primary template. CXXRecordDecl *TD = TST->getAsCXXRecordDecl(); - if (!TD) + if (!TD || TD->getTemplateSpecializationKind() == TSK_Undeclared) return ND; // We ignore explicit instantiations. This might imply marking the wrong // declaration as used in specific cases, but seems like the right trade-off diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -144,6 +144,9 @@ ElementsAre(Decl::CXXRecord)); // Implicit instantiations references most relevant template. + EXPECT_THAT( + testWalk("template struct $explicit^Foo;", "^Foo x();"), + ElementsAre(Decl::Kind::ClassTemplate)); EXPECT_THAT( testWalk("template struct $explicit^Foo {};", "^Foo x;"), ElementsAre(Decl::CXXRecord)); @@ -154,9 +157,15 @@ ElementsAre(Decl::ClassTemplateSpecialization)); EXPECT_THAT(testWalk(R"cpp( template struct Foo {}; - template struct $explicit^Foo { void x(); };)cpp", + template struct $explicit^Foo {};)cpp", "^Foo x;"), ElementsAre(Decl::ClassTemplatePartialSpecialization)); + // Incomplete instantiations don't have a specific specialization associated. + EXPECT_THAT(testWalk(R"cpp( + template struct $explicit^Foo; + template struct Foo;)cpp", + "^Foo x();"), + ElementsAre(Decl::Kind::ClassTemplate)); EXPECT_THAT(testWalk(R"cpp( template struct $explicit^Foo {}; template struct Foo;)cpp",