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