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 18 namespace clang { 19 20 namespace 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. 30 static 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. 45 static NestedNameSpecifier *createNestedNameSpecifier( 46 const ASTContext &Ctx, const TypeDecl *TD, 47 bool FullyQualify, bool WithGlobalNsPrefix); 48 49 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 50 const ASTContext &Ctx, const Decl *decl, 51 bool FullyQualified, bool WithGlobalNsPrefix); 52 53 static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( 54 const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix); 55 56 static 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 && 69 !QTName->hasTemplateKeyword() && 70 (NNS = QTName->getQualifier())) { 71 NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier( 72 Ctx, NNS, WithGlobalNsPrefix); 73 if (QNNS != NNS) { 74 Changed = true; 75 NNS = QNNS; 76 } else { 77 NNS = nullptr; 78 } 79 } else { 80 NNS = createNestedNameSpecifierForScopeOf( 81 Ctx, ArgTDecl, true, WithGlobalNsPrefix); 82 } 83 if (NNS) { 84 TemplateName UnderlyingTN(ArgTDecl); 85 if (UsingShadowDecl *USD = TName.getAsUsingShadowDecl()) 86 UnderlyingTN = TemplateName(USD); 87 TName = 88 Ctx.getQualifiedTemplateName(NNS, 89 /*TemplateKeyword=*/false, UnderlyingTN); 90 Changed = true; 91 } 92 return Changed; 93 } 94 95 static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx, 96 TemplateArgument &Arg, 97 bool WithGlobalNsPrefix) { 98 bool Changed = false; 99 100 // Note: we do not handle TemplateArgument::Expression, to replace it 101 // we need the information for the template instance decl. 102 103 if (Arg.getKind() == TemplateArgument::Template) { 104 TemplateName TName = Arg.getAsTemplate(); 105 Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix); 106 if (Changed) { 107 Arg = TemplateArgument(TName); 108 } 109 } else if (Arg.getKind() == TemplateArgument::Type) { 110 QualType SubTy = Arg.getAsType(); 111 // Check if the type needs more desugaring and recurse. 112 QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix); 113 if (QTFQ != SubTy) { 114 Arg = TemplateArgument(QTFQ); 115 Changed = true; 116 } 117 } 118 return Changed; 119 } 120 121 static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, 122 const Type *TypePtr, 123 bool WithGlobalNsPrefix) { 124 // DependentTemplateTypes exist within template declarations and 125 // definitions. Therefore we shouldn't encounter them at the end of 126 // a translation unit. If we do, the caller has made an error. 127 assert(!isa<DependentTemplateSpecializationType>(TypePtr)); 128 // In case of template specializations, iterate over the arguments 129 // and fully qualify them as well. 130 if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) { 131 bool MightHaveChanged = false; 132 SmallVector<TemplateArgument, 4> FQArgs; 133 // Cheap to copy and potentially modified by 134 // getFullyQualifedTemplateArgument. 135 for (TemplateArgument Arg : TST->template_arguments()) { 136 MightHaveChanged |= getFullyQualifiedTemplateArgument( 137 Ctx, Arg, WithGlobalNsPrefix); 138 FQArgs.push_back(Arg); 139 } 140 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 149 // it. 150 return QT.getTypePtr(); 151 } 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. 156 157 if (const auto *TSTDecl = 158 dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) { 159 const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); 160 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); 170 } 171 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( 177 TN, FQArgs, 178 TSTRecord->getCanonicalTypeInternal()); 179 // getTemplateSpecializationType returns a fully qualified 180 // version of the specialization itself, so no need to qualify 181 // it. 182 return QT.getTypePtr(); 183 } 184 } 185 } 186 return TypePtr; 187 } 188 189 static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, 190 bool FullyQualify, 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()); 197 } 198 if (NS && NS->getDeclName()) { 199 return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix); 200 } 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); 209 } 210 return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false 211 } 212 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 220 return Scope; 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( 230 Ctx, 231 Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(), 232 WithGlobalNsPrefix); 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(); 247 } else { 248 TD = Type->getAsCXXRecordDecl(); 249 } 250 if (TD) { 251 return TypeName::createNestedNameSpecifier(Ctx, TD, 252 true /*FullyQualified*/, 253 WithGlobalNsPrefix); 254 } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) { 255 return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(), 256 true /*FullyQualified*/, 257 WithGlobalNsPrefix); 258 } 259 return Scope; 260 } 261 } 262 llvm_unreachable("bad NNS kind"); 263 } 264 265 /// Create a nested name specifier for the declaring context of 266 /// the type. 267 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 268 const ASTContext &Ctx, const Decl *Decl, 269 bool FullyQualified, bool WithGlobalNsPrefix) { 270 assert(Decl); 271 272 const DeclContext *DC = Decl->getDeclContext()->getRedeclContext(); 273 const auto *Outer = dyn_cast<NamedDecl>(DC); 274 const auto *OuterNS = dyn_cast<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: 284 // 285 // vector<_Tp,_Alloc>::size_type 286 // 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); 293 } 294 } 295 } 296 297 if (OuterNS) { 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 (isa<TranslationUnitDecl>(Outer)) { 303 // Context is the TU. Nothing needs to be done. 304 return nullptr; 305 } else { 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. 309 return nullptr; 310 } 311 } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { 312 return NestedNameSpecifier::GlobalSpecifier(Ctx); 313 } 314 return nullptr; 315 } 316 317 /// Create a nested name specifier for the declaring context of 318 /// the type. 319 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 320 const ASTContext &Ctx, const Type *TypePtr, 321 bool FullyQualified, bool WithGlobalNsPrefix) { 322 if (!TypePtr) return nullptr; 323 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(); 332 } else { 333 Decl = TypePtr->getAsCXXRecordDecl(); 334 } 335 336 if (!Decl) return nullptr; 337 338 return createNestedNameSpecifierForScopeOf( 339 Ctx, Decl, FullyQualified, WithGlobalNsPrefix); 340 } 341 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()); 348 } 349 if (!Namespace) return nullptr; 350 351 bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces 352 return NestedNameSpecifier::Create( 353 Ctx, 354 createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix), 355 Namespace); 356 } 357 358 NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, 359 const TypeDecl *TD, 360 bool FullyQualify, 361 bool WithGlobalNsPrefix) { 362 const Type *TypePtr = TD->getTypeForDecl(); 363 if (isa<const TemplateSpecializationType>(TypePtr) || 364 isa<const RecordType>(TypePtr)) { 365 // We are asked to fully qualify and we have a Record Type (which 366 // may point to a template specialization) or Template 367 // Specialization Type. We need to fully qualify their arguments. 368 369 TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix); 370 } 371 372 return NestedNameSpecifier::Create( 373 Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), 374 false /*No TemplateKeyword*/, TypePtr); 375 } 376 377 /// Return the fully qualified type, including fully-qualified 378 /// versions of any template parameters. 379 QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, 380 bool WithGlobalNsPrefix) { 381 // In case of myType* we need to strip the pointer first, fully 382 // qualify and attach the pointer once again. 383 if (isa<PointerType>(QT.getTypePtr())) { 384 // Get the qualifiers. 385 Qualifiers Quals = QT.getQualifiers(); 386 QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); 387 QT = Ctx.getPointerType(QT); 388 // Add back the qualifiers. 389 QT = Ctx.getQualifiedType(QT, Quals); 390 return QT; 391 } 392 393 if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) { 394 // Get the qualifiers. 395 Qualifiers Quals = QT.getQualifiers(); 396 // Fully qualify the pointee and class types. 397 QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); 398 QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx, 399 WithGlobalNsPrefix); 400 QT = Ctx.getMemberPointerType(QT, Class.getTypePtr()); 401 // Add back the qualifiers. 402 QT = Ctx.getQualifiedType(QT, Quals); 403 return QT; 404 } 405 406 // In case of myType& we need to strip the reference first, fully 407 // qualify and attach the reference once again. 408 if (isa<ReferenceType>(QT.getTypePtr())) { 409 // Get the qualifiers. 410 bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr()); 411 Qualifiers Quals = QT.getQualifiers(); 412 QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); 413 // Add the r- or l-value reference type back to the fully 414 // qualified one. 415 if (IsLValueRefTy) 416 QT = Ctx.getLValueReferenceType(QT); 417 else 418 QT = Ctx.getRValueReferenceType(QT); 419 // Add back the qualifiers. 420 QT = Ctx.getQualifiedType(QT, Quals); 421 return QT; 422 } 423 424 // Remove the part of the type related to the type being a template 425 // parameter (we won't report it as part of the 'type name' and it 426 // is actually make the code below to be more complex (to handle 427 // those) 428 while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) { 429 // Get the qualifiers. 430 Qualifiers Quals = QT.getQualifiers(); 431 432 QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar(); 433 434 // Add back the qualifiers. 435 QT = Ctx.getQualifiedType(QT, Quals); 436 } 437 438 NestedNameSpecifier *Prefix = nullptr; 439 // Local qualifiers are attached to the QualType outside of the 440 // elaborated type. Retrieve them before descending into the 441 // elaborated type. 442 Qualifiers PrefixQualifiers = QT.getLocalQualifiers(); 443 QT = QualType(QT.getTypePtr(), 0); 444 ElaboratedTypeKeyword Keyword = ElaboratedTypeKeyword::None; 445 if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) { 446 QT = ETypeInput->getNamedType(); 447 assert(!QT.hasLocalQualifiers()); 448 Keyword = ETypeInput->getKeyword(); 449 } 450 451 // We don't consider the alias introduced by `using a::X` as a new type. 452 // The qualified name is still a::X. 453 if (const auto *UT = QT->getAs<UsingType>()) { 454 QT = Ctx.getQualifiedType(UT->getUnderlyingType(), PrefixQualifiers); 455 return getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix); 456 } 457 458 // Create a nested name specifier if needed. 459 Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(), 460 true /*FullyQualified*/, 461 WithGlobalNsPrefix); 462 463 // In case of template specializations iterate over the arguments and 464 // fully qualify them as well. 465 if (isa<const TemplateSpecializationType>(QT.getTypePtr()) || 466 isa<const RecordType>(QT.getTypePtr())) { 467 // We are asked to fully qualify and we have a Record Type (which 468 // may point to a template specialization) or Template 469 // Specialization Type. We need to fully qualify their arguments. 470 471 const Type *TypePtr = getFullyQualifiedTemplateType( 472 Ctx, QT.getTypePtr(), WithGlobalNsPrefix); 473 QT = QualType(TypePtr, 0); 474 } 475 if (Prefix || Keyword != ElaboratedTypeKeyword::None) { 476 QT = Ctx.getElaboratedType(Keyword, Prefix, QT); 477 } 478 QT = Ctx.getQualifiedType(QT, PrefixQualifiers); 479 return QT; 480 } 481 482 std::string getFullyQualifiedName(QualType QT, 483 const ASTContext &Ctx, 484 const PrintingPolicy &Policy, 485 bool WithGlobalNsPrefix) { 486 QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix); 487 return FQQT.getAsString(Policy); 488 } 489 490 } // end namespace TypeName 491 } // end namespace clang 492