xref: /freebsd/contrib/llvm-project/clang/lib/AST/QualTypeNames.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 #include "clang/AST/Type.h"
14 
15 namespace clang {
16 
17 namespace TypeName {
18 
19 /// Create a NestedNameSpecifier for Namesp and its enclosing
20 /// scopes.
21 ///
22 /// \param[in] Ctx - the AST Context to be used.
23 /// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier
24 /// is requested.
25 /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
26 /// specifier "::" should be prepended or not.
27 static NestedNameSpecifier *createNestedNameSpecifier(
28     const ASTContext &Ctx,
29     const NamespaceDecl *Namesp,
30     bool WithGlobalNsPrefix);
31 
32 /// Create a NestedNameSpecifier for TagDecl and its enclosing
33 /// scopes.
34 ///
35 /// \param[in] Ctx - the AST Context to be used.
36 /// \param[in] TD - the TagDecl for which a NestedNameSpecifier is
37 /// requested.
38 /// \param[in] FullyQualify - Convert all template arguments into fully
39 /// qualified names.
40 /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
41 /// specifier "::" should be prepended or not.
42 static NestedNameSpecifier *createNestedNameSpecifier(
43     const ASTContext &Ctx, const TypeDecl *TD,
44     bool FullyQualify, bool WithGlobalNsPrefix);
45 
46 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
47     const ASTContext &Ctx, const Decl *decl,
48     bool FullyQualified, bool WithGlobalNsPrefix);
49 
50 static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
51     const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix);
52 
getFullyQualifiedTemplateName(const ASTContext & Ctx,TemplateName & TName,bool WithGlobalNsPrefix)53 static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
54                                           TemplateName &TName,
55                                           bool WithGlobalNsPrefix) {
56   bool Changed = false;
57   NestedNameSpecifier *NNS = nullptr;
58 
59   TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();
60   // ArgTDecl won't be NULL because we asserted that this isn't a
61   // dependent context very early in the call chain.
62   assert(ArgTDecl != nullptr);
63   QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName();
64 
65   if (QTName &&
66       !QTName->hasTemplateKeyword() &&
67       (NNS = QTName->getQualifier())) {
68     NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier(
69         Ctx, NNS, WithGlobalNsPrefix);
70     if (QNNS != NNS) {
71       Changed = true;
72       NNS = QNNS;
73     } else {
74       NNS = nullptr;
75     }
76   } else {
77     NNS = createNestedNameSpecifierForScopeOf(
78         Ctx, ArgTDecl, true, WithGlobalNsPrefix);
79   }
80   if (NNS) {
81     TemplateName UnderlyingTN(ArgTDecl);
82     if (UsingShadowDecl *USD = TName.getAsUsingShadowDecl())
83       UnderlyingTN = TemplateName(USD);
84     TName =
85         Ctx.getQualifiedTemplateName(NNS,
86                                      /*TemplateKeyword=*/false, UnderlyingTN);
87     Changed = true;
88   }
89   return Changed;
90 }
91 
getFullyQualifiedTemplateArgument(const ASTContext & Ctx,TemplateArgument & Arg,bool WithGlobalNsPrefix)92 static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx,
93                                               TemplateArgument &Arg,
94                                               bool WithGlobalNsPrefix) {
95   bool Changed = false;
96 
97   // Note: we do not handle TemplateArgument::Expression, to replace it
98   // we need the information for the template instance decl.
99 
100   if (Arg.getKind() == TemplateArgument::Template) {
101     TemplateName TName = Arg.getAsTemplate();
102     Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix);
103     if (Changed) {
104       Arg = TemplateArgument(TName);
105     }
106   } else if (Arg.getKind() == TemplateArgument::Type) {
107     QualType SubTy = Arg.getAsType();
108     // Check if the type needs more desugaring and recurse.
109     QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix);
110     if (QTFQ != SubTy) {
111       Arg = TemplateArgument(QTFQ);
112       Changed = true;
113     }
114   }
115   return Changed;
116 }
117 
getFullyQualifiedTemplateType(const ASTContext & Ctx,const Type * TypePtr,bool WithGlobalNsPrefix)118 static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
119                                                  const Type *TypePtr,
120                                                  bool WithGlobalNsPrefix) {
121   // DependentTemplateTypes exist within template declarations and
122   // definitions. Therefore we shouldn't encounter them at the end of
123   // a translation unit. If we do, the caller has made an error.
124   assert(!isa<DependentTemplateSpecializationType>(TypePtr));
125   // In case of template specializations, iterate over the arguments
126   // and fully qualify them as well.
127   if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) {
128     bool MightHaveChanged = false;
129     SmallVector<TemplateArgument, 4> FQArgs;
130     // Cheap to copy and potentially modified by
131     // getFullyQualifedTemplateArgument.
132     for (TemplateArgument Arg : TST->template_arguments()) {
133       MightHaveChanged |= getFullyQualifiedTemplateArgument(
134           Ctx, Arg, WithGlobalNsPrefix);
135       FQArgs.push_back(Arg);
136     }
137 
138     // If a fully qualified arg is different from the unqualified arg,
139     // allocate new type in the AST.
140     if (MightHaveChanged) {
141       QualType QT = Ctx.getTemplateSpecializationType(
142           TST->getTemplateName(), FQArgs,
143           /*CanonicalArgs=*/{}, TST->desugar());
144       // getTemplateSpecializationType returns a fully qualified
145       // version of the specialization itself, so no need to qualify
146       // it.
147       return QT.getTypePtr();
148     }
149   } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) {
150     // We are asked to fully qualify and we have a Record Type,
151     // which can point to a template instantiation with no sugar in any of
152     // its template argument, however we still need to fully qualify them.
153 
154     if (const auto *TSTDecl =
155         dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) {
156       const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();
157 
158       bool MightHaveChanged = false;
159       SmallVector<TemplateArgument, 4> FQArgs;
160       for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {
161         // cheap to copy and potentially modified by
162         // getFullyQualifedTemplateArgument
163         TemplateArgument Arg(TemplateArgs[I]);
164         MightHaveChanged |= getFullyQualifiedTemplateArgument(
165             Ctx, Arg, WithGlobalNsPrefix);
166         FQArgs.push_back(Arg);
167       }
168 
169       // If a fully qualified arg is different from the unqualified arg,
170       // allocate new type in the AST.
171       if (MightHaveChanged) {
172         TemplateName TN(TSTDecl->getSpecializedTemplate());
173         QualType QT = Ctx.getTemplateSpecializationType(
174             TN, FQArgs,
175             /*CanonicalArgs=*/{}, TSTRecord->getCanonicalTypeInternal());
176         // getTemplateSpecializationType returns a fully qualified
177         // version of the specialization itself, so no need to qualify
178         // it.
179         return QT.getTypePtr();
180       }
181     }
182   }
183   return TypePtr;
184 }
185 
createOuterNNS(const ASTContext & Ctx,const Decl * D,bool FullyQualify,bool WithGlobalNsPrefix)186 static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
187                                            bool FullyQualify,
188                                            bool WithGlobalNsPrefix) {
189   const DeclContext *DC = D->getDeclContext();
190   if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
191     while (NS && NS->isInline()) {
192       // Ignore inline namespace;
193       NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
194     }
195     if (NS && NS->getDeclName()) {
196       return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
197     }
198     return nullptr;  // no starting '::', no anonymous
199   } else if (const auto *TD = dyn_cast<TagDecl>(DC)) {
200     return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
201   } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
202     return createNestedNameSpecifier(
203         Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
204   } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
205     return NestedNameSpecifier::GlobalSpecifier(Ctx);
206   }
207   return nullptr;  // no starting '::' if |WithGlobalNsPrefix| is false
208 }
209 
210 /// Return a fully qualified version of this name specifier.
getFullyQualifiedNestedNameSpecifier(const ASTContext & Ctx,NestedNameSpecifier * Scope,bool WithGlobalNsPrefix)211 static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
212     const ASTContext &Ctx, NestedNameSpecifier *Scope,
213     bool WithGlobalNsPrefix) {
214   switch (Scope->getKind()) {
215     case NestedNameSpecifier::Global:
216     case NestedNameSpecifier::Super:
217       // Already fully qualified
218       return Scope;
219     case NestedNameSpecifier::Namespace:
220       return TypeName::createNestedNameSpecifier(
221           Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix);
222     case NestedNameSpecifier::NamespaceAlias:
223       // Namespace aliases are only valid for the duration of the
224       // scope where they were introduced, and therefore are often
225       // invalid at the end of the TU.  So use the namespace name more
226       // likely to be valid at the end of the TU.
227       return TypeName::createNestedNameSpecifier(
228           Ctx,
229           Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(),
230           WithGlobalNsPrefix);
231     case NestedNameSpecifier::Identifier:
232       // A function or some other construct that makes it un-namable
233       // at the end of the TU. Skip the current component of the name,
234       // but use the name of it's prefix.
235       return getFullyQualifiedNestedNameSpecifier(
236           Ctx, Scope->getPrefix(), WithGlobalNsPrefix);
237     case NestedNameSpecifier::TypeSpec: {
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.
createNestedNameSpecifierForScopeOf(const ASTContext & Ctx,const Decl * Decl,bool FullyQualified,bool WithGlobalNsPrefix)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.
createNestedNameSpecifierForScopeOf(const ASTContext & Ctx,const Type * TypePtr,bool FullyQualified,bool WithGlobalNsPrefix)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 
createNestedNameSpecifier(const ASTContext & Ctx,const NamespaceDecl * Namespace,bool WithGlobalNsPrefix)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 
createNestedNameSpecifier(const ASTContext & Ctx,const TypeDecl * TD,bool FullyQualify,bool WithGlobalNsPrefix)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), TypePtr);
370 }
371 
372 /// Return the fully qualified type, including fully-qualified
373 /// versions of any template parameters.
getFullyQualifiedType(QualType QT,const ASTContext & Ctx,bool WithGlobalNsPrefix)374 QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
375                                bool WithGlobalNsPrefix) {
376   // In case of myType* we need to strip the pointer first, fully
377   // qualify and attach the pointer once again.
378   if (isa<PointerType>(QT.getTypePtr())) {
379     // Get the qualifiers.
380     Qualifiers Quals = QT.getQualifiers();
381     QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
382     QT = Ctx.getPointerType(QT);
383     // Add back the qualifiers.
384     QT = Ctx.getQualifiedType(QT, Quals);
385     return QT;
386   }
387 
388   if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
389     // Get the qualifiers.
390     Qualifiers Quals = QT.getQualifiers();
391     // Fully qualify the pointee and class types.
392     QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
393     NestedNameSpecifier *Qualifier = getFullyQualifiedNestedNameSpecifier(
394         Ctx, MPT->getQualifier(), WithGlobalNsPrefix);
395     QT = Ctx.getMemberPointerType(QT, Qualifier,
396                                   MPT->getMostRecentCXXRecordDecl());
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   // Handle types with attributes such as `unique_ptr<int> _Nonnull`.
421   if (auto *AT = dyn_cast<AttributedType>(QT.getTypePtr())) {
422     QualType NewModified =
423         getFullyQualifiedType(AT->getModifiedType(), Ctx, WithGlobalNsPrefix);
424     QualType NewEquivalent =
425         getFullyQualifiedType(AT->getEquivalentType(), Ctx, WithGlobalNsPrefix);
426     Qualifiers Qualifiers = QT.getLocalQualifiers();
427     return Ctx.getQualifiedType(
428         Ctx.getAttributedType(AT->getAttrKind(), NewModified, NewEquivalent),
429         Qualifiers);
430   }
431 
432   // Remove the part of the type related to the type being a template
433   // parameter (we won't report it as part of the 'type name' and it
434   // is actually make the code below to be more complex (to handle
435   // those)
436   while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
437     // Get the qualifiers.
438     Qualifiers Quals = QT.getQualifiers();
439 
440     QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();
441 
442     // Add back the qualifiers.
443     QT = Ctx.getQualifiedType(QT, Quals);
444   }
445 
446   NestedNameSpecifier *Prefix = nullptr;
447   // Local qualifiers are attached to the QualType outside of the
448   // elaborated type.  Retrieve them before descending into the
449   // elaborated type.
450   Qualifiers PrefixQualifiers = QT.getLocalQualifiers();
451   QT = QualType(QT.getTypePtr(), 0);
452   ElaboratedTypeKeyword Keyword = ElaboratedTypeKeyword::None;
453   if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) {
454     QT = ETypeInput->getNamedType();
455     assert(!QT.hasLocalQualifiers());
456     Keyword = ETypeInput->getKeyword();
457   }
458 
459   // We don't consider the alias introduced by `using a::X` as a new type.
460   // The qualified name is still a::X.
461   if (const auto *UT = QT->getAs<UsingType>()) {
462     QT = Ctx.getQualifiedType(UT->getUnderlyingType(), PrefixQualifiers);
463     return getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
464   }
465 
466   // Create a nested name specifier if needed.
467   Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
468                                                true /*FullyQualified*/,
469                                                WithGlobalNsPrefix);
470 
471   // In case of template specializations iterate over the arguments and
472   // fully qualify them as well.
473   if (isa<const TemplateSpecializationType>(QT.getTypePtr()) ||
474       isa<const RecordType>(QT.getTypePtr())) {
475     // We are asked to fully qualify and we have a Record Type (which
476     // may point to a template specialization) or Template
477     // Specialization Type. We need to fully qualify their arguments.
478 
479     const Type *TypePtr = getFullyQualifiedTemplateType(
480         Ctx, QT.getTypePtr(), WithGlobalNsPrefix);
481     QT = QualType(TypePtr, 0);
482   }
483   if (Prefix || Keyword != ElaboratedTypeKeyword::None) {
484     QT = Ctx.getElaboratedType(Keyword, Prefix, QT);
485   }
486   QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
487   return QT;
488 }
489 
getFullyQualifiedName(QualType QT,const ASTContext & Ctx,const PrintingPolicy & Policy,bool WithGlobalNsPrefix)490 std::string getFullyQualifiedName(QualType QT,
491                                   const ASTContext &Ctx,
492                                   const PrintingPolicy &Policy,
493                                   bool WithGlobalNsPrefix) {
494   QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
495   return FQQT.getAsString(Policy);
496 }
497 
498 }  // end namespace TypeName
499 }  // end namespace clang
500