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