This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG3d6d2ae6f490: [include-cleaner] Handle incomplete template specializations (authored by kadircet).
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D148158/new/ https://reviews.llvm.org/D148158 Files: clang-tools-extra/include-cleaner/lib/WalkAST.cpp clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp Index: clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp =================================================================== --- clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ 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<typename> struct $explicit^Foo;", "^Foo<int> x();"), + ElementsAre(Decl::Kind::ClassTemplate)); EXPECT_THAT( testWalk("template<typename> struct $explicit^Foo {};", "^Foo<int> x;"), ElementsAre(Decl::CXXRecord)); @@ -154,9 +157,15 @@ ElementsAre(Decl::ClassTemplateSpecialization)); EXPECT_THAT(testWalk(R"cpp( template<typename> struct Foo {}; - template<typename T> struct $explicit^Foo<T*> { void x(); };)cpp", + template<typename T> struct $explicit^Foo<T*> {};)cpp", "^Foo<int *> x;"), ElementsAre(Decl::ClassTemplatePartialSpecialization)); + // Incomplete instantiations don't have a specific specialization associated. + EXPECT_THAT(testWalk(R"cpp( + template<typename> struct $explicit^Foo; + template<typename T> struct Foo<T*>;)cpp", + "^Foo<int *> x();"), + ElementsAre(Decl::Kind::ClassTemplate)); EXPECT_THAT(testWalk(R"cpp( template<typename> struct $explicit^Foo {}; template struct Foo<int>;)cpp", Index: clang-tools-extra/include-cleaner/lib/WalkAST.cpp =================================================================== --- clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ 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<UsingShadowDecl, TypeAliasTemplateDecl>(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
Index: clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp =================================================================== --- clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ 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<typename> struct $explicit^Foo;", "^Foo<int> x();"), + ElementsAre(Decl::Kind::ClassTemplate)); EXPECT_THAT( testWalk("template<typename> struct $explicit^Foo {};", "^Foo<int> x;"), ElementsAre(Decl::CXXRecord)); @@ -154,9 +157,15 @@ ElementsAre(Decl::ClassTemplateSpecialization)); EXPECT_THAT(testWalk(R"cpp( template<typename> struct Foo {}; - template<typename T> struct $explicit^Foo<T*> { void x(); };)cpp", + template<typename T> struct $explicit^Foo<T*> {};)cpp", "^Foo<int *> x;"), ElementsAre(Decl::ClassTemplatePartialSpecialization)); + // Incomplete instantiations don't have a specific specialization associated. + EXPECT_THAT(testWalk(R"cpp( + template<typename> struct $explicit^Foo; + template<typename T> struct Foo<T*>;)cpp", + "^Foo<int *> x();"), + ElementsAre(Decl::Kind::ClassTemplate)); EXPECT_THAT(testWalk(R"cpp( template<typename> struct $explicit^Foo {}; template struct Foo<int>;)cpp", Index: clang-tools-extra/include-cleaner/lib/WalkAST.cpp =================================================================== --- clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ 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<UsingShadowDecl, TypeAliasTemplateDecl>(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
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits