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