xref: /freebsd/contrib/llvm-project/clang/lib/AST/TemplateName.cpp (revision d56accc7c3dcc897489b6a07834763a03b9f3d68)
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
36 SubstTemplateTemplateParmPackStorage::getArgumentPack() const {
37   return TemplateArgument(llvm::makeArrayRef(Arguments, size()));
38 }
39 
40 void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID) {
41   Profile(ID, Parameter, Replacement);
42 }
43 
44 void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID,
45                                            TemplateTemplateParmDecl *parameter,
46                                                TemplateName replacement) {
47   ID.AddPointer(parameter);
48   ID.AddPointer(replacement.getAsVoidPointer());
49 }
50 
51 void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
52                                                    ASTContext &Context) {
53   Profile(ID, Context, Parameter, getArgumentPack());
54 }
55 
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 
64 TemplateName::TemplateName(void *Ptr) {
65   Storage = StorageType::getFromOpaqueValue(Ptr);
66 }
67 
68 TemplateName::TemplateName(TemplateDecl *Template) : Storage(Template) {}
69 TemplateName::TemplateName(OverloadedTemplateStorage *Storage)
70     : Storage(Storage) {}
71 TemplateName::TemplateName(AssumedTemplateStorage *Storage)
72     : Storage(Storage) {}
73 TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage)
74     : Storage(Storage) {}
75 TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage)
76     : Storage(Storage) {}
77 TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {}
78 TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {}
79 
80 bool TemplateName::isNull() const { return Storage.isNull(); }
81 
82 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 
101 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 
114 OverloadedTemplateStorage *TemplateName::getAsOverloadedTemplate() const {
115   if (UncommonTemplateNameStorage *Uncommon =
116           Storage.dyn_cast<UncommonTemplateNameStorage *>())
117     return Uncommon->getAsOverloadedStorage();
118 
119   return nullptr;
120 }
121 
122 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 *
131 TemplateName::getAsSubstTemplateTemplateParm() const {
132   if (UncommonTemplateNameStorage *uncommon =
133           Storage.dyn_cast<UncommonTemplateNameStorage *>())
134     return uncommon->getAsSubstTemplateTemplateParm();
135 
136   return nullptr;
137 }
138 
139 SubstTemplateTemplateParmPackStorage *
140 TemplateName::getAsSubstTemplateTemplateParmPack() const {
141   if (UncommonTemplateNameStorage *Uncommon =
142           Storage.dyn_cast<UncommonTemplateNameStorage *>())
143     return Uncommon->getAsSubstTemplateTemplateParmPack();
144 
145   return nullptr;
146 }
147 
148 QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const {
149   return Storage.dyn_cast<QualifiedTemplateName *>();
150 }
151 
152 DependentTemplateName *TemplateName::getAsDependentTemplateName() const {
153   return Storage.dyn_cast<DependentTemplateName *>();
154 }
155 
156 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 
173 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 
211 bool TemplateName::isDependent() const {
212   return getDependence() & TemplateNameDependence::Dependent;
213 }
214 
215 bool TemplateName::isInstantiationDependent() const {
216   return getDependence() & TemplateNameDependence::Instantiation;
217 }
218 
219 bool TemplateName::containsUnexpandedParameterPack() const {
220   return getDependence() & TemplateNameDependence::UnexpandedPack;
221 }
222 
223 void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
224                          Qualified Qual) const {
225   if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
226     if (Policy.CleanUglifiedParameters &&
227         isa<TemplateTemplateParmDecl>(Template) && Template->getIdentifier())
228       OS << Template->getIdentifier()->deuglifiedName();
229     else if (Qual == Qualified::Fully &&
230              getDependence() !=
231                  TemplateNameDependenceScope::DependentInstantiation)
232       Template->printQualifiedName(OS, Policy);
233     else
234       OS << *Template;
235   else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
236     if (Qual == Qualified::Fully &&
237         getDependence() !=
238             TemplateNameDependenceScope::DependentInstantiation) {
239       QTN->getTemplateDecl()->printQualifiedName(OS, Policy);
240       return;
241     }
242     if (Qual == Qualified::AsWritten)
243       QTN->getQualifier()->print(OS, Policy);
244     if (QTN->hasTemplateKeyword())
245       OS << "template ";
246     OS << *QTN->getDecl();
247   } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
248     if (Qual == Qualified::AsWritten && DTN->getQualifier())
249       DTN->getQualifier()->print(OS, Policy);
250     OS << "template ";
251 
252     if (DTN->isIdentifier())
253       OS << DTN->getIdentifier()->getName();
254     else
255       OS << "operator " << getOperatorSpelling(DTN->getOperator());
256   } else if (SubstTemplateTemplateParmStorage *subst
257                = getAsSubstTemplateTemplateParm()) {
258     subst->getReplacement().print(OS, Policy, Qual);
259   } else if (SubstTemplateTemplateParmPackStorage *SubstPack
260                                         = getAsSubstTemplateTemplateParmPack())
261     OS << *SubstPack->getParameterPack();
262   else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) {
263     Assumed->getDeclName().print(OS, Policy);
264   } else {
265     OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
266     (*OTS->begin())->printName(OS);
267   }
268 }
269 
270 const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
271                                              TemplateName N) {
272   std::string NameStr;
273   llvm::raw_string_ostream OS(NameStr);
274   LangOptions LO;
275   LO.CPlusPlus = true;
276   LO.Bool = true;
277   OS << '\'';
278   N.print(OS, PrintingPolicy(LO));
279   OS << '\'';
280   OS.flush();
281   return DB << NameStr;
282 }
283 
284 void TemplateName::dump(raw_ostream &OS) const {
285   LangOptions LO;  // FIXME!
286   LO.CPlusPlus = true;
287   LO.Bool = true;
288   print(OS, PrintingPolicy(LO));
289 }
290 
291 LLVM_DUMP_METHOD void TemplateName::dump() const {
292   dump(llvm::errs());
293 }
294