1 //===------- QualTypeNames.cpp - Generate Complete QualType Names ---------===//
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
7 //===----------------------------------------------------------------------===//
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"
22 /// Create a NestedNameSpecifier for Namesp and its enclosing
25 /// \param[in] Ctx - the AST Context to be used.
26 /// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier
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
);
35 /// Create a NestedNameSpecifier for TagDecl and its enclosing
38 /// \param[in] Ctx - the AST Context to be used.
39 /// \param[in] TD - the TagDecl for which a NestedNameSpecifier is
41 /// \param[in] FullyQualify - Convert all template arguments into fully
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
);
49 static NestedNameSpecifier
*createNestedNameSpecifierForScopeOf(
50 const ASTContext
&Ctx
, const Decl
*decl
,
51 bool FullyQualified
, bool WithGlobalNsPrefix
);
53 static NestedNameSpecifier
*getFullyQualifiedNestedNameSpecifier(
54 const ASTContext
&Ctx
, NestedNameSpecifier
*scope
, bool WithGlobalNsPrefix
);
56 static bool getFullyQualifiedTemplateName(const ASTContext
&Ctx
,
58 bool WithGlobalNsPrefix
) {
60 NestedNameSpecifier
*NNS
= nullptr;
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();
68 if (QTName
&& !QTName
->hasTemplateKeyword()) {
69 NNS
= QTName
->getQualifier();
70 NestedNameSpecifier
*QNNS
= getFullyQualifiedNestedNameSpecifier(
71 Ctx
, NNS
, WithGlobalNsPrefix
);
79 NNS
= createNestedNameSpecifierForScopeOf(
80 Ctx
, ArgTDecl
, true, WithGlobalNsPrefix
);
83 TemplateName
UnderlyingTN(ArgTDecl
);
84 if (UsingShadowDecl
*USD
= TName
.getAsUsingShadowDecl())
85 UnderlyingTN
= TemplateName(USD
);
87 Ctx
.getQualifiedTemplateName(NNS
,
88 /*TemplateKeyword=*/false, UnderlyingTN
);
94 static bool getFullyQualifiedTemplateArgument(const ASTContext
&Ctx
,
95 TemplateArgument
&Arg
,
96 bool WithGlobalNsPrefix
) {
99 // Note: we do not handle TemplateArgument::Expression, to replace it
100 // we need the information for the template instance decl.
102 if (Arg
.getKind() == TemplateArgument::Template
) {
103 TemplateName TName
= Arg
.getAsTemplate();
104 Changed
= getFullyQualifiedTemplateName(Ctx
, TName
, WithGlobalNsPrefix
);
106 Arg
= TemplateArgument(TName
);
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
);
113 Arg
= TemplateArgument(QTFQ
);
120 static const Type
*getFullyQualifiedTemplateType(const ASTContext
&Ctx
,
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
);
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
149 return QT
.getTypePtr();
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.
156 if (const auto *TSTDecl
=
157 dyn_cast
<ClassTemplateSpecializationDecl
>(TSTRecord
->getDecl())) {
158 const TemplateArgumentList
&TemplateArgs
= TSTDecl
->getTemplateArgs();
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
);
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(
177 TSTRecord
->getCanonicalTypeInternal());
178 // getTemplateSpecializationType returns a fully qualified
179 // version of the specialization itself, so no need to qualify
181 return QT
.getTypePtr();
188 static NestedNameSpecifier
*createOuterNNS(const ASTContext
&Ctx
, const Decl
*D
,
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());
197 if (NS
&& NS
->getDeclName()) {
198 return createNestedNameSpecifier(Ctx
, NS
, WithGlobalNsPrefix
);
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
);
209 return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false
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
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(
230 Scope
->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(),
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();
247 TD
= Type
->getAsCXXRecordDecl();
250 return TypeName::createNestedNameSpecifier(Ctx
, TD
,
251 true /*FullyQualified*/,
253 } else if (const auto *TDD
= dyn_cast
<TypedefType
>(Type
)) {
254 return TypeName::createNestedNameSpecifier(Ctx
, TDD
->getDecl(),
255 true /*FullyQualified*/,
261 llvm_unreachable("bad NNS kind");
264 /// Create a nested name specifier for the declaring context of
266 static NestedNameSpecifier
*createNestedNameSpecifierForScopeOf(
267 const ASTContext
&Ctx
, const Decl
*Decl
,
268 bool FullyQualified
, bool WithGlobalNsPrefix
) {
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:
284 // vector<_Tp,_Alloc>::size_type
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
);
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.
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.
310 } else if (WithGlobalNsPrefix
&& DC
->isTranslationUnit()) {
311 return NestedNameSpecifier::GlobalSpecifier(Ctx
);
316 /// Create a nested name specifier for the declaring context of
318 static NestedNameSpecifier
*createNestedNameSpecifierForScopeOf(
319 const ASTContext
&Ctx
, const Type
*TypePtr
,
320 bool FullyQualified
, bool WithGlobalNsPrefix
) {
321 if (!TypePtr
) return nullptr;
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();
332 Decl
= TypePtr
->getAsCXXRecordDecl();
335 if (!Decl
) return nullptr;
337 return createNestedNameSpecifierForScopeOf(
338 Ctx
, Decl
, FullyQualified
, WithGlobalNsPrefix
);
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());
348 if (!Namespace
) return nullptr;
350 bool FullyQualified
= true; // doesn't matter, DeclContexts are namespaces
351 return NestedNameSpecifier::Create(
353 createOuterNNS(Ctx
, Namespace
, FullyQualified
, WithGlobalNsPrefix
),
357 NestedNameSpecifier
*createNestedNameSpecifier(const ASTContext
&Ctx
,
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.
368 TypePtr
= getFullyQualifiedTemplateType(Ctx
, TypePtr
, WithGlobalNsPrefix
);
371 return NestedNameSpecifier::Create(
372 Ctx
, createOuterNNS(Ctx
, TD
, FullyQualify
, WithGlobalNsPrefix
),
373 false /*No TemplateKeyword*/, TypePtr
);
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
);
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
,
399 QT
= Ctx
.getMemberPointerType(QT
, Class
.getTypePtr());
400 // Add back the qualifiers.
401 QT
= Ctx
.getQualifiedType(QT
, Quals
);
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
415 QT
= Ctx
.getLValueReferenceType(QT
);
417 QT
= Ctx
.getRValueReferenceType(QT
);
418 // Add back the qualifiers.
419 QT
= Ctx
.getQualifiedType(QT
, Quals
);
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
427 while (isa
<SubstTemplateTypeParmType
>(QT
.getTypePtr())) {
428 // Get the qualifiers.
429 Qualifiers Quals
= QT
.getQualifiers();
431 QT
= cast
<SubstTemplateTypeParmType
>(QT
.getTypePtr())->desugar();
433 // Add back the qualifiers.
434 QT
= Ctx
.getQualifiedType(QT
, Quals
);
437 NestedNameSpecifier
*Prefix
= nullptr;
438 // Local qualifiers are attached to the QualType outside of the
439 // elaborated type. Retrieve them before descending into the
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();
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
);
457 // Create a nested name specifier if needed.
458 Prefix
= createNestedNameSpecifierForScopeOf(Ctx
, QT
.getTypePtr(),
459 true /*FullyQualified*/,
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.
470 const Type
*TypePtr
= getFullyQualifiedTemplateType(
471 Ctx
, QT
.getTypePtr(), WithGlobalNsPrefix
);
472 QT
= QualType(TypePtr
, 0);
474 if (Prefix
|| Keyword
!= ETK_None
) {
475 QT
= Ctx
.getElaboratedType(Keyword
, Prefix
, QT
);
477 QT
= Ctx
.getQualifiedType(QT
, PrefixQualifiers
);
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
);
489 } // end namespace TypeName
490 } // end namespace clang