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
34 SubstTemplateTemplateParmPackStorage::getArgumentPack() const {
35   return TemplateArgument(llvm::makeArrayRef(Arguments, size()));
36 }
37 
38 void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID) {
39   Profile(ID, Parameter, Replacement);
40 }
41 
42 void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID,
43                                            TemplateTemplateParmDecl *parameter,
44                                                TemplateName replacement) {
45   ID.AddPointer(parameter);
46   ID.AddPointer(replacement.getAsVoidPointer());
47 }
48 
49 void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
50                                                    ASTContext &Context) {
51   Profile(ID, Context, Parameter, getArgumentPack());
52 }
53 
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 
62 TemplateName::TemplateName(void *Ptr) {
63   Storage = StorageType::getFromOpaqueValue(Ptr);
64 }
65 
66 TemplateName::TemplateName(TemplateDecl *Template) : Storage(Template) {}
67 TemplateName::TemplateName(OverloadedTemplateStorage *Storage)
68     : Storage(Storage) {}
69 TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage)
70     : Storage(Storage) {}
71 TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage)
72     : Storage(Storage) {}
73 TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {}
74 TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {}
75 
76 bool TemplateName::isNull() const { return Storage.isNull(); }
77 
78 TemplateName::NameKind TemplateName::getKind() const {
79   if (Storage.is<TemplateDecl *>())
80     return Template;
81   if (Storage.is<DependentTemplateName *>())
82     return DependentTemplate;
83   if (Storage.is<QualifiedTemplateName *>())
84     return QualifiedTemplate;
85 
86   UncommonTemplateNameStorage *uncommon
87     = Storage.get<UncommonTemplateNameStorage*>();
88   if (uncommon->getAsOverloadedStorage())
89     return OverloadedTemplate;
90   if (uncommon->getAsSubstTemplateTemplateParm())
91     return SubstTemplateTemplateParm;
92   return SubstTemplateTemplateParmPack;
93 }
94 
95 TemplateDecl *TemplateName::getAsTemplateDecl() const {
96   if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
97     return Template;
98 
99   if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName())
100     return QTN->getTemplateDecl();
101 
102   if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm())
103     return sub->getReplacement().getAsTemplateDecl();
104 
105   return nullptr;
106 }
107 
108 OverloadedTemplateStorage *TemplateName::getAsOverloadedTemplate() const {
109   if (UncommonTemplateNameStorage *Uncommon =
110           Storage.dyn_cast<UncommonTemplateNameStorage *>())
111     return Uncommon->getAsOverloadedStorage();
112 
113   return nullptr;
114 }
115 
116 SubstTemplateTemplateParmStorage *
117 TemplateName::getAsSubstTemplateTemplateParm() const {
118   if (UncommonTemplateNameStorage *uncommon =
119           Storage.dyn_cast<UncommonTemplateNameStorage *>())
120     return uncommon->getAsSubstTemplateTemplateParm();
121 
122   return nullptr;
123 }
124 
125 SubstTemplateTemplateParmPackStorage *
126 TemplateName::getAsSubstTemplateTemplateParmPack() const {
127   if (UncommonTemplateNameStorage *Uncommon =
128           Storage.dyn_cast<UncommonTemplateNameStorage *>())
129     return Uncommon->getAsSubstTemplateTemplateParmPack();
130 
131   return nullptr;
132 }
133 
134 QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const {
135   return Storage.dyn_cast<QualifiedTemplateName *>();
136 }
137 
138 DependentTemplateName *TemplateName::getAsDependentTemplateName() const {
139   return Storage.dyn_cast<DependentTemplateName *>();
140 }
141 
142 TemplateName TemplateName::getNameToSubstitute() const {
143   TemplateDecl *Decl = getAsTemplateDecl();
144 
145   // Substituting a dependent template name: preserve it as written.
146   if (!Decl)
147     return *this;
148 
149   // If we have a template declaration, use the most recent non-friend
150   // declaration of that template.
151   Decl = cast<TemplateDecl>(Decl->getMostRecentDecl());
152   while (Decl->getFriendObjectKind()) {
153     Decl = cast<TemplateDecl>(Decl->getPreviousDecl());
154     assert(Decl && "all declarations of template are friends");
155   }
156   return TemplateName(Decl);
157 }
158 
159 bool TemplateName::isDependent() const {
160   if (TemplateDecl *Template = getAsTemplateDecl()) {
161     if (isa<TemplateTemplateParmDecl>(Template))
162       return true;
163     // FIXME: Hack, getDeclContext() can be null if Template is still
164     // initializing due to PCH reading, so we check it before using it.
165     // Should probably modify TemplateSpecializationType to allow constructing
166     // it without the isDependent() checking.
167     return Template->getDeclContext() &&
168            Template->getDeclContext()->isDependentContext();
169   }
170 
171   assert(!getAsOverloadedTemplate() &&
172          "overloaded templates shouldn't survive to here");
173 
174   return true;
175 }
176 
177 bool TemplateName::isInstantiationDependent() const {
178   if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
179     if (QTN->getQualifier()->isInstantiationDependent())
180       return true;
181   }
182 
183   return isDependent();
184 }
185 
186 bool TemplateName::containsUnexpandedParameterPack() const {
187   if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
188     if (QTN->getQualifier()->containsUnexpandedParameterPack())
189       return true;
190   }
191 
192   if (TemplateDecl *Template = getAsTemplateDecl()) {
193     if (TemplateTemplateParmDecl *TTP
194                                   = dyn_cast<TemplateTemplateParmDecl>(Template))
195       return TTP->isParameterPack();
196 
197     return false;
198   }
199 
200   if (DependentTemplateName *DTN = getAsDependentTemplateName())
201     return DTN->getQualifier() &&
202       DTN->getQualifier()->containsUnexpandedParameterPack();
203 
204   return getAsSubstTemplateTemplateParmPack() != nullptr;
205 }
206 
207 void
208 TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
209                     bool SuppressNNS) const {
210   if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
211     OS << *Template;
212   else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
213     if (!SuppressNNS)
214       QTN->getQualifier()->print(OS, Policy);
215     if (QTN->hasTemplateKeyword())
216       OS << "template ";
217     OS << *QTN->getDecl();
218   } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
219     if (!SuppressNNS && DTN->getQualifier())
220       DTN->getQualifier()->print(OS, Policy);
221     OS << "template ";
222 
223     if (DTN->isIdentifier())
224       OS << DTN->getIdentifier()->getName();
225     else
226       OS << "operator " << getOperatorSpelling(DTN->getOperator());
227   } else if (SubstTemplateTemplateParmStorage *subst
228                = getAsSubstTemplateTemplateParm()) {
229     subst->getReplacement().print(OS, Policy, SuppressNNS);
230   } else if (SubstTemplateTemplateParmPackStorage *SubstPack
231                                         = getAsSubstTemplateTemplateParmPack())
232     OS << *SubstPack->getParameterPack();
233   else {
234     OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
235     (*OTS->begin())->printName(OS);
236   }
237 }
238 
239 const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
240                                            TemplateName N) {
241   std::string NameStr;
242   llvm::raw_string_ostream OS(NameStr);
243   LangOptions LO;
244   LO.CPlusPlus = true;
245   LO.Bool = true;
246   OS << '\'';
247   N.print(OS, PrintingPolicy(LO));
248   OS << '\'';
249   OS.flush();
250   return DB << NameStr;
251 }
252 
253 void TemplateName::dump(raw_ostream &OS) const {
254   LangOptions LO;  // FIXME!
255   LO.CPlusPlus = true;
256   LO.Bool = true;
257   print(OS, PrintingPolicy(LO));
258 }
259 
260 LLVM_DUMP_METHOD void TemplateName::dump() const {
261   dump(llvm::errs());
262 }
263