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//===----------------------------------------------------------------------===// 8 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" 14 15#include <stdio.h> 16#include <memory> 17 18namespace clang { 19 20namespace TypeName { 21 22/// Create a NestedNameSpecifier for Namesp and its enclosing 23/// scopes. 24/// 25/// \param[in] Ctx - the AST Context to be used. 26/// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier 27/// is requested. 28/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace 29/// specifier "::" should be prepended or not. 30static NestedNameSpecifier *createNestedNameSpecifier( 31 const ASTContext &Ctx, 32 const NamespaceDecl *Namesp, 33 bool WithGlobalNsPrefix); 34 35/// Create a NestedNameSpecifier for TagDecl and its enclosing 36/// scopes. 37/// 38/// \param[in] Ctx - the AST Context to be used. 39/// \param[in] TD - the TagDecl for which a NestedNameSpecifier is 40/// requested. 41/// \param[in] FullyQualify - Convert all template arguments into fully 42/// qualified names. 43/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace 44/// specifier "::" should be prepended or not. 45static NestedNameSpecifier *createNestedNameSpecifier( 46 const ASTContext &Ctx, const TypeDecl *TD, 47 bool FullyQualify, bool WithGlobalNsPrefix); 48 49static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 50 const ASTContext &Ctx, const Decl *decl, 51 bool FullyQualified, bool WithGlobalNsPrefix); 52 53static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( 54 const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix); 55 56static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, 57 TemplateName &TName, 58 bool WithGlobalNsPrefix) { 59 bool Changed = false; 60 NestedNameSpecifier *NNS = nullptr; 61 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(); 67 68 if (QTName && !QTName->hasTemplateKeyword()) { 69 NNS = QTName->getQualifier(); 70 NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier( 71 Ctx, NNS, WithGlobalNsPrefix); 72 if (QNNS != NNS) { 73 Changed = true; 74 NNS = QNNS; 75 } else { 76 NNS = nullptr; 77 } 78 } else { 79 NNS = createNestedNameSpecifierForScopeOf( 80 Ctx, ArgTDecl, true, WithGlobalNsPrefix); 81 } 82 if (NNS) { 83 TemplateName UnderlyingTN(ArgTDecl); 84 if (UsingShadowDecl *USD = TName.getAsUsingShadowDecl()) 85 UnderlyingTN = TemplateName(USD); 86 TName = 87 Ctx.getQualifiedTemplateName(NNS, 88 /*TemplateKeyword=*/false, UnderlyingTN); 89 Changed = true; 90 } 91 return Changed; 92} 93 94static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx, 95 TemplateArgument &Arg, 96 bool WithGlobalNsPrefix) { 97 bool Changed = false; 98 99 // Note: we do not handle TemplateArgument::Expression, to replace it 100 // we need the information for the template instance decl. 101 102 if (Arg.getKind() == TemplateArgument::Template) { 103 TemplateName TName = Arg.getAsTemplate(); 104 Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix); 105 if (Changed) { 106 Arg = TemplateArgument(TName); 107 } 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); 112 if (QTFQ != SubTy) { 113 Arg = TemplateArgument(QTFQ); 114 Changed = true; 115 } 116 } 117 return Changed; 118} 119 120static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, 121 const Type *TypePtr, 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); 138 } 139 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 148 // it. 149 return QT.getTypePtr(); 150 } 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. 155 156 if (const auto *TSTDecl = 157 dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) { 158 const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); 159 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); 169 } 170 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( 176 TN, FQArgs, 177 TSTRecord->getCanonicalTypeInternal()); 178 // getTemplateSpecializationType returns a fully qualified 179 // version of the specialization itself, so no need to qualify 180 // it. 181 return QT.getTypePtr(); 182 } 183 } 184 } 185 return TypePtr; 186} 187 188static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, 189 bool FullyQualify, 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()); 196 } 197 if (NS && NS->getDeclName()) { 198 return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix); 199 } 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); 208 } 209 return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false 210} 211 212/// Return a fully qualified version of this name specifier. 213static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( 214 const ASTContext &Ctx, NestedNameSpecifier *Scope, 215 bool WithGlobalNsPrefix) { 216 switch (Scope->getKind()) { 217 case NestedNameSpecifier::Global: 218 // Already fully qualified 219 return Scope; 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( 229 Ctx, 230 Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(), 231 WithGlobalNsPrefix); 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(); 246 } else { 247 TD = Type->getAsCXXRecordDecl(); 248 } 249 if (TD) { 250 return TypeName::createNestedNameSpecifier(Ctx, TD, 251 true /*FullyQualified*/, 252 WithGlobalNsPrefix); 253 } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) { 254 return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(), 255 true /*FullyQualified*/, 256 WithGlobalNsPrefix); 257 } 258 return Scope; 259 } 260 } 261 llvm_unreachable("bad NNS kind"); 262} 263 264/// Create a nested name specifier for the declaring context of 265/// the type. 266static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 267 const ASTContext &Ctx, const Decl *Decl, 268 bool FullyQualified, bool WithGlobalNsPrefix) { 269 assert(Decl); 270 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: 283 // 284 // vector<_Tp,_Alloc>::size_type 285 // 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); 292 } 293 } 294 } 295 296 if (OuterNS) { 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. 303 return nullptr; 304 } else { 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. 308 return nullptr; 309 } 310 } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { 311 return NestedNameSpecifier::GlobalSpecifier(Ctx); 312 } 313 return nullptr; 314} 315 316/// Create a nested name specifier for the declaring context of 317/// the type. 318static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 319 const ASTContext &Ctx, const Type *TypePtr, 320 bool FullyQualified, bool WithGlobalNsPrefix) { 321 if (!TypePtr) return nullptr; 322 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(); 331 } else { 332 Decl = TypePtr->getAsCXXRecordDecl(); 333 } 334 335 if (!Decl) return nullptr; 336 337 return createNestedNameSpecifierForScopeOf( 338 Ctx, Decl, FullyQualified, WithGlobalNsPrefix); 339} 340 341NestedNameSpecifier *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()); 347 } 348 if (!Namespace) return nullptr; 349 350 bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces 351 return NestedNameSpecifier::Create( 352 Ctx, 353 createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix), 354 Namespace); 355} 356 357NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, 358 const TypeDecl *TD, 359 bool FullyQualify, 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. 367 368 TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix); 369 } 370 371 return NestedNameSpecifier::Create( 372 Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), 373 false /*No TemplateKeyword*/, TypePtr); 374} 375 376/// Return the fully qualified type, including fully-qualified 377/// versions of any template parameters. 378QualType 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); 389 return QT; 390 } 391 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, 398 WithGlobalNsPrefix); 399 QT = Ctx.getMemberPointerType(QT, Class.getTypePtr()); 400 // Add back the qualifiers. 401 QT = Ctx.getQualifiedType(QT, Quals); 402 return QT; 403 } 404 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 413 // qualified one. 414 if (IsLValueRefTy) 415 QT = Ctx.getLValueReferenceType(QT); 416 else 417 QT = Ctx.getRValueReferenceType(QT); 418 // Add back the qualifiers. 419 QT = Ctx.getQualifiedType(QT, Quals); 420 return QT; 421 } 422 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 426 // those) 427 while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) { 428 // Get the qualifiers. 429 Qualifiers Quals = QT.getQualifiers(); 430 431 QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar(); 432 433 // Add back the qualifiers. 434 QT = Ctx.getQualifiedType(QT, Quals); 435 } 436 437 NestedNameSpecifier *Prefix = nullptr; 438 // Local qualifiers are attached to the QualType outside of the 439 // elaborated type. Retrieve them before descending into the 440 // elaborated type. 441 Qualifiers PrefixQualifiers = QT.getLocalQualifiers(); 442 QT = QualType(QT.getTypePtr(), 0); 443 ElaboratedTypeKeyword Keyword = ElaboratedTypeKeyword::None; 444 if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) { 445 QT = ETypeInput->getNamedType(); 446 assert(!QT.hasLocalQualifiers()); 447 Keyword = ETypeInput->getKeyword(); 448 } 449 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); 455 } 456 457 // Create a nested name specifier if needed. 458 Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(), 459 true /*FullyQualified*/, 460 WithGlobalNsPrefix); 461 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. 469 470 const Type *TypePtr = getFullyQualifiedTemplateType( 471 Ctx, QT.getTypePtr(), WithGlobalNsPrefix); 472 QT = QualType(TypePtr, 0); 473 } 474 if (Prefix || Keyword != ElaboratedTypeKeyword::None) { 475 QT = Ctx.getElaboratedType(Keyword, Prefix, QT); 476 } 477 QT = Ctx.getQualifiedType(QT, PrefixQualifiers); 478 return QT; 479} 480 481std::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); 487} 488 489} // end namespace TypeName 490} // end namespace clang 491