1//===- TemplateName.cpp - C++ Template Name Representation ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the TemplateName interface and subclasses.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/TemplateName.h"
14#include "clang/AST/Decl.h"
15#include "clang/AST/DeclBase.h"
16#include "clang/AST/DeclCXX.h"
17#include "clang/AST/DeclTemplate.h"
18#include "clang/AST/DependenceFlags.h"
19#include "clang/AST/NestedNameSpecifier.h"
20#include "clang/AST/PrettyPrinter.h"
21#include "clang/AST/TemplateBase.h"
22#include "clang/Basic/Diagnostic.h"
23#include "clang/Basic/LLVM.h"
24#include "clang/Basic/LangOptions.h"
25#include "clang/Basic/OperatorKinds.h"
26#include "llvm/ADT/ArrayRef.h"
27#include "llvm/ADT/FoldingSet.h"
28#include "llvm/Support/Casting.h"
29#include "llvm/Support/Compiler.h"
30#include "llvm/Support/raw_ostream.h"
31#include <cassert>
32#include <optional>
33#include <string>
34
35using namespace clang;
36
37TemplateArgument
38SubstTemplateTemplateParmPackStorage::getArgumentPack() const {
39 return TemplateArgument(llvm::ArrayRef(Arguments, Bits.Data));
40}
41
42TemplateTemplateParmDecl *
43SubstTemplateTemplateParmPackStorage::getParameterPack() const {
44 return cast<TemplateTemplateParmDecl>(
45 Val: getReplacedTemplateParameterList(D: getAssociatedDecl())
46 ->asArray()[Bits.Index]);
47}
48
49TemplateTemplateParmDecl *
50SubstTemplateTemplateParmStorage::getParameter() const {
51 return cast<TemplateTemplateParmDecl>(
52 Val: getReplacedTemplateParameterList(D: getAssociatedDecl())
53 ->asArray()[Bits.Index]);
54}
55
56void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID) {
57 Profile(ID, Replacement, AssociatedDecl: getAssociatedDecl(), Index: getIndex(), PackIndex: getPackIndex());
58}
59
60void SubstTemplateTemplateParmStorage::Profile(
61 llvm::FoldingSetNodeID &ID, TemplateName Replacement, Decl *AssociatedDecl,
62 unsigned Index, std::optional<unsigned> PackIndex) {
63 Replacement.Profile(ID);
64 ID.AddPointer(Ptr: AssociatedDecl);
65 ID.AddInteger(I: Index);
66 ID.AddInteger(I: PackIndex ? *PackIndex + 1 : 0);
67}
68
69SubstTemplateTemplateParmPackStorage::SubstTemplateTemplateParmPackStorage(
70 ArrayRef<TemplateArgument> ArgPack, Decl *AssociatedDecl, unsigned Index,
71 bool Final)
72 : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Index,
73 ArgPack.size()),
74 Arguments(ArgPack.data()), AssociatedDeclAndFinal(AssociatedDecl, Final) {
75 assert(AssociatedDecl != nullptr);
76}
77
78void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
79 ASTContext &Context) {
80 Profile(ID, Context, ArgPack: getArgumentPack(), AssociatedDecl: getAssociatedDecl(), Index: getIndex(),
81 Final: getFinal());
82}
83
84Decl *SubstTemplateTemplateParmPackStorage::getAssociatedDecl() const {
85 return AssociatedDeclAndFinal.getPointer();
86}
87
88bool SubstTemplateTemplateParmPackStorage::getFinal() const {
89 return AssociatedDeclAndFinal.getInt();
90}
91
92void SubstTemplateTemplateParmPackStorage::Profile(
93 llvm::FoldingSetNodeID &ID, ASTContext &Context,
94 const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index,
95 bool Final) {
96 ArgPack.Profile(ID, Context);
97 ID.AddPointer(Ptr: AssociatedDecl);
98 ID.AddInteger(I: Index);
99 ID.AddBoolean(B: Final);
100}
101
102TemplateName::TemplateName(void *Ptr) {
103 Storage = StorageType::getFromOpaqueValue(VP: Ptr);
104}
105
106TemplateName::TemplateName(TemplateDecl *Template) : Storage(Template) {}
107TemplateName::TemplateName(OverloadedTemplateStorage *Storage)
108 : Storage(Storage) {}
109TemplateName::TemplateName(AssumedTemplateStorage *Storage)
110 : Storage(Storage) {}
111TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage)
112 : Storage(Storage) {}
113TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage)
114 : Storage(Storage) {}
115TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {}
116TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {}
117TemplateName::TemplateName(UsingShadowDecl *Using) : Storage(Using) {}
118
119bool TemplateName::isNull() const { return Storage.isNull(); }
120
121TemplateName::NameKind TemplateName::getKind() const {
122 if (auto *ND = Storage.dyn_cast<Decl *>()) {
123 if (isa<UsingShadowDecl>(Val: ND))
124 return UsingTemplate;
125 assert(isa<TemplateDecl>(ND));
126 return Template;
127 }
128
129 if (Storage.is<DependentTemplateName *>())
130 return DependentTemplate;
131 if (Storage.is<QualifiedTemplateName *>())
132 return QualifiedTemplate;
133
134 UncommonTemplateNameStorage *uncommon
135 = Storage.get<UncommonTemplateNameStorage*>();
136 if (uncommon->getAsOverloadedStorage())
137 return OverloadedTemplate;
138 if (uncommon->getAsAssumedTemplateName())
139 return AssumedTemplate;
140 if (uncommon->getAsSubstTemplateTemplateParm())
141 return SubstTemplateTemplateParm;
142 return SubstTemplateTemplateParmPack;
143}
144
145TemplateDecl *TemplateName::getAsTemplateDecl() const {
146 if (Decl *TemplateOrUsing = Storage.dyn_cast<Decl *>()) {
147 if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(Val: TemplateOrUsing))
148 return cast<TemplateDecl>(Val: USD->getTargetDecl());
149
150 assert(isa<TemplateDecl>(TemplateOrUsing));
151 return cast<TemplateDecl>(Val: TemplateOrUsing);
152 }
153
154 if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
155 return QTN->getUnderlyingTemplate().getAsTemplateDecl();
156
157 if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm())
158 return sub->getReplacement().getAsTemplateDecl();
159
160 if (UsingShadowDecl *USD = getAsUsingShadowDecl())
161 return cast<TemplateDecl>(Val: USD->getTargetDecl());
162
163 return nullptr;
164}
165
166OverloadedTemplateStorage *TemplateName::getAsOverloadedTemplate() const {
167 if (UncommonTemplateNameStorage *Uncommon =
168 Storage.dyn_cast<UncommonTemplateNameStorage *>())
169 return Uncommon->getAsOverloadedStorage();
170
171 return nullptr;
172}
173
174AssumedTemplateStorage *TemplateName::getAsAssumedTemplateName() const {
175 if (UncommonTemplateNameStorage *Uncommon =
176 Storage.dyn_cast<UncommonTemplateNameStorage *>())
177 return Uncommon->getAsAssumedTemplateName();
178
179 return nullptr;
180}
181
182SubstTemplateTemplateParmStorage *
183TemplateName::getAsSubstTemplateTemplateParm() const {
184 if (UncommonTemplateNameStorage *uncommon =
185 Storage.dyn_cast<UncommonTemplateNameStorage *>())
186 return uncommon->getAsSubstTemplateTemplateParm();
187
188 return nullptr;
189}
190
191SubstTemplateTemplateParmPackStorage *
192TemplateName::getAsSubstTemplateTemplateParmPack() const {
193 if (UncommonTemplateNameStorage *Uncommon =
194 Storage.dyn_cast<UncommonTemplateNameStorage *>())
195 return Uncommon->getAsSubstTemplateTemplateParmPack();
196
197 return nullptr;
198}
199
200QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const {
201 return Storage.dyn_cast<QualifiedTemplateName *>();
202}
203
204DependentTemplateName *TemplateName::getAsDependentTemplateName() const {
205 return Storage.dyn_cast<DependentTemplateName *>();
206}
207
208UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const {
209 if (Decl *D = Storage.dyn_cast<Decl *>())
210 if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(Val: D))
211 return USD;
212 if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
213 return QTN->getUnderlyingTemplate().getAsUsingShadowDecl();
214 return nullptr;
215}
216
217TemplateNameDependence TemplateName::getDependence() const {
218 auto D = TemplateNameDependence::None;
219 switch (getKind()) {
220 case TemplateName::NameKind::QualifiedTemplate:
221 if (NestedNameSpecifier *NNS = getAsQualifiedTemplateName()->getQualifier())
222 D |= toTemplateNameDependence(D: NNS->getDependence());
223 break;
224 case TemplateName::NameKind::DependentTemplate:
225 D |= toTemplateNameDependence(
226 D: getAsDependentTemplateName()->getQualifier()->getDependence());
227 break;
228 case TemplateName::NameKind::SubstTemplateTemplateParmPack:
229 D |= TemplateNameDependence::UnexpandedPack;
230 break;
231 case TemplateName::NameKind::OverloadedTemplate:
232 llvm_unreachable("overloaded templates shouldn't survive to here.");
233 default:
234 break;
235 }
236 if (TemplateDecl *Template = getAsTemplateDecl()) {
237 if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Val: Template)) {
238 D |= TemplateNameDependence::DependentInstantiation;
239 if (TTP->isParameterPack())
240 D |= TemplateNameDependence::UnexpandedPack;
241 }
242 // FIXME: Hack, getDeclContext() can be null if Template is still
243 // initializing due to PCH reading, so we check it before using it.
244 // Should probably modify TemplateSpecializationType to allow constructing
245 // it without the isDependent() checking.
246 if (Template->getDeclContext() &&
247 Template->getDeclContext()->isDependentContext())
248 D |= TemplateNameDependence::DependentInstantiation;
249 } else {
250 D |= TemplateNameDependence::DependentInstantiation;
251 }
252 return D;
253}
254
255bool TemplateName::isDependent() const {
256 return getDependence() & TemplateNameDependence::Dependent;
257}
258
259bool TemplateName::isInstantiationDependent() const {
260 return getDependence() & TemplateNameDependence::Instantiation;
261}
262
263bool TemplateName::containsUnexpandedParameterPack() const {
264 return getDependence() & TemplateNameDependence::UnexpandedPack;
265}
266
267void TemplateName::Profile(llvm::FoldingSetNodeID &ID) {
268 if (const auto* USD = getAsUsingShadowDecl())
269 ID.AddPointer(Ptr: USD->getCanonicalDecl());
270 else if (const auto *TD = getAsTemplateDecl())
271 ID.AddPointer(Ptr: TD->getCanonicalDecl());
272 else
273 ID.AddPointer(Ptr: Storage.getOpaqueValue());
274}
275
276void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
277 Qualified Qual) const {
278 auto handleAnonymousTTP = [](TemplateDecl *TD, raw_ostream &OS) {
279 if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(Val: TD);
280 TTP && TTP->getIdentifier() == nullptr) {
281 OS << "template-parameter-" << TTP->getDepth() << "-" << TTP->getIndex();
282 return true;
283 }
284 return false;
285 };
286 if (NameKind Kind = getKind();
287 Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) {
288 // After `namespace ns { using std::vector }`, what is the fully-qualified
289 // name of the UsingTemplateName `vector` within ns?
290 //
291 // - ns::vector (the qualified name of the using-shadow decl)
292 // - std::vector (the qualified name of the underlying template decl)
293 //
294 // Similar to the UsingType behavior, using declarations are used to import
295 // names more often than to export them, thus using the original name is
296 // most useful in this case.
297 TemplateDecl *Template = getAsTemplateDecl();
298 if (handleAnonymousTTP(Template, OS))
299 return;
300 if (Qual == Qualified::None)
301 OS << *Template;
302 else
303 Template->printQualifiedName(OS, Policy);
304 } else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
305 if (NestedNameSpecifier *NNS = QTN->getQualifier();
306 Qual != Qualified::None && NNS)
307 NNS->print(OS, Policy);
308 if (QTN->hasTemplateKeyword())
309 OS << "template ";
310
311 TemplateName Underlying = QTN->getUnderlyingTemplate();
312 assert(Underlying.getKind() == TemplateName::Template ||
313 Underlying.getKind() == TemplateName::UsingTemplate);
314
315 TemplateDecl *UTD = Underlying.getAsTemplateDecl();
316
317 if (handleAnonymousTTP(UTD, OS))
318 return;
319
320 if (IdentifierInfo *II = UTD->getIdentifier();
321 Policy.CleanUglifiedParameters && II &&
322 isa<TemplateTemplateParmDecl>(Val: UTD))
323 OS << II->deuglifiedName();
324 else
325 OS << *UTD;
326 } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
327 if (NestedNameSpecifier *NNS = DTN->getQualifier())
328 NNS->print(OS, Policy);
329 OS << "template ";
330
331 if (DTN->isIdentifier())
332 OS << DTN->getIdentifier()->getName();
333 else
334 OS << "operator " << getOperatorSpelling(Operator: DTN->getOperator());
335 } else if (SubstTemplateTemplateParmStorage *subst =
336 getAsSubstTemplateTemplateParm()) {
337 subst->getReplacement().print(OS, Policy, Qual);
338 } else if (SubstTemplateTemplateParmPackStorage *SubstPack =
339 getAsSubstTemplateTemplateParmPack())
340 OS << *SubstPack->getParameterPack();
341 else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {
342 Assumed->getDeclName().print(OS, Policy);
343 } else {
344 assert(getKind() == TemplateName::OverloadedTemplate);
345 OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
346 (*OTS->begin())->printName(OS, Policy);
347 }
348}
349
350const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
351 TemplateName N) {
352 std::string NameStr;
353 llvm::raw_string_ostream OS(NameStr);
354 LangOptions LO;
355 LO.CPlusPlus = true;
356 LO.Bool = true;
357 OS << '\'';
358 N.print(OS, Policy: PrintingPolicy(LO));
359 OS << '\'';
360 OS.flush();
361 return DB << NameStr;
362}
363