[clang-tools-extra] 03101e1 - [include-cleaner] Attribute references to explicit specializations
Kadir Cetinkaya via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 24 03:43:16 PDT 2023
Author: Kadir Cetinkaya
Date: 2023-03-24T11:39:21+01:00
New Revision: 03101e141bf745f036be604e2a5a7c085eb02f5e
URL: https://github.com/llvm/llvm-project/commit/03101e141bf745f036be604e2a5a7c085eb02f5e
DIFF: https://github.com/llvm/llvm-project/commit/03101e141bf745f036be604e2a5a7c085eb02f5e.diff
LOG: [include-cleaner] Attribute references to explicit specializations
Fixes https://github.com/llvm/llvm-project/issues/61652
Differential Revision: https://reviews.llvm.org/D146732
Added:
Modified:
clang-tools-extra/include-cleaner/lib/WalkAST.cpp
clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
index 0ca84145721a6..e70a24367d6a9 100644
--- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
+++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
@@ -7,16 +7,19 @@
//===----------------------------------------------------------------------===//
#include "AnalysisInternal.h"
+#include "clang-include-cleaner/Types.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/Support/Casting.h"
namespace clang::include_cleaner {
@@ -62,6 +65,24 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
return resolveTemplateName(TST->getTemplateName());
return Base->getAsRecordDecl();
}
+ // Templated as TemplateSpecializationType and
+ // DeducedTemplateSpecializationType doesn't share a common base.
+ template <typename T>
+ // Picks the most specific specialization for a
+ // (Deduced)TemplateSpecializationType, while prioritizing using-decls.
+ NamedDecl *getMostRelevantTemplatePattern(const T *TST) {
+ // This is the underlying decl used by TemplateSpecializationType, can be
+ // null when type is dependent.
+ auto *RD = TST->getAsTagDecl();
+ auto *ND = resolveTemplateName(TST->getTemplateName());
+ // In case of exported template names always prefer the using-decl. This
+ // implies we'll point at the using-decl even when there's an explicit
+ // specializaiton using the exported name, but that's rare.
+ if (llvm::isa_and_present<UsingShadowDecl, TypeAliasTemplateDecl>(ND))
+ return ND;
+ // Fallback to primary template for dependent instantiations.
+ return RD ? RD : ND;
+ }
public:
ASTWalker(DeclCallback Callback) : Callback(Callback) {}
@@ -161,17 +182,15 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
}
bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
- // FIXME: Handle explicit specializations.
report(TL.getTemplateNameLoc(),
- resolveTemplateName(TL.getTypePtr()->getTemplateName()));
+ getMostRelevantTemplatePattern(TL.getTypePtr()));
return true;
}
bool VisitDeducedTemplateSpecializationTypeLoc(
DeducedTemplateSpecializationTypeLoc TL) {
- // FIXME: Handle specializations.
report(TL.getTemplateNameLoc(),
- resolveTemplateName(TL.getTypePtr()->getTemplateName()));
+ getMostRelevantTemplatePattern(TL.getTypePtr()));
return true;
}
diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
index 68b6b217a2e01..8fcc2b5886ae4 100644
--- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -114,6 +114,25 @@ TEST(WalkAST, TagType) {
// One explicit call from the TypeLoc in constructor spelling, another
// implicit reference through the constructor call.
testWalk("struct $explicit^$implicit^S { static int x; };", "auto y = ^S();");
+ testWalk("template<typename> struct $explicit^Foo {};", "^Foo<int> x;");
+ testWalk(R"cpp(
+ template<typename> struct Foo {};
+ template<> struct $explicit^Foo<int> {};)cpp",
+ "^Foo<int> x;");
+ testWalk(R"cpp(
+ template<typename> struct Foo {};
+ template<typename T> struct $explicit^Foo<T*> { void x(); };)cpp",
+ "^Foo<int *> x;");
+ testWalk(R"cpp(
+ template<typename> struct Foo {};
+ template struct $explicit^Foo<int>;)cpp",
+ "^Foo<int> x;");
+ // FIXME: This is broken due to
+ // https://github.com/llvm/llvm-project/issues/42259.
+ testWalk(R"cpp(
+ template<typename T> struct $explicit^Foo { Foo(T); };
+ template<> struct Foo<int> { void get(); Foo(int); };)cpp",
+ "^Foo x(3);");
}
TEST(WalkAST, Alias) {
@@ -124,6 +143,25 @@ TEST(WalkAST, Alias) {
"int y = ^x;");
testWalk("using $explicit^foo = int;", "^foo x;");
testWalk("struct S {}; using $explicit^foo = S;", "^foo x;");
+ testWalk(R"cpp(
+ template<typename> struct Foo {};
+ template<> struct Foo<int> {};
+ namespace ns { using ::$explicit^Foo; })cpp",
+ "ns::^Foo<int> x;");
+ testWalk(R"cpp(
+ template<typename> struct Foo {};
+ namespace ns { using ::Foo; }
+ template<> struct ns::$explicit^Foo<int> {};)cpp",
+ "^Foo<int> x;");
+ // AST doesn't have enough information to figure out whether specialization
+ // happened through an exported type or not. So err towards attributing use to
+ // the using-decl, specializations on the exported type should be rare and
+ // they're not permitted on type-aliases.
+ testWalk(R"cpp(
+ template<typename> struct Foo {};
+ namespace ns { using ::$explicit^Foo; }
+ template<> struct ns::Foo<int> {};)cpp",
+ "ns::^Foo<int> x;");
}
TEST(WalkAST, Using) {
@@ -183,10 +221,6 @@ TEST(WalkAST, TemplateNames) {
template <template <typename> typename> struct X {};
X<^S> x;)cpp");
testWalk("template<typename T> struct $explicit^S { S(T); };", "^S s(42);");
- // Should we mark the specialization instead?
- testWalk(
- "template<typename> struct $explicit^S {}; template <> struct S<int> {};",
- "^S<int> s;");
}
TEST(WalkAST, MemberExprs) {
More information about the cfe-commits
mailing list