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/DeclTemplate.h"
17 #include "clang/AST/DependenceFlags.h"
18 #include "clang/AST/NestedNameSpecifier.h"
19 #include "clang/AST/PrettyPrinter.h"
20 #include "clang/AST/TemplateBase.h"
21 #include "clang/Basic/Diagnostic.h"
22 #include "clang/Basic/LLVM.h"
23 #include "clang/Basic/LangOptions.h"
24 #include "clang/Basic/OperatorKinds.h"
25 #include "llvm/ADT/ArrayRef.h"
26 #include "llvm/ADT/FoldingSet.h"
27 #include "llvm/Support/Casting.h"
28 #include "llvm/Support/Compiler.h"
29 #include "llvm/Support/raw_ostream.h"
30 #include <cassert>
31 #include <string>
32
33 using namespace clang;
34
35 TemplateArgument
getArgumentPack() const36 SubstTemplateTemplateParmPackStorage::getArgumentPack() const {
37 return TemplateArgument(llvm::makeArrayRef(Arguments, size()));
38 }
39
Profile(llvm::FoldingSetNodeID & ID)40 void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID) {
41 Profile(ID, Parameter, Replacement);
42 }
43
Profile(llvm::FoldingSetNodeID & ID,TemplateTemplateParmDecl * parameter,TemplateName replacement)44 void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID,
45 TemplateTemplateParmDecl *parameter,
46 TemplateName replacement) {
47 ID.AddPointer(parameter);
48 ID.AddPointer(replacement.getAsVoidPointer());
49 }
50
Profile(llvm::FoldingSetNodeID & ID,ASTContext & Context)51 void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
52 ASTContext &Context) {
53 Profile(ID, Context, Parameter, getArgumentPack());
54 }
55
Profile(llvm::FoldingSetNodeID & ID,ASTContext & Context,TemplateTemplateParmDecl * Parameter,const TemplateArgument & ArgPack)56 void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
57 ASTContext &Context,
58 TemplateTemplateParmDecl *Parameter,
59 const TemplateArgument &ArgPack) {
60 ID.AddPointer(Parameter);
61 ArgPack.Profile(ID, Context);
62 }
63
TemplateName(void * Ptr)64 TemplateName::TemplateName(void *Ptr) {
65 Storage = StorageType::getFromOpaqueValue(Ptr);
66 }
67
TemplateName(TemplateDecl * Template)68 TemplateName::TemplateName(TemplateDecl *Template) : Storage(Template) {}
TemplateName(OverloadedTemplateStorage * Storage)69 TemplateName::TemplateName(OverloadedTemplateStorage *Storage)
70 : Storage(Storage) {}
TemplateName(AssumedTemplateStorage * Storage)71 TemplateName::TemplateName(AssumedTemplateStorage *Storage)
72 : Storage(Storage) {}
TemplateName(SubstTemplateTemplateParmStorage * Storage)73 TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage)
74 : Storage(Storage) {}
TemplateName(SubstTemplateTemplateParmPackStorage * Storage)75 TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage)
76 : Storage(Storage) {}
TemplateName(QualifiedTemplateName * Qual)77 TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {}
TemplateName(DependentTemplateName * Dep)78 TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {}
79
isNull() const80 bool TemplateName::isNull() const { return Storage.isNull(); }
81
getKind() const82 TemplateName::NameKind TemplateName::getKind() const {
83 if (Storage.is<TemplateDecl *>())
84 return Template;
85 if (Storage.is<DependentTemplateName *>())
86 return DependentTemplate;
87 if (Storage.is<QualifiedTemplateName *>())
88 return QualifiedTemplate;
89
90 UncommonTemplateNameStorage *uncommon
91 = Storage.get<UncommonTemplateNameStorage*>();
92 if (uncommon->getAsOverloadedStorage())
93 return OverloadedTemplate;
94 if (uncommon->getAsAssumedTemplateName())
95 return AssumedTemplate;
96 if (uncommon->getAsSubstTemplateTemplateParm())
97 return SubstTemplateTemplateParm;
98 return SubstTemplateTemplateParmPack;
99 }
100
getAsTemplateDecl() const101 TemplateDecl *TemplateName::getAsTemplateDecl() const {
102 if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
103 return Template;
104
105 if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
106 return QTN->getTemplateDecl();
107
108 if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm())
109 return sub->getReplacement().getAsTemplateDecl();
110
111 return nullptr;
112 }
113
getAsOverloadedTemplate() const114 OverloadedTemplateStorage *TemplateName::getAsOverloadedTemplate() const {
115 if (UncommonTemplateNameStorage *Uncommon =
116 Storage.dyn_cast<UncommonTemplateNameStorage *>())
117 return Uncommon->getAsOverloadedStorage();
118
119 return nullptr;
120 }
121
getAsAssumedTemplateName() const122 AssumedTemplateStorage *TemplateName::getAsAssumedTemplateName() const {
123 if (UncommonTemplateNameStorage *Uncommon =
124 Storage.dyn_cast<UncommonTemplateNameStorage *>())
125 return Uncommon->getAsAssumedTemplateName();
126
127 return nullptr;
128 }
129
130 SubstTemplateTemplateParmStorage *
getAsSubstTemplateTemplateParm() const131 TemplateName::getAsSubstTemplateTemplateParm() const {
132 if (UncommonTemplateNameStorage *uncommon =
133 Storage.dyn_cast<UncommonTemplateNameStorage *>())
134 return uncommon->getAsSubstTemplateTemplateParm();
135
136 return nullptr;
137 }
138
139 SubstTemplateTemplateParmPackStorage *
getAsSubstTemplateTemplateParmPack() const140 TemplateName::getAsSubstTemplateTemplateParmPack() const {
141 if (UncommonTemplateNameStorage *Uncommon =
142 Storage.dyn_cast<UncommonTemplateNameStorage *>())
143 return Uncommon->getAsSubstTemplateTemplateParmPack();
144
145 return nullptr;
146 }
147
getAsQualifiedTemplateName() const148 QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const {
149 return Storage.dyn_cast<QualifiedTemplateName *>();
150 }
151
getAsDependentTemplateName() const152 DependentTemplateName *TemplateName::getAsDependentTemplateName() const {
153 return Storage.dyn_cast<DependentTemplateName *>();
154 }
155
getNameToSubstitute() const156 TemplateName TemplateName::getNameToSubstitute() const {
157 TemplateDecl *Decl = getAsTemplateDecl();
158
159 // Substituting a dependent template name: preserve it as written.
160 if (!Decl)
161 return *this;
162
163 // If we have a template declaration, use the most recent non-friend
164 // declaration of that template.
165 Decl = cast<TemplateDecl>(Decl->getMostRecentDecl());
166 while (Decl->getFriendObjectKind()) {
167 Decl = cast<TemplateDecl>(Decl->getPreviousDecl());
168 assert(Decl && "all declarations of template are friends");
169 }
170 return TemplateName(Decl);
171 }
172
getDependence() const173 TemplateNameDependence TemplateName::getDependence() const {
174 auto D = TemplateNameDependence::None;
175 switch (getKind()) {
176 case TemplateName::NameKind::QualifiedTemplate:
177 D |= toTemplateNameDependence(
178 getAsQualifiedTemplateName()->getQualifier()->getDependence());
179 break;
180 case TemplateName::NameKind::DependentTemplate:
181 D |= toTemplateNameDependence(
182 getAsDependentTemplateName()->getQualifier()->getDependence());
183 break;
184 case TemplateName::NameKind::SubstTemplateTemplateParmPack:
185 D |= TemplateNameDependence::UnexpandedPack;
186 break;
187 case TemplateName::NameKind::OverloadedTemplate:
188 llvm_unreachable("overloaded templates shouldn't survive to here.");
189 default:
190 break;
191 }
192 if (TemplateDecl *Template = getAsTemplateDecl()) {
193 if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Template)) {
194 D |= TemplateNameDependence::DependentInstantiation;
195 if (TTP->isParameterPack())
196 D |= TemplateNameDependence::UnexpandedPack;
197 }
198 // FIXME: Hack, getDeclContext() can be null if Template is still
199 // initializing due to PCH reading, so we check it before using it.
200 // Should probably modify TemplateSpecializationType to allow constructing
201 // it without the isDependent() checking.
202 if (Template->getDeclContext() &&
203 Template->getDeclContext()->isDependentContext())
204 D |= TemplateNameDependence::DependentInstantiation;
205 } else {
206 D |= TemplateNameDependence::DependentInstantiation;
207 }
208 return D;
209 }
210
isDependent() const211 bool TemplateName::isDependent() const {
212 return getDependence() & TemplateNameDependence::Dependent;
213 }
214
isInstantiationDependent() const215 bool TemplateName::isInstantiationDependent() const {
216 return getDependence() & TemplateNameDependence::Instantiation;
217 }
218
containsUnexpandedParameterPack() const219 bool TemplateName::containsUnexpandedParameterPack() const {
220 return getDependence() & TemplateNameDependence::UnexpandedPack;
221 }
222
223 void
print(raw_ostream & OS,const PrintingPolicy & Policy,bool SuppressNNS) const224 TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
225 bool SuppressNNS) const {
226 if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
227 OS << *Template;
228 else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
229 if (!SuppressNNS)
230 QTN->getQualifier()->print(OS, Policy);
231 if (QTN->hasTemplateKeyword())
232 OS << "template ";
233 OS << *QTN->getDecl();
234 } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
235 if (!SuppressNNS && DTN->getQualifier())
236 DTN->getQualifier()->print(OS, Policy);
237 OS << "template ";
238
239 if (DTN->isIdentifier())
240 OS << DTN->getIdentifier()->getName();
241 else
242 OS << "operator " << getOperatorSpelling(DTN->getOperator());
243 } else if (SubstTemplateTemplateParmStorage *subst
244 = getAsSubstTemplateTemplateParm()) {
245 subst->getReplacement().print(OS, Policy, SuppressNNS);
246 } else if (SubstTemplateTemplateParmPackStorage *SubstPack
247 = getAsSubstTemplateTemplateParmPack())
248 OS << *SubstPack->getParameterPack();
249 else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {
250 Assumed->getDeclName().print(OS, Policy);
251 } else {
252 OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
253 (*OTS->begin())->printName(OS);
254 }
255 }
256
operator <<(const StreamingDiagnostic & DB,TemplateName N)257 const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
258 TemplateName N) {
259 std::string NameStr;
260 llvm::raw_string_ostream OS(NameStr);
261 LangOptions LO;
262 LO.CPlusPlus = true;
263 LO.Bool = true;
264 OS << '\'';
265 N.print(OS, PrintingPolicy(LO));
266 OS << '\'';
267 OS.flush();
268 return DB << NameStr;
269 }
270
dump(raw_ostream & OS) const271 void TemplateName::dump(raw_ostream &OS) const {
272 LangOptions LO; // FIXME!
273 LO.CPlusPlus = true;
274 LO.Bool = true;
275 print(OS, PrintingPolicy(LO));
276 }
277
dump() const278 LLVM_DUMP_METHOD void TemplateName::dump() const {
279 dump(llvm::errs());
280 }
281