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