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/AST/DeclTemplate.h"
13 #include "clang/AST/DeclarationName.h"
14 #include "clang/AST/GlobalDecl.h"
15 #include "clang/AST/Mangle.h"
16 #include "clang/AST/QualTypeNames.h"
25 /// Create a NestedNameSpecifier for Namesp and its enclosing
28 /// \param[in] Ctx - the AST Context to be used.
29 /// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier
31 /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
32 /// specifier "::" should be prepended or not.
33 static NestedNameSpecifier *createNestedNameSpecifier(
34 const ASTContext &Ctx,
35 const NamespaceDecl *Namesp,
36 bool WithGlobalNsPrefix);
38 /// Create a NestedNameSpecifier for TagDecl and its enclosing
41 /// \param[in] Ctx - the AST Context to be used.
42 /// \param[in] TD - the TagDecl for which a NestedNameSpecifier is
44 /// \param[in] FullyQualify - Convert all template arguments into fully
46 /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
47 /// specifier "::" should be prepended or not.
48 static NestedNameSpecifier *createNestedNameSpecifier(
49 const ASTContext &Ctx, const TypeDecl *TD,
50 bool FullyQualify, bool WithGlobalNsPrefix);
52 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
53 const ASTContext &Ctx, const Decl *decl,
54 bool FullyQualified, bool WithGlobalNsPrefix);
56 static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
57 const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix);
59 static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
61 bool WithGlobalNsPrefix) {
63 NestedNameSpecifier *NNS = nullptr;
65 TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();
66 // ArgTDecl won't be NULL because we asserted that this isn't a
67 // dependent context very early in the call chain.
68 assert(ArgTDecl != nullptr);
69 QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName();
71 if (QTName && !QTName->hasTemplateKeyword()) {
72 NNS = QTName->getQualifier();
73 NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier(
74 Ctx, NNS, WithGlobalNsPrefix);
82 NNS = createNestedNameSpecifierForScopeOf(
83 Ctx, ArgTDecl, true, WithGlobalNsPrefix);
86 TName = Ctx.getQualifiedTemplateName(NNS,
87 /*TemplateKeyword=*/false, ArgTDecl);
93 static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx,
94 TemplateArgument &Arg,
95 bool WithGlobalNsPrefix) {
98 // Note: we do not handle TemplateArgument::Expression, to replace it
99 // we need the information for the template instance decl.
101 if (Arg.getKind() == TemplateArgument::Template) {
102 TemplateName TName = Arg.getAsTemplate();
103 Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix);
105 Arg = TemplateArgument(TName);
107 } else if (Arg.getKind() == TemplateArgument::Type) {
108 QualType SubTy = Arg.getAsType();
109 // Check if the type needs more desugaring and recurse.
110 QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix);
112 Arg = TemplateArgument(QTFQ);
119 static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
121 bool WithGlobalNsPrefix) {
122 // DependentTemplateTypes exist within template declarations and
123 // definitions. Therefore we shouldn't encounter them at the end of
124 // a translation unit. If we do, the caller has made an error.
125 assert(!isa<DependentTemplateSpecializationType>(TypePtr));
126 // In case of template specializations, iterate over the arguments
127 // and fully qualify them as well.
128 if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) {
129 bool MightHaveChanged = false;
130 SmallVector<TemplateArgument, 4> FQArgs;
131 for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
133 // Cheap to copy and potentially modified by
134 // getFullyQualifedTemplateArgument.
135 TemplateArgument Arg(*I);
136 MightHaveChanged |= getFullyQualifiedTemplateArgument(
137 Ctx, Arg, WithGlobalNsPrefix);
138 FQArgs.push_back(Arg);
141 // If a fully qualified arg is different from the unqualified arg,
142 // allocate new type in the AST.
143 if (MightHaveChanged) {
144 QualType QT = Ctx.getTemplateSpecializationType(
145 TST->getTemplateName(), FQArgs,
146 TST->getCanonicalTypeInternal());
147 // getTemplateSpecializationType returns a fully qualified
148 // version of the specialization itself, so no need to qualify
150 return QT.getTypePtr();
152 } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) {
153 // We are asked to fully qualify and we have a Record Type,
154 // which can point to a template instantiation with no sugar in any of
155 // its template argument, however we still need to fully qualify them.
157 if (const auto *TSTDecl =
158 dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) {
159 const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();
161 bool MightHaveChanged = false;
162 SmallVector<TemplateArgument, 4> FQArgs;
163 for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {
164 // cheap to copy and potentially modified by
165 // getFullyQualifedTemplateArgument
166 TemplateArgument Arg(TemplateArgs[I]);
167 MightHaveChanged |= getFullyQualifiedTemplateArgument(
168 Ctx, Arg, WithGlobalNsPrefix);
169 FQArgs.push_back(Arg);
172 // If a fully qualified arg is different from the unqualified arg,
173 // allocate new type in the AST.
174 if (MightHaveChanged) {
175 TemplateName TN(TSTDecl->getSpecializedTemplate());
176 QualType QT = Ctx.getTemplateSpecializationType(
178 TSTRecord->getCanonicalTypeInternal());
179 // getTemplateSpecializationType returns a fully qualified
180 // version of the specialization itself, so no need to qualify
182 return QT.getTypePtr();
189 static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
191 bool WithGlobalNsPrefix) {
192 const DeclContext *DC = D->getDeclContext();
193 if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
194 while (NS && NS->isInline()) {
195 // Ignore inline namespace;
196 NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
198 if (NS->getDeclName()) {
199 return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
201 return nullptr; // no starting '::', no anonymous
202 } else if (const auto *TD = dyn_cast<TagDecl>(DC)) {
203 return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
204 } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
205 return createNestedNameSpecifier(
206 Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
207 } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
208 return NestedNameSpecifier::GlobalSpecifier(Ctx);
210 return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false
213 /// Return a fully qualified version of this name specifier.
214 static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
215 const ASTContext &Ctx, NestedNameSpecifier *Scope,
216 bool WithGlobalNsPrefix) {
217 switch (Scope->getKind()) {
218 case NestedNameSpecifier::Global:
219 // Already fully qualified
221 case NestedNameSpecifier::Namespace:
222 return TypeName::createNestedNameSpecifier(
223 Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix);
224 case NestedNameSpecifier::NamespaceAlias:
225 // Namespace aliases are only valid for the duration of the
226 // scope where they were introduced, and therefore are often
227 // invalid at the end of the TU. So use the namespace name more
228 // likely to be valid at the end of the TU.
229 return TypeName::createNestedNameSpecifier(
231 Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(),
233 case NestedNameSpecifier::Identifier:
234 // A function or some other construct that makes it un-namable
235 // at the end of the TU. Skip the current component of the name,
236 // but use the name of it's prefix.
237 return getFullyQualifiedNestedNameSpecifier(
238 Ctx, Scope->getPrefix(), WithGlobalNsPrefix);
239 case NestedNameSpecifier::Super:
240 case NestedNameSpecifier::TypeSpec:
241 case NestedNameSpecifier::TypeSpecWithTemplate: {
242 const Type *Type = Scope->getAsType();
243 // Find decl context.
244 const TagDecl *TD = nullptr;
245 if (const TagType *TagDeclType = Type->getAs<TagType>()) {
246 TD = TagDeclType->getDecl();
248 TD = Type->getAsCXXRecordDecl();
251 return TypeName::createNestedNameSpecifier(Ctx, TD,
252 true /*FullyQualified*/,
254 } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) {
255 return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(),
256 true /*FullyQualified*/,
262 llvm_unreachable("bad NNS kind");
265 /// Create a nested name specifier for the declaring context of
267 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
268 const ASTContext &Ctx, const Decl *Decl,
269 bool FullyQualified, bool WithGlobalNsPrefix) {
272 const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
273 const auto *Outer = dyn_cast_or_null<NamedDecl>(DC);
274 const auto *OuterNS = dyn_cast_or_null<NamespaceDecl>(DC);
275 if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) {
276 if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) {
277 if (ClassTemplateDecl *ClassTempl =
278 CxxDecl->getDescribedClassTemplate()) {
279 // We are in the case of a type(def) that was declared in a
280 // class template but is *not* type dependent. In clang, it
281 // gets attached to the class template declaration rather than
282 // any specific class template instantiation. This result in
283 // 'odd' fully qualified typename:
285 // vector<_Tp,_Alloc>::size_type
287 // Make the situation is 'useable' but looking a bit odd by
288 // picking a random instance as the declaring context.
289 if (ClassTempl->spec_begin() != ClassTempl->spec_end()) {
290 Decl = *(ClassTempl->spec_begin());
291 Outer = dyn_cast<NamedDecl>(Decl);
292 OuterNS = dyn_cast<NamespaceDecl>(Decl);
298 return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix);
299 } else if (const auto *TD = dyn_cast<TagDecl>(Outer)) {
300 return createNestedNameSpecifier(
301 Ctx, TD, FullyQualified, WithGlobalNsPrefix);
302 } else if (dyn_cast<TranslationUnitDecl>(Outer)) {
303 // Context is the TU. Nothing needs to be done.
306 // Decl's context was neither the TU, a namespace, nor a
307 // TagDecl, which means it is a type local to a scope, and not
308 // accessible at the end of the TU.
311 } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
312 return NestedNameSpecifier::GlobalSpecifier(Ctx);
317 /// Create a nested name specifier for the declaring context of
319 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
320 const ASTContext &Ctx, const Type *TypePtr,
321 bool FullyQualified, bool WithGlobalNsPrefix) {
322 if (!TypePtr) return nullptr;
324 Decl *Decl = nullptr;
325 // There are probably other cases ...
326 if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) {
327 Decl = TDT->getDecl();
328 } else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) {
329 Decl = TagDeclType->getDecl();
330 } else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {
331 Decl = TST->getTemplateName().getAsTemplateDecl();
333 Decl = TypePtr->getAsCXXRecordDecl();
336 if (!Decl) return nullptr;
338 return createNestedNameSpecifierForScopeOf(
339 Ctx, Decl, FullyQualified, WithGlobalNsPrefix);
342 NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
343 const NamespaceDecl *Namespace,
344 bool WithGlobalNsPrefix) {
345 while (Namespace && Namespace->isInline()) {
346 // Ignore inline namespace;
347 Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());
349 if (!Namespace) return nullptr;
351 bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces
352 return NestedNameSpecifier::Create(
354 createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix),
358 NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
361 bool WithGlobalNsPrefix) {
362 return NestedNameSpecifier::Create(
364 createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
365 false /*No TemplateKeyword*/,
366 TD->getTypeForDecl());
369 /// Return the fully qualified type, including fully-qualified
370 /// versions of any template parameters.
371 QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
372 bool WithGlobalNsPrefix) {
373 // In case of myType* we need to strip the pointer first, fully
374 // qualify and attach the pointer once again.
375 if (isa<PointerType>(QT.getTypePtr())) {
376 // Get the qualifiers.
377 Qualifiers Quals = QT.getQualifiers();
378 QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
379 QT = Ctx.getPointerType(QT);
380 // Add back the qualifiers.
381 QT = Ctx.getQualifiedType(QT, Quals);
385 // In case of myType& we need to strip the reference first, fully
386 // qualify and attach the reference once again.
387 if (isa<ReferenceType>(QT.getTypePtr())) {
388 // Get the qualifiers.
389 bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
390 Qualifiers Quals = QT.getQualifiers();
391 QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
392 // Add the r- or l-value reference type back to the fully
395 QT = Ctx.getLValueReferenceType(QT);
397 QT = Ctx.getRValueReferenceType(QT);
398 // Add back the qualifiers.
399 QT = Ctx.getQualifiedType(QT, Quals);
403 // Remove the part of the type related to the type being a template
404 // parameter (we won't report it as part of the 'type name' and it
405 // is actually make the code below to be more complex (to handle
407 while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
408 // Get the qualifiers.
409 Qualifiers Quals = QT.getQualifiers();
411 QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar();
413 // Add back the qualifiers.
414 QT = Ctx.getQualifiedType(QT, Quals);
417 NestedNameSpecifier *Prefix = nullptr;
418 // Local qualifiers are attached to the QualType outside of the
419 // elaborated type. Retrieve them before descending into the
421 Qualifiers PrefixQualifiers = QT.getLocalQualifiers();
422 QT = QualType(QT.getTypePtr(), 0);
423 ElaboratedTypeKeyword Keyword = ETK_None;
424 if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) {
425 QT = ETypeInput->getNamedType();
426 assert(!QT.hasLocalQualifiers());
427 Keyword = ETypeInput->getKeyword();
429 // Create a nested name specifier if needed.
430 Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
431 true /*FullyQualified*/,
434 // In case of template specializations iterate over the arguments and
435 // fully qualify them as well.
436 if (isa<const TemplateSpecializationType>(QT.getTypePtr()) ||
437 isa<const RecordType>(QT.getTypePtr())) {
438 // We are asked to fully qualify and we have a Record Type (which
439 // may point to a template specialization) or Template
440 // Specialization Type. We need to fully qualify their arguments.
442 const Type *TypePtr = getFullyQualifiedTemplateType(
443 Ctx, QT.getTypePtr(), WithGlobalNsPrefix);
444 QT = QualType(TypePtr, 0);
446 if (Prefix || Keyword != ETK_None) {
447 QT = Ctx.getElaboratedType(Keyword, Prefix, QT);
449 QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
453 std::string getFullyQualifiedName(QualType QT,
454 const ASTContext &Ctx,
455 const PrintingPolicy &Policy,
456 bool WithGlobalNsPrefix) {
457 QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
458 return FQQT.getAsString(Policy);
461 } // end namespace TypeName
462 } // end namespace clang