[Clang] Unify interface for accessing template arguments as written for class/variable template specializations (#81642)
Our current method of storing the template arguments as written for
`(Class/Var)Template(Partial)SpecializationDecl` suffers from a number
of flaws:
- We use `TypeSourceInfo` to store `TemplateArgumentLocs` for class
template/variable template partial/explicit specializations. For
variable template specializations, this is a rather unintuitive hack (as
we store a non-type specialization as a type). Moreover, we don't ever
*need* the type as written -- in almost all cases, we only want the
template arguments (e.g. in tooling use-cases).
- The template arguments as written are stored in a number of redundant
data members. For example, `(Class/Var)TemplatePartialSpecialization`
have their own `ArgsAsWritten` member that stores an
`ASTTemplateArgumentListInfo` (the template arguments).
`VarTemplateSpecializationDecl` has yet _another_ redundant member
"`TemplateArgsInfo`" that also stores an `ASTTemplateArgumentListInfo`.
This patch eliminates all
`(Class/Var)Template(Partial)SpecializationDecl` members which store the
template arguments as written, and turns the `ExplicitInfo` member into
a `llvm::PointerUnion<const ASTTemplateArgumentListInfo*,
ExplicitInstantiationInfo*>` (to avoid unnecessary allocations when the
declaration isn't an explicit instantiation). The template arguments as
written are now accessed via `getTemplateArgsWritten` in all cases.
The "most breaking" change is to AST Matchers, insofar that `hasTypeLoc`
will no longer match class template specializations (since they no
longer store the type as written).
GitOrigin-RevId: 7115ed0fff027b65fa76fdfae215ed1382ed1473
diff --git a/clangd/AST.cpp b/clangd/AST.cpp
index 1b86ea1..fda1e5f 100644
--- a/clangd/AST.cpp
+++ b/clangd/AST.cpp
@@ -50,16 +50,11 @@
if (const ASTTemplateArgumentListInfo *Args =
Func->getTemplateSpecializationArgsAsWritten())
return Args->arguments();
- } else if (auto *Cls =
- llvm::dyn_cast<ClassTemplatePartialSpecializationDecl>(&ND)) {
+ } else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
if (auto *Args = Cls->getTemplateArgsAsWritten())
return Args->arguments();
- } else if (auto *Var =
- llvm::dyn_cast<VarTemplatePartialSpecializationDecl>(&ND)) {
- if (auto *Args = Var->getTemplateArgsAsWritten())
- return Args->arguments();
} else if (auto *Var = llvm::dyn_cast<VarTemplateSpecializationDecl>(&ND)) {
- if (auto *Args = Var->getTemplateArgsInfo())
+ if (auto *Args = Var->getTemplateArgsAsWritten())
return Args->arguments();
}
// We return std::nullopt for ClassTemplateSpecializationDecls because it does
@@ -270,22 +265,10 @@
getTemplateSpecializationArgLocs(ND)) {
printTemplateArgumentList(OS, *Args, Policy);
} else if (auto *Cls = llvm::dyn_cast<ClassTemplateSpecializationDecl>(&ND)) {
- if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) {
- // ClassTemplateSpecializationDecls do not contain
- // TemplateArgumentTypeLocs, they only have TemplateArgumentTypes. So we
- // create a new argument location list from TypeSourceInfo.
- auto STL = TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
- llvm::SmallVector<TemplateArgumentLoc> ArgLocs;
- ArgLocs.reserve(STL.getNumArgs());
- for (unsigned I = 0; I < STL.getNumArgs(); ++I)
- ArgLocs.push_back(STL.getArgLoc(I));
- printTemplateArgumentList(OS, ArgLocs, Policy);
- } else {
- // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST,
- // e.g. friend decls. Currently we fallback to Template Arguments without
- // location information.
- printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy);
- }
+ // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST,
+ // e.g. friend decls. Currently we fallback to Template Arguments without
+ // location information.
+ printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy);
}
OS.flush();
return TemplateArgs;
@@ -453,10 +436,12 @@
}
QualType declaredType(const TypeDecl *D) {
+ ASTContext &Context = D->getASTContext();
if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
- if (const auto *TSI = CTSD->getTypeAsWritten())
- return TSI->getType();
- return D->getASTContext().getTypeDeclType(D);
+ if (const auto *Args = CTSD->getTemplateArgsAsWritten())
+ return Context.getTemplateSpecializationType(
+ TemplateName(CTSD->getSpecializedTemplate()), Args->arguments());
+ return Context.getTypeDeclType(D);
}
namespace {
diff --git a/clangd/SemanticHighlighting.cpp b/clangd/SemanticHighlighting.cpp
index 08f99e1..eb025f2 100644
--- a/clangd/SemanticHighlighting.cpp
+++ b/clangd/SemanticHighlighting.cpp
@@ -693,17 +693,22 @@
return true;
}
- bool VisitClassTemplatePartialSpecializationDecl(
- ClassTemplatePartialSpecializationDecl *D) {
- if (auto *TPL = D->getTemplateParameters())
- H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
+ bool
+ VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D) {
if (auto *Args = D->getTemplateArgsAsWritten())
H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
return true;
}
+ bool VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ if (auto *TPL = D->getTemplateParameters())
+ H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
+ return true;
+ }
+
bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) {
- if (auto *Args = D->getTemplateArgsInfo())
+ if (auto *Args = D->getTemplateArgsAsWritten())
H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
return true;
}
@@ -712,8 +717,6 @@
VarTemplatePartialSpecializationDecl *D) {
if (auto *TPL = D->getTemplateParameters())
H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
- if (auto *Args = D->getTemplateArgsAsWritten())
- H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
return true;
}
diff --git a/include-cleaner/lib/WalkAST.cpp b/include-cleaner/lib/WalkAST.cpp
index 878067a..f7cc9d1 100644
--- a/include-cleaner/lib/WalkAST.cpp
+++ b/include-cleaner/lib/WalkAST.cpp
@@ -267,18 +267,21 @@
return true;
}
- // Report a reference from explicit specializations to the specialized
- // template. Implicit ones are filtered out by RAV and explicit instantiations
- // are already traversed through typelocs.
+ // Report a reference from explicit specializations/instantiations to the
+ // specialized template. Implicit ones are filtered out by RAV.
bool
VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *CTSD) {
- if (CTSD->isExplicitSpecialization())
+ // if (CTSD->isExplicitSpecialization())
+ if (clang::isTemplateExplicitInstantiationOrSpecialization(
+ CTSD->getTemplateSpecializationKind()))
report(CTSD->getLocation(),
CTSD->getSpecializedTemplate()->getTemplatedDecl());
return true;
}
bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *VTSD) {
- if (VTSD->isExplicitSpecialization())
+ // if (VTSD->isExplicitSpecialization())
+ if (clang::isTemplateExplicitInstantiationOrSpecialization(
+ VTSD->getTemplateSpecializationKind()))
report(VTSD->getLocation(),
VTSD->getSpecializedTemplate()->getTemplatedDecl());
return true;