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