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/QualTypeNames.h" 10 #include "clang/AST/DeclTemplate.h" 11 #include "clang/AST/DeclarationName.h" 12 #include "clang/AST/Mangle.h" 13 14 namespace clang { 15 16 namespace TypeName { 17 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); 30 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); 44 45 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 46 const ASTContext &Ctx, const Decl *decl, 47 bool FullyQualified, bool WithGlobalNsPrefix); 48 49 static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( 50 const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix); 51 52 static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, 53 TemplateName &TName, 54 bool WithGlobalNsPrefix) { 55 bool Changed = false; 56 NestedNameSpecifier *NNS = nullptr; 57 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(); 63 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; 74 } 75 } else { 76 NNS = createNestedNameSpecifierForScopeOf( 77 Ctx, ArgTDecl, true, WithGlobalNsPrefix); 78 } 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; 87 } 88 return Changed; 89 } 90 91 static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx, 92 TemplateArgument &Arg, 93 bool WithGlobalNsPrefix) { 94 bool Changed = false; 95 96 // Note: we do not handle TemplateArgument::Expression, to replace it 97 // we need the information for the template instance decl. 98 99 if (Arg.getKind() == TemplateArgument::Template) { 100 TemplateName TName = Arg.getAsTemplate(); 101 Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix); 102 if (Changed) { 103 Arg = TemplateArgument(TName); 104 } 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; 112 } 113 } 114 return Changed; 115 } 116 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); 135 } 136 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(); 147 } 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. 152 153 if (const auto *TSTDecl = 154 dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) { 155 const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); 156 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); 166 } 167 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(); 179 } 180 } 181 } 182 return TypePtr; 183 } 184 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()); 193 } 194 if (NS && NS->getDeclName()) { 195 return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix); 196 } 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); 205 } 206 return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false 207 } 208 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(); 245 } 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); 254 } 255 return Scope; 256 } 257 } 258 llvm_unreachable("bad NNS kind"); 259 } 260 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); 267 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: 280 // 281 // vector<_Tp,_Alloc>::size_type 282 // 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); 289 } 290 } 291 } 292 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; 306 } 307 } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { 308 return NestedNameSpecifier::GlobalSpecifier(Ctx); 309 } 310 return nullptr; 311 } 312 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; 319 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(); 330 } 331 332 if (!Decl) return nullptr; 333 334 return createNestedNameSpecifierForScopeOf( 335 Ctx, Decl, FullyQualified, WithGlobalNsPrefix); 336 } 337 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()); 344 } 345 if (!Namespace) return nullptr; 346 347 bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces 348 return NestedNameSpecifier::Create( 349 Ctx, 350 createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix), 351 Namespace); 352 } 353 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. 364 365 TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix); 366 } 367 368 return NestedNameSpecifier::Create( 369 Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), 370 false /*No TemplateKeyword*/, TypePtr); 371 } 372 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; 387 } 388 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; 400 } 401 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; 418 } 419 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(); 427 428 QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar(); 429 430 // Add back the qualifiers. 431 QT = Ctx.getQualifiedType(QT, Quals); 432 } 433 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(); 445 } 446 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); 452 } 453 454 // Create a nested name specifier if needed. 455 Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(), 456 true /*FullyQualified*/, 457 WithGlobalNsPrefix); 458 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. 466 467 const Type *TypePtr = getFullyQualifiedTemplateType( 468 Ctx, QT.getTypePtr(), WithGlobalNsPrefix); 469 QT = QualType(TypePtr, 0); 470 } 471 if (Prefix || Keyword != ElaboratedTypeKeyword::None) { 472 QT = Ctx.getElaboratedType(Keyword, Prefix, QT); 473 } 474 QT = Ctx.getQualifiedType(QT, PrefixQualifiers); 475 return QT; 476 } 477 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); 484 } 485 486 } // end namespace TypeName 487 } // end namespace clang 488