/src/llvm-project/clang/lib/AST/TemplateName.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
35 | | using namespace clang; |
36 | | |
37 | | TemplateArgument |
38 | 0 | SubstTemplateTemplateParmPackStorage::getArgumentPack() const { |
39 | 0 | return TemplateArgument(llvm::ArrayRef(Arguments, Bits.Data)); |
40 | 0 | } |
41 | | |
42 | | TemplateTemplateParmDecl * |
43 | 0 | SubstTemplateTemplateParmPackStorage::getParameterPack() const { |
44 | 0 | return cast<TemplateTemplateParmDecl>( |
45 | 0 | getReplacedTemplateParameterList(getAssociatedDecl()) |
46 | 0 | ->asArray()[Bits.Index]); |
47 | 0 | } |
48 | | |
49 | | TemplateTemplateParmDecl * |
50 | 0 | SubstTemplateTemplateParmStorage::getParameter() const { |
51 | 0 | return cast<TemplateTemplateParmDecl>( |
52 | 0 | getReplacedTemplateParameterList(getAssociatedDecl()) |
53 | 0 | ->asArray()[Bits.Index]); |
54 | 0 | } |
55 | | |
56 | 0 | void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID) { |
57 | 0 | Profile(ID, Replacement, getAssociatedDecl(), getIndex(), getPackIndex()); |
58 | 0 | } |
59 | | |
60 | | void SubstTemplateTemplateParmStorage::Profile( |
61 | | llvm::FoldingSetNodeID &ID, TemplateName Replacement, Decl *AssociatedDecl, |
62 | 0 | unsigned Index, std::optional<unsigned> PackIndex) { |
63 | 0 | Replacement.Profile(ID); |
64 | 0 | ID.AddPointer(AssociatedDecl); |
65 | 0 | ID.AddInteger(Index); |
66 | 0 | ID.AddInteger(PackIndex ? *PackIndex + 1 : 0); |
67 | 0 | } |
68 | | |
69 | | SubstTemplateTemplateParmPackStorage::SubstTemplateTemplateParmPackStorage( |
70 | | ArrayRef<TemplateArgument> ArgPack, Decl *AssociatedDecl, unsigned Index, |
71 | | bool Final) |
72 | | : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Index, |
73 | | ArgPack.size()), |
74 | 0 | Arguments(ArgPack.data()), AssociatedDeclAndFinal(AssociatedDecl, Final) { |
75 | 0 | assert(AssociatedDecl != nullptr); |
76 | 0 | } |
77 | | |
78 | | void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID, |
79 | 0 | ASTContext &Context) { |
80 | 0 | Profile(ID, Context, getArgumentPack(), getAssociatedDecl(), getIndex(), |
81 | 0 | getFinal()); |
82 | 0 | } |
83 | | |
84 | 0 | Decl *SubstTemplateTemplateParmPackStorage::getAssociatedDecl() const { |
85 | 0 | return AssociatedDeclAndFinal.getPointer(); |
86 | 0 | } |
87 | | |
88 | 0 | bool SubstTemplateTemplateParmPackStorage::getFinal() const { |
89 | 0 | return AssociatedDeclAndFinal.getInt(); |
90 | 0 | } |
91 | | |
92 | | void SubstTemplateTemplateParmPackStorage::Profile( |
93 | | llvm::FoldingSetNodeID &ID, ASTContext &Context, |
94 | | const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index, |
95 | 0 | bool Final) { |
96 | 0 | ArgPack.Profile(ID, Context); |
97 | 0 | ID.AddPointer(AssociatedDecl); |
98 | 0 | ID.AddInteger(Index); |
99 | 0 | ID.AddBoolean(Final); |
100 | 0 | } |
101 | | |
102 | 1 | TemplateName::TemplateName(void *Ptr) { |
103 | 1 | Storage = StorageType::getFromOpaqueValue(Ptr); |
104 | 1 | } |
105 | | |
106 | 0 | TemplateName::TemplateName(TemplateDecl *Template) : Storage(Template) {} |
107 | | TemplateName::TemplateName(OverloadedTemplateStorage *Storage) |
108 | 0 | : Storage(Storage) {} |
109 | | TemplateName::TemplateName(AssumedTemplateStorage *Storage) |
110 | 3.06k | : Storage(Storage) {} |
111 | | TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage) |
112 | 0 | : Storage(Storage) {} |
113 | | TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage) |
114 | 0 | : Storage(Storage) {} |
115 | 0 | TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {} |
116 | 0 | TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {} |
117 | 0 | TemplateName::TemplateName(UsingShadowDecl *Using) : Storage(Using) {} |
118 | | |
119 | 0 | bool TemplateName::isNull() const { return Storage.isNull(); } |
120 | | |
121 | 0 | TemplateName::NameKind TemplateName::getKind() const { |
122 | 0 | if (auto *ND = Storage.dyn_cast<Decl *>()) { |
123 | 0 | if (isa<UsingShadowDecl>(ND)) |
124 | 0 | return UsingTemplate; |
125 | 0 | assert(isa<TemplateDecl>(ND)); |
126 | 0 | return Template; |
127 | 0 | } |
128 | | |
129 | 0 | if (Storage.is<DependentTemplateName *>()) |
130 | 0 | return DependentTemplate; |
131 | 0 | if (Storage.is<QualifiedTemplateName *>()) |
132 | 0 | return QualifiedTemplate; |
133 | | |
134 | 0 | UncommonTemplateNameStorage *uncommon |
135 | 0 | = Storage.get<UncommonTemplateNameStorage*>(); |
136 | 0 | if (uncommon->getAsOverloadedStorage()) |
137 | 0 | return OverloadedTemplate; |
138 | 0 | if (uncommon->getAsAssumedTemplateName()) |
139 | 0 | return AssumedTemplate; |
140 | 0 | if (uncommon->getAsSubstTemplateTemplateParm()) |
141 | 0 | return SubstTemplateTemplateParm; |
142 | 0 | return SubstTemplateTemplateParmPack; |
143 | 0 | } |
144 | | |
145 | 0 | TemplateDecl *TemplateName::getAsTemplateDecl() const { |
146 | 0 | if (Decl *TemplateOrUsing = Storage.dyn_cast<Decl *>()) { |
147 | 0 | if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(TemplateOrUsing)) |
148 | 0 | return cast<TemplateDecl>(USD->getTargetDecl()); |
149 | | |
150 | 0 | assert(isa<TemplateDecl>(TemplateOrUsing)); |
151 | 0 | return cast<TemplateDecl>(TemplateOrUsing); |
152 | 0 | } |
153 | | |
154 | 0 | if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) |
155 | 0 | return QTN->getUnderlyingTemplate().getAsTemplateDecl(); |
156 | | |
157 | 0 | if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm()) |
158 | 0 | return sub->getReplacement().getAsTemplateDecl(); |
159 | | |
160 | 0 | if (UsingShadowDecl *USD = getAsUsingShadowDecl()) |
161 | 0 | return cast<TemplateDecl>(USD->getTargetDecl()); |
162 | | |
163 | 0 | return nullptr; |
164 | 0 | } |
165 | | |
166 | 0 | OverloadedTemplateStorage *TemplateName::getAsOverloadedTemplate() const { |
167 | 0 | if (UncommonTemplateNameStorage *Uncommon = |
168 | 0 | Storage.dyn_cast<UncommonTemplateNameStorage *>()) |
169 | 0 | return Uncommon->getAsOverloadedStorage(); |
170 | | |
171 | 0 | return nullptr; |
172 | 0 | } |
173 | | |
174 | 2 | AssumedTemplateStorage *TemplateName::getAsAssumedTemplateName() const { |
175 | 2 | if (UncommonTemplateNameStorage *Uncommon = |
176 | 2 | Storage.dyn_cast<UncommonTemplateNameStorage *>()) |
177 | 2 | return Uncommon->getAsAssumedTemplateName(); |
178 | | |
179 | 0 | return nullptr; |
180 | 2 | } |
181 | | |
182 | | SubstTemplateTemplateParmStorage * |
183 | 0 | TemplateName::getAsSubstTemplateTemplateParm() const { |
184 | 0 | if (UncommonTemplateNameStorage *uncommon = |
185 | 0 | Storage.dyn_cast<UncommonTemplateNameStorage *>()) |
186 | 0 | return uncommon->getAsSubstTemplateTemplateParm(); |
187 | | |
188 | 0 | return nullptr; |
189 | 0 | } |
190 | | |
191 | | SubstTemplateTemplateParmPackStorage * |
192 | 0 | TemplateName::getAsSubstTemplateTemplateParmPack() const { |
193 | 0 | if (UncommonTemplateNameStorage *Uncommon = |
194 | 0 | Storage.dyn_cast<UncommonTemplateNameStorage *>()) |
195 | 0 | return Uncommon->getAsSubstTemplateTemplateParmPack(); |
196 | | |
197 | 0 | return nullptr; |
198 | 0 | } |
199 | | |
200 | 0 | QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const { |
201 | 0 | return Storage.dyn_cast<QualifiedTemplateName *>(); |
202 | 0 | } |
203 | | |
204 | 0 | DependentTemplateName *TemplateName::getAsDependentTemplateName() const { |
205 | 0 | return Storage.dyn_cast<DependentTemplateName *>(); |
206 | 0 | } |
207 | | |
208 | 0 | UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { |
209 | 0 | if (Decl *D = Storage.dyn_cast<Decl *>()) |
210 | 0 | if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) |
211 | 0 | return USD; |
212 | 0 | if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) |
213 | 0 | return QTN->getUnderlyingTemplate().getAsUsingShadowDecl(); |
214 | 0 | return nullptr; |
215 | 0 | } |
216 | | |
217 | 0 | TemplateName TemplateName::getNameToSubstitute() const { |
218 | 0 | TemplateDecl *Decl = getAsTemplateDecl(); |
219 | | |
220 | | // Substituting a dependent template name: preserve it as written. |
221 | 0 | if (!Decl) |
222 | 0 | return *this; |
223 | | |
224 | | // If we have a template declaration, use the most recent non-friend |
225 | | // declaration of that template. |
226 | 0 | Decl = cast<TemplateDecl>(Decl->getMostRecentDecl()); |
227 | 0 | while (Decl->getFriendObjectKind()) { |
228 | 0 | Decl = cast<TemplateDecl>(Decl->getPreviousDecl()); |
229 | 0 | assert(Decl && "all declarations of template are friends"); |
230 | 0 | } |
231 | 0 | return TemplateName(Decl); |
232 | 0 | } |
233 | | |
234 | 0 | TemplateNameDependence TemplateName::getDependence() const { |
235 | 0 | auto D = TemplateNameDependence::None; |
236 | 0 | switch (getKind()) { |
237 | 0 | case TemplateName::NameKind::QualifiedTemplate: |
238 | 0 | D |= toTemplateNameDependence( |
239 | 0 | getAsQualifiedTemplateName()->getQualifier()->getDependence()); |
240 | 0 | break; |
241 | 0 | case TemplateName::NameKind::DependentTemplate: |
242 | 0 | D |= toTemplateNameDependence( |
243 | 0 | getAsDependentTemplateName()->getQualifier()->getDependence()); |
244 | 0 | break; |
245 | 0 | case TemplateName::NameKind::SubstTemplateTemplateParmPack: |
246 | 0 | D |= TemplateNameDependence::UnexpandedPack; |
247 | 0 | break; |
248 | 0 | case TemplateName::NameKind::OverloadedTemplate: |
249 | 0 | llvm_unreachable("overloaded templates shouldn't survive to here."); |
250 | 0 | default: |
251 | 0 | break; |
252 | 0 | } |
253 | 0 | if (TemplateDecl *Template = getAsTemplateDecl()) { |
254 | 0 | if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Template)) { |
255 | 0 | D |= TemplateNameDependence::DependentInstantiation; |
256 | 0 | if (TTP->isParameterPack()) |
257 | 0 | D |= TemplateNameDependence::UnexpandedPack; |
258 | 0 | } |
259 | | // FIXME: Hack, getDeclContext() can be null if Template is still |
260 | | // initializing due to PCH reading, so we check it before using it. |
261 | | // Should probably modify TemplateSpecializationType to allow constructing |
262 | | // it without the isDependent() checking. |
263 | 0 | if (Template->getDeclContext() && |
264 | 0 | Template->getDeclContext()->isDependentContext()) |
265 | 0 | D |= TemplateNameDependence::DependentInstantiation; |
266 | 0 | } else { |
267 | 0 | D |= TemplateNameDependence::DependentInstantiation; |
268 | 0 | } |
269 | 0 | return D; |
270 | 0 | } |
271 | | |
272 | 0 | bool TemplateName::isDependent() const { |
273 | 0 | return getDependence() & TemplateNameDependence::Dependent; |
274 | 0 | } |
275 | | |
276 | 0 | bool TemplateName::isInstantiationDependent() const { |
277 | 0 | return getDependence() & TemplateNameDependence::Instantiation; |
278 | 0 | } |
279 | | |
280 | 0 | bool TemplateName::containsUnexpandedParameterPack() const { |
281 | 0 | return getDependence() & TemplateNameDependence::UnexpandedPack; |
282 | 0 | } |
283 | | |
284 | 0 | void TemplateName::Profile(llvm::FoldingSetNodeID &ID) { |
285 | 0 | if (const auto* USD = getAsUsingShadowDecl()) |
286 | 0 | ID.AddPointer(USD->getCanonicalDecl()); |
287 | 0 | else if (const auto *TD = getAsTemplateDecl()) |
288 | 0 | ID.AddPointer(TD->getCanonicalDecl()); |
289 | 0 | else |
290 | 0 | ID.AddPointer(Storage.getOpaqueValue()); |
291 | 0 | } |
292 | | |
293 | | void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, |
294 | 0 | Qualified Qual) const { |
295 | 0 | auto Kind = getKind(); |
296 | 0 | TemplateDecl *Template = nullptr; |
297 | 0 | if (Kind == TemplateName::Template || Kind == TemplateName::UsingTemplate) { |
298 | | // After `namespace ns { using std::vector }`, what is the fully-qualified |
299 | | // name of the UsingTemplateName `vector` within ns? |
300 | | // |
301 | | // - ns::vector (the qualified name of the using-shadow decl) |
302 | | // - std::vector (the qualified name of the underlying template decl) |
303 | | // |
304 | | // Similar to the UsingType behavior, using declarations are used to import |
305 | | // names more often than to export them, thus using the original name is |
306 | | // most useful in this case. |
307 | 0 | Template = getAsTemplateDecl(); |
308 | 0 | } |
309 | |
|
310 | 0 | if (Template) |
311 | 0 | if (Policy.CleanUglifiedParameters && |
312 | 0 | isa<TemplateTemplateParmDecl>(Template) && Template->getIdentifier()) |
313 | 0 | OS << Template->getIdentifier()->deuglifiedName(); |
314 | 0 | else if (Qual == Qualified::Fully && |
315 | 0 | getDependence() != |
316 | 0 | TemplateNameDependenceScope::DependentInstantiation) |
317 | 0 | Template->printQualifiedName(OS, Policy); |
318 | 0 | else |
319 | 0 | OS << *Template; |
320 | 0 | else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { |
321 | 0 | if (Qual == Qualified::Fully && |
322 | 0 | getDependence() != |
323 | 0 | TemplateNameDependenceScope::DependentInstantiation) { |
324 | 0 | QTN->getUnderlyingTemplate().getAsTemplateDecl()->printQualifiedName( |
325 | 0 | OS, Policy); |
326 | 0 | return; |
327 | 0 | } |
328 | 0 | if (Qual == Qualified::AsWritten) |
329 | 0 | QTN->getQualifier()->print(OS, Policy); |
330 | 0 | if (QTN->hasTemplateKeyword()) |
331 | 0 | OS << "template "; |
332 | 0 | OS << *QTN->getUnderlyingTemplate().getAsTemplateDecl(); |
333 | 0 | } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { |
334 | 0 | if (Qual == Qualified::AsWritten && DTN->getQualifier()) |
335 | 0 | DTN->getQualifier()->print(OS, Policy); |
336 | 0 | OS << "template "; |
337 | |
|
338 | 0 | if (DTN->isIdentifier()) |
339 | 0 | OS << DTN->getIdentifier()->getName(); |
340 | 0 | else |
341 | 0 | OS << "operator " << getOperatorSpelling(DTN->getOperator()); |
342 | 0 | } else if (SubstTemplateTemplateParmStorage *subst |
343 | 0 | = getAsSubstTemplateTemplateParm()) { |
344 | 0 | subst->getReplacement().print(OS, Policy, Qual); |
345 | 0 | } else if (SubstTemplateTemplateParmPackStorage *SubstPack |
346 | 0 | = getAsSubstTemplateTemplateParmPack()) |
347 | 0 | OS << *SubstPack->getParameterPack(); |
348 | 0 | else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) { |
349 | 0 | Assumed->getDeclName().print(OS, Policy); |
350 | 0 | } else { |
351 | 0 | assert(getKind() == TemplateName::OverloadedTemplate); |
352 | 0 | OverloadedTemplateStorage *OTS = getAsOverloadedTemplate(); |
353 | 0 | (*OTS->begin())->printName(OS, Policy); |
354 | 0 | } |
355 | 0 | } |
356 | | |
357 | | const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB, |
358 | 0 | TemplateName N) { |
359 | 0 | std::string NameStr; |
360 | 0 | llvm::raw_string_ostream OS(NameStr); |
361 | 0 | LangOptions LO; |
362 | 0 | LO.CPlusPlus = true; |
363 | 0 | LO.Bool = true; |
364 | 0 | OS << '\''; |
365 | 0 | N.print(OS, PrintingPolicy(LO)); |
366 | 0 | OS << '\''; |
367 | 0 | OS.flush(); |
368 | 0 | return DB << NameStr; |
369 | 0 | } |
370 | | |
371 | 0 | void TemplateName::dump(raw_ostream &OS) const { |
372 | 0 | LangOptions LO; // FIXME! |
373 | 0 | LO.CPlusPlus = true; |
374 | 0 | LO.Bool = true; |
375 | 0 | print(OS, PrintingPolicy(LO)); |
376 | 0 | } |
377 | | |
378 | 0 | LLVM_DUMP_METHOD void TemplateName::dump() const { |
379 | 0 | dump(llvm::errs()); |
380 | 0 | } |