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