xref: /llvm-project/clang/lib/AST/QualTypeNames.cpp (revision dec6324cb05ac1d339c1b2bd43add968f2931c62)
1 //===------- QualTypeNames.cpp - Generate Complete QualType Names ---------===//
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 #include "clang/AST/QualTypeNames.h"
10 #include "clang/AST/DeclTemplate.h"
11 #include "clang/AST/DeclarationName.h"
12 #include "clang/AST/Mangle.h"
13 
14 namespace clang {
15 
16 namespace TypeName {
17 
18 /// Create a NestedNameSpecifier for Namesp and its enclosing
19 /// scopes.
20 ///
21 /// \param[in] Ctx - the AST Context to be used.
22 /// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier
23 /// is requested.
24 /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
25 /// specifier "::" should be prepended or not.
26 static NestedNameSpecifier *createNestedNameSpecifier(
27     const ASTContext &Ctx,
28     const NamespaceDecl *Namesp,
29     bool WithGlobalNsPrefix);
30 
31 /// Create a NestedNameSpecifier for TagDecl and its enclosing
32 /// scopes.
33 ///
34 /// \param[in] Ctx - the AST Context to be used.
35 /// \param[in] TD - the TagDecl for which a NestedNameSpecifier is
36 /// requested.
37 /// \param[in] FullyQualify - Convert all template arguments into fully
38 /// qualified names.
39 /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
40 /// specifier "::" should be prepended or not.
41 static NestedNameSpecifier *createNestedNameSpecifier(
42     const ASTContext &Ctx, const TypeDecl *TD,
43     bool FullyQualify, bool WithGlobalNsPrefix);
44 
45 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
46     const ASTContext &Ctx, const Decl *decl,
47     bool FullyQualified, bool WithGlobalNsPrefix);
48 
49 static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
50     const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix);
51 
52 static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
53                                           TemplateName &TName,
54                                           bool WithGlobalNsPrefix) {
55   bool Changed = false;
56   NestedNameSpecifier *NNS = nullptr;
57 
58   TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();
59   // ArgTDecl won't be NULL because we asserted that this isn't a
60   // dependent context very early in the call chain.
61   assert(ArgTDecl != nullptr);
62   QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName();
63 
64   if (QTName &&
65       !QTName->hasTemplateKeyword() &&
66       (NNS = QTName->getQualifier())) {
67     NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier(
68         Ctx, NNS, WithGlobalNsPrefix);
69     if (QNNS != NNS) {
70       Changed = true;
71       NNS = QNNS;
72     } else {
73       NNS = nullptr;
74     }
75   } else {
76     NNS = createNestedNameSpecifierForScopeOf(
77         Ctx, ArgTDecl, true, WithGlobalNsPrefix);
78   }
79   if (NNS) {
80     TemplateName UnderlyingTN(ArgTDecl);
81     if (UsingShadowDecl *USD = TName.getAsUsingShadowDecl())
82       UnderlyingTN = TemplateName(USD);
83     TName =
84         Ctx.getQualifiedTemplateName(NNS,
85                                      /*TemplateKeyword=*/false, UnderlyingTN);
86     Changed = true;
87   }
88   return Changed;
89 }
90 
91 static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx,
92                                               TemplateArgument &Arg,
93                                               bool WithGlobalNsPrefix) {
94   bool Changed = false;
95 
96   // Note: we do not handle TemplateArgument::Expression, to replace it
97   // we need the information for the template instance decl.
98 
99   if (Arg.getKind() == TemplateArgument::Template) {
100     TemplateName TName = Arg.getAsTemplate();
101     Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix);
102     if (Changed) {
103       Arg = TemplateArgument(TName);
104     }
105   } else if (Arg.getKind() == TemplateArgument::Type) {
106     QualType SubTy = Arg.getAsType();
107     // Check if the type needs more desugaring and recurse.
108     QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix);
109     if (QTFQ != SubTy) {
110       Arg = TemplateArgument(QTFQ);
111       Changed = true;
112     }
113   }
114   return Changed;
115 }
116 
117 static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
118                                                  const Type *TypePtr,
119                                                  bool WithGlobalNsPrefix) {
120   // DependentTemplateTypes exist within template declarations and
121   // definitions. Therefore we shouldn't encounter them at the end of
122   // a translation unit. If we do, the caller has made an error.
123   assert(!isa<DependentTemplateSpecializationType>(TypePtr));
124   // In case of template specializations, iterate over the arguments
125   // and fully qualify them as well.
126   if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) {
127     bool MightHaveChanged = false;
128     SmallVector<TemplateArgument, 4> FQArgs;
129     // Cheap to copy and potentially modified by
130     // getFullyQualifedTemplateArgument.
131     for (TemplateArgument Arg : TST->template_arguments()) {
132       MightHaveChanged |= getFullyQualifiedTemplateArgument(
133           Ctx, Arg, WithGlobalNsPrefix);
134       FQArgs.push_back(Arg);
135     }
136 
137     // If a fully qualified arg is different from the unqualified arg,
138     // allocate new type in the AST.
139     if (MightHaveChanged) {
140       QualType QT = Ctx.getTemplateSpecializationType(
141           TST->getTemplateName(), FQArgs,
142           TST->getCanonicalTypeInternal());
143       // getTemplateSpecializationType returns a fully qualified
144       // version of the specialization itself, so no need to qualify
145       // it.
146       return QT.getTypePtr();
147     }
148   } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) {
149     // We are asked to fully qualify and we have a Record Type,
150     // which can point to a template instantiation with no sugar in any of
151     // its template argument, however we still need to fully qualify them.
152 
153     if (const auto *TSTDecl =
154         dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) {
155       const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();
156 
157       bool MightHaveChanged = false;
158       SmallVector<TemplateArgument, 4> FQArgs;
159       for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {
160         // cheap to copy and potentially modified by
161         // getFullyQualifedTemplateArgument
162         TemplateArgument Arg(TemplateArgs[I]);
163         MightHaveChanged |= getFullyQualifiedTemplateArgument(
164             Ctx, Arg, WithGlobalNsPrefix);
165         FQArgs.push_back(Arg);
166       }
167 
168       // If a fully qualified arg is different from the unqualified arg,
169       // allocate new type in the AST.
170       if (MightHaveChanged) {
171         TemplateName TN(TSTDecl->getSpecializedTemplate());
172         QualType QT = Ctx.getTemplateSpecializationType(
173             TN, FQArgs,
174             TSTRecord->getCanonicalTypeInternal());
175         // getTemplateSpecializationType returns a fully qualified
176         // version of the specialization itself, so no need to qualify
177         // it.
178         return QT.getTypePtr();
179       }
180     }
181   }
182   return TypePtr;
183 }
184 
185 static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
186                                            bool FullyQualify,
187                                            bool WithGlobalNsPrefix) {
188   const DeclContext *DC = D->getDeclContext();
189   if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
190     while (NS && NS->isInline()) {
191       // Ignore inline namespace;
192       NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
193     }
194     if (NS && NS->getDeclName()) {
195       return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
196     }
197     return nullptr;  // no starting '::', no anonymous
198   } else if (const auto *TD = dyn_cast<TagDecl>(DC)) {
199     return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
200   } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
201     return createNestedNameSpecifier(
202         Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
203   } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
204     return NestedNameSpecifier::GlobalSpecifier(Ctx);
205   }
206   return nullptr;  // no starting '::' if |WithGlobalNsPrefix| is false
207 }
208 
209 /// Return a fully qualified version of this name specifier.
210 static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
211     const ASTContext &Ctx, NestedNameSpecifier *Scope,
212     bool WithGlobalNsPrefix) {
213   switch (Scope->getKind()) {
214     case NestedNameSpecifier::Global:
215       // Already fully qualified
216       return Scope;
217     case NestedNameSpecifier::Namespace:
218       return TypeName::createNestedNameSpecifier(
219           Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix);
220     case NestedNameSpecifier::NamespaceAlias:
221       // Namespace aliases are only valid for the duration of the
222       // scope where they were introduced, and therefore are often
223       // invalid at the end of the TU.  So use the namespace name more
224       // likely to be valid at the end of the TU.
225       return TypeName::createNestedNameSpecifier(
226           Ctx,
227           Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(),
228           WithGlobalNsPrefix);
229     case NestedNameSpecifier::Identifier:
230       // A function or some other construct that makes it un-namable
231       // at the end of the TU. Skip the current component of the name,
232       // but use the name of it's prefix.
233       return getFullyQualifiedNestedNameSpecifier(
234           Ctx, Scope->getPrefix(), WithGlobalNsPrefix);
235     case NestedNameSpecifier::Super:
236     case NestedNameSpecifier::TypeSpec:
237     case NestedNameSpecifier::TypeSpecWithTemplate: {
238       const Type *Type = Scope->getAsType();
239       // Find decl context.
240       const TagDecl *TD = nullptr;
241       if (const TagType *TagDeclType = Type->getAs<TagType>()) {
242         TD = TagDeclType->getDecl();
243       } else {
244         TD = Type->getAsCXXRecordDecl();
245       }
246       if (TD) {
247         return TypeName::createNestedNameSpecifier(Ctx, TD,
248                                                    true /*FullyQualified*/,
249                                                    WithGlobalNsPrefix);
250       } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) {
251         return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(),
252                                                    true /*FullyQualified*/,
253                                                    WithGlobalNsPrefix);
254       }
255       return Scope;
256     }
257   }
258   llvm_unreachable("bad NNS kind");
259 }
260 
261 /// Create a nested name specifier for the declaring context of
262 /// the type.
263 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
264     const ASTContext &Ctx, const Decl *Decl,
265     bool FullyQualified, bool WithGlobalNsPrefix) {
266   assert(Decl);
267 
268   const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
269   const auto *Outer = dyn_cast<NamedDecl>(DC);
270   const auto *OuterNS = dyn_cast<NamespaceDecl>(DC);
271   if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) {
272     if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) {
273       if (ClassTemplateDecl *ClassTempl =
274               CxxDecl->getDescribedClassTemplate()) {
275         // We are in the case of a type(def) that was declared in a
276         // class template but is *not* type dependent.  In clang, it
277         // gets attached to the class template declaration rather than
278         // any specific class template instantiation.  This result in
279         // 'odd' fully qualified typename:
280         //
281         //    vector<_Tp,_Alloc>::size_type
282         //
283         // Make the situation is 'useable' but looking a bit odd by
284         // picking a random instance as the declaring context.
285         if (ClassTempl->spec_begin() != ClassTempl->spec_end()) {
286           Decl = *(ClassTempl->spec_begin());
287           Outer = dyn_cast<NamedDecl>(Decl);
288           OuterNS = dyn_cast<NamespaceDecl>(Decl);
289         }
290       }
291     }
292 
293     if (OuterNS) {
294       return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix);
295     } else if (const auto *TD = dyn_cast<TagDecl>(Outer)) {
296       return createNestedNameSpecifier(
297           Ctx, TD, FullyQualified, WithGlobalNsPrefix);
298     } else if (isa<TranslationUnitDecl>(Outer)) {
299       // Context is the TU. Nothing needs to be done.
300       return nullptr;
301     } else {
302       // Decl's context was neither the TU, a namespace, nor a
303       // TagDecl, which means it is a type local to a scope, and not
304       // accessible at the end of the TU.
305       return nullptr;
306     }
307   } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
308     return NestedNameSpecifier::GlobalSpecifier(Ctx);
309   }
310   return nullptr;
311 }
312 
313 /// Create a nested name specifier for the declaring context of
314 /// the type.
315 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
316     const ASTContext &Ctx, const Type *TypePtr,
317     bool FullyQualified, bool WithGlobalNsPrefix) {
318   if (!TypePtr) return nullptr;
319 
320   Decl *Decl = nullptr;
321   // There are probably other cases ...
322   if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) {
323     Decl = TDT->getDecl();
324   } else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) {
325     Decl = TagDeclType->getDecl();
326   } else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {
327     Decl = TST->getTemplateName().getAsTemplateDecl();
328   } else {
329     Decl = TypePtr->getAsCXXRecordDecl();
330   }
331 
332   if (!Decl) return nullptr;
333 
334   return createNestedNameSpecifierForScopeOf(
335       Ctx, Decl, FullyQualified, WithGlobalNsPrefix);
336 }
337 
338 NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
339                                                const NamespaceDecl *Namespace,
340                                                bool WithGlobalNsPrefix) {
341   while (Namespace && Namespace->isInline()) {
342     // Ignore inline namespace;
343     Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());
344   }
345   if (!Namespace) return nullptr;
346 
347   bool FullyQualified = true;  // doesn't matter, DeclContexts are namespaces
348   return NestedNameSpecifier::Create(
349       Ctx,
350       createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix),
351       Namespace);
352 }
353 
354 NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
355                                                const TypeDecl *TD,
356                                                bool FullyQualify,
357                                                bool WithGlobalNsPrefix) {
358   const Type *TypePtr = TD->getTypeForDecl();
359   if (isa<const TemplateSpecializationType>(TypePtr) ||
360       isa<const RecordType>(TypePtr)) {
361     // We are asked to fully qualify and we have a Record Type (which
362     // may point to a template specialization) or Template
363     // Specialization Type. We need to fully qualify their arguments.
364 
365     TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix);
366   }
367 
368   return NestedNameSpecifier::Create(
369       Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
370       false /*No TemplateKeyword*/, TypePtr);
371 }
372 
373 /// Return the fully qualified type, including fully-qualified
374 /// versions of any template parameters.
375 QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
376                                bool WithGlobalNsPrefix) {
377   // In case of myType* we need to strip the pointer first, fully
378   // qualify and attach the pointer once again.
379   if (isa<PointerType>(QT.getTypePtr())) {
380     // Get the qualifiers.
381     Qualifiers Quals = QT.getQualifiers();
382     QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
383     QT = Ctx.getPointerType(QT);
384     // Add back the qualifiers.
385     QT = Ctx.getQualifiedType(QT, Quals);
386     return QT;
387   }
388 
389   if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
390     // Get the qualifiers.
391     Qualifiers Quals = QT.getQualifiers();
392     // Fully qualify the pointee and class types.
393     QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
394     QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx,
395                                            WithGlobalNsPrefix);
396     QT = Ctx.getMemberPointerType(QT, Class.getTypePtr());
397     // Add back the qualifiers.
398     QT = Ctx.getQualifiedType(QT, Quals);
399     return QT;
400   }
401 
402   // In case of myType& we need to strip the reference first, fully
403   // qualify and attach the reference once again.
404   if (isa<ReferenceType>(QT.getTypePtr())) {
405     // Get the qualifiers.
406     bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
407     Qualifiers Quals = QT.getQualifiers();
408     QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
409     // Add the r- or l-value reference type back to the fully
410     // qualified one.
411     if (IsLValueRefTy)
412       QT = Ctx.getLValueReferenceType(QT);
413     else
414       QT = Ctx.getRValueReferenceType(QT);
415     // Add back the qualifiers.
416     QT = Ctx.getQualifiedType(QT, Quals);
417     return QT;
418   }
419 
420   // Remove the part of the type related to the type being a template
421   // parameter (we won't report it as part of the 'type name' and it
422   // is actually make the code below to be more complex (to handle
423   // those)
424   while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
425     // Get the qualifiers.
426     Qualifiers Quals = QT.getQualifiers();
427 
428     QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();
429 
430     // Add back the qualifiers.
431     QT = Ctx.getQualifiedType(QT, Quals);
432   }
433 
434   NestedNameSpecifier *Prefix = nullptr;
435   // Local qualifiers are attached to the QualType outside of the
436   // elaborated type.  Retrieve them before descending into the
437   // elaborated type.
438   Qualifiers PrefixQualifiers = QT.getLocalQualifiers();
439   QT = QualType(QT.getTypePtr(), 0);
440   ElaboratedTypeKeyword Keyword = ElaboratedTypeKeyword::None;
441   if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) {
442     QT = ETypeInput->getNamedType();
443     assert(!QT.hasLocalQualifiers());
444     Keyword = ETypeInput->getKeyword();
445   }
446 
447   // We don't consider the alias introduced by `using a::X` as a new type.
448   // The qualified name is still a::X.
449   if (const auto *UT = QT->getAs<UsingType>()) {
450     QT = Ctx.getQualifiedType(UT->getUnderlyingType(), PrefixQualifiers);
451     return getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
452   }
453 
454   // Create a nested name specifier if needed.
455   Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
456                                                true /*FullyQualified*/,
457                                                WithGlobalNsPrefix);
458 
459   // In case of template specializations iterate over the arguments and
460   // fully qualify them as well.
461   if (isa<const TemplateSpecializationType>(QT.getTypePtr()) ||
462       isa<const RecordType>(QT.getTypePtr())) {
463     // We are asked to fully qualify and we have a Record Type (which
464     // may point to a template specialization) or Template
465     // Specialization Type. We need to fully qualify their arguments.
466 
467     const Type *TypePtr = getFullyQualifiedTemplateType(
468         Ctx, QT.getTypePtr(), WithGlobalNsPrefix);
469     QT = QualType(TypePtr, 0);
470   }
471   if (Prefix || Keyword != ElaboratedTypeKeyword::None) {
472     QT = Ctx.getElaboratedType(Keyword, Prefix, QT);
473   }
474   QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
475   return QT;
476 }
477 
478 std::string getFullyQualifiedName(QualType QT,
479                                   const ASTContext &Ctx,
480                                   const PrintingPolicy &Policy,
481                                   bool WithGlobalNsPrefix) {
482   QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
483   return FQQT.getAsString(Policy);
484 }
485 
486 }  // end namespace TypeName
487 }  // end namespace clang
488