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 && !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 94 static 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 120 static 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 for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end(); 133 I != E; ++I) { 134 // Cheap to copy and potentially modified by 135 // getFullyQualifedTemplateArgument. 136 TemplateArgument Arg(*I); 137 MightHaveChanged |= getFullyQualifiedTemplateArgument( 138 Ctx, Arg, WithGlobalNsPrefix); 139 FQArgs.push_back(Arg); 140 } 141 142 // If a fully qualified arg is different from the unqualified arg, 143 // allocate new type in the AST. 144 if (MightHaveChanged) { 145 QualType QT = Ctx.getTemplateSpecializationType( 146 TST->getTemplateName(), FQArgs, 147 TST->getCanonicalTypeInternal()); 148 // getTemplateSpecializationType returns a fully qualified 149 // version of the specialization itself, so no need to qualify 150 // it. 151 return QT.getTypePtr(); 152 } 153 } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) { 154 // We are asked to fully qualify and we have a Record Type, 155 // which can point to a template instantiation with no sugar in any of 156 // its template argument, however we still need to fully qualify them. 157 158 if (const auto *TSTDecl = 159 dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) { 160 const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); 161 162 bool MightHaveChanged = false; 163 SmallVector<TemplateArgument, 4> FQArgs; 164 for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) { 165 // cheap to copy and potentially modified by 166 // getFullyQualifedTemplateArgument 167 TemplateArgument Arg(TemplateArgs[I]); 168 MightHaveChanged |= getFullyQualifiedTemplateArgument( 169 Ctx, Arg, WithGlobalNsPrefix); 170 FQArgs.push_back(Arg); 171 } 172 173 // If a fully qualified arg is different from the unqualified arg, 174 // allocate new type in the AST. 175 if (MightHaveChanged) { 176 TemplateName TN(TSTDecl->getSpecializedTemplate()); 177 QualType QT = Ctx.getTemplateSpecializationType( 178 TN, FQArgs, 179 TSTRecord->getCanonicalTypeInternal()); 180 // getTemplateSpecializationType returns a fully qualified 181 // version of the specialization itself, so no need to qualify 182 // it. 183 return QT.getTypePtr(); 184 } 185 } 186 } 187 return TypePtr; 188 } 189 190 static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, 191 bool FullyQualify, 192 bool WithGlobalNsPrefix) { 193 const DeclContext *DC = D->getDeclContext(); 194 if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) { 195 while (NS && NS->isInline()) { 196 // Ignore inline namespace; 197 NS = dyn_cast<NamespaceDecl>(NS->getDeclContext()); 198 } 199 if (NS && NS->getDeclName()) { 200 return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix); 201 } 202 return nullptr; // no starting '::', no anonymous 203 } else if (const auto *TD = dyn_cast<TagDecl>(DC)) { 204 return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix); 205 } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) { 206 return createNestedNameSpecifier( 207 Ctx, TDD, FullyQualify, WithGlobalNsPrefix); 208 } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { 209 return NestedNameSpecifier::GlobalSpecifier(Ctx); 210 } 211 return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false 212 } 213 214 /// Return a fully qualified version of this name specifier. 215 static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( 216 const ASTContext &Ctx, NestedNameSpecifier *Scope, 217 bool WithGlobalNsPrefix) { 218 switch (Scope->getKind()) { 219 case NestedNameSpecifier::Global: 220 // Already fully qualified 221 return Scope; 222 case NestedNameSpecifier::Namespace: 223 return TypeName::createNestedNameSpecifier( 224 Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix); 225 case NestedNameSpecifier::NamespaceAlias: 226 // Namespace aliases are only valid for the duration of the 227 // scope where they were introduced, and therefore are often 228 // invalid at the end of the TU. So use the namespace name more 229 // likely to be valid at the end of the TU. 230 return TypeName::createNestedNameSpecifier( 231 Ctx, 232 Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(), 233 WithGlobalNsPrefix); 234 case NestedNameSpecifier::Identifier: 235 // A function or some other construct that makes it un-namable 236 // at the end of the TU. Skip the current component of the name, 237 // but use the name of it's prefix. 238 return getFullyQualifiedNestedNameSpecifier( 239 Ctx, Scope->getPrefix(), WithGlobalNsPrefix); 240 case NestedNameSpecifier::Super: 241 case NestedNameSpecifier::TypeSpec: 242 case NestedNameSpecifier::TypeSpecWithTemplate: { 243 const Type *Type = Scope->getAsType(); 244 // Find decl context. 245 const TagDecl *TD = nullptr; 246 if (const TagType *TagDeclType = Type->getAs<TagType>()) { 247 TD = TagDeclType->getDecl(); 248 } else { 249 TD = Type->getAsCXXRecordDecl(); 250 } 251 if (TD) { 252 return TypeName::createNestedNameSpecifier(Ctx, TD, 253 true /*FullyQualified*/, 254 WithGlobalNsPrefix); 255 } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) { 256 return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(), 257 true /*FullyQualified*/, 258 WithGlobalNsPrefix); 259 } 260 return Scope; 261 } 262 } 263 llvm_unreachable("bad NNS kind"); 264 } 265 266 /// Create a nested name specifier for the declaring context of 267 /// the type. 268 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 269 const ASTContext &Ctx, const Decl *Decl, 270 bool FullyQualified, bool WithGlobalNsPrefix) { 271 assert(Decl); 272 273 const DeclContext *DC = Decl->getDeclContext()->getRedeclContext(); 274 const auto *Outer = dyn_cast_or_null<NamedDecl>(DC); 275 const auto *OuterNS = dyn_cast_or_null<NamespaceDecl>(DC); 276 if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) { 277 if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) { 278 if (ClassTemplateDecl *ClassTempl = 279 CxxDecl->getDescribedClassTemplate()) { 280 // We are in the case of a type(def) that was declared in a 281 // class template but is *not* type dependent. In clang, it 282 // gets attached to the class template declaration rather than 283 // any specific class template instantiation. This result in 284 // 'odd' fully qualified typename: 285 // 286 // vector<_Tp,_Alloc>::size_type 287 // 288 // Make the situation is 'useable' but looking a bit odd by 289 // picking a random instance as the declaring context. 290 if (ClassTempl->spec_begin() != ClassTempl->spec_end()) { 291 Decl = *(ClassTempl->spec_begin()); 292 Outer = dyn_cast<NamedDecl>(Decl); 293 OuterNS = dyn_cast<NamespaceDecl>(Decl); 294 } 295 } 296 } 297 298 if (OuterNS) { 299 return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix); 300 } else if (const auto *TD = dyn_cast<TagDecl>(Outer)) { 301 return createNestedNameSpecifier( 302 Ctx, TD, FullyQualified, WithGlobalNsPrefix); 303 } else if (isa<TranslationUnitDecl>(Outer)) { 304 // Context is the TU. Nothing needs to be done. 305 return nullptr; 306 } else { 307 // Decl's context was neither the TU, a namespace, nor a 308 // TagDecl, which means it is a type local to a scope, and not 309 // accessible at the end of the TU. 310 return nullptr; 311 } 312 } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { 313 return NestedNameSpecifier::GlobalSpecifier(Ctx); 314 } 315 return nullptr; 316 } 317 318 /// Create a nested name specifier for the declaring context of 319 /// the type. 320 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( 321 const ASTContext &Ctx, const Type *TypePtr, 322 bool FullyQualified, bool WithGlobalNsPrefix) { 323 if (!TypePtr) return nullptr; 324 325 Decl *Decl = nullptr; 326 // There are probably other cases ... 327 if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) { 328 Decl = TDT->getDecl(); 329 } else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) { 330 Decl = TagDeclType->getDecl(); 331 } else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) { 332 Decl = TST->getTemplateName().getAsTemplateDecl(); 333 } else { 334 Decl = TypePtr->getAsCXXRecordDecl(); 335 } 336 337 if (!Decl) return nullptr; 338 339 return createNestedNameSpecifierForScopeOf( 340 Ctx, Decl, FullyQualified, WithGlobalNsPrefix); 341 } 342 343 NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, 344 const NamespaceDecl *Namespace, 345 bool WithGlobalNsPrefix) { 346 while (Namespace && Namespace->isInline()) { 347 // Ignore inline namespace; 348 Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext()); 349 } 350 if (!Namespace) return nullptr; 351 352 bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces 353 return NestedNameSpecifier::Create( 354 Ctx, 355 createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix), 356 Namespace); 357 } 358 359 NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, 360 const TypeDecl *TD, 361 bool FullyQualify, 362 bool WithGlobalNsPrefix) { 363 const Type *TypePtr = TD->getTypeForDecl(); 364 if (isa<const TemplateSpecializationType>(TypePtr) || 365 isa<const RecordType>(TypePtr)) { 366 // We are asked to fully qualify and we have a Record Type (which 367 // may point to a template specialization) or Template 368 // Specialization Type. We need to fully qualify their arguments. 369 370 TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix); 371 } 372 373 return NestedNameSpecifier::Create( 374 Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), 375 false /*No TemplateKeyword*/, TypePtr); 376 } 377 378 /// Return the fully qualified type, including fully-qualified 379 /// versions of any template parameters. 380 QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, 381 bool WithGlobalNsPrefix) { 382 // In case of myType* we need to strip the pointer first, fully 383 // qualify and attach the pointer once again. 384 if (isa<PointerType>(QT.getTypePtr())) { 385 // Get the qualifiers. 386 Qualifiers Quals = QT.getQualifiers(); 387 QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); 388 QT = Ctx.getPointerType(QT); 389 // Add back the qualifiers. 390 QT = Ctx.getQualifiedType(QT, Quals); 391 return QT; 392 } 393 394 if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) { 395 // Get the qualifiers. 396 Qualifiers Quals = QT.getQualifiers(); 397 // Fully qualify the pointee and class types. 398 QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); 399 QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx, 400 WithGlobalNsPrefix); 401 QT = Ctx.getMemberPointerType(QT, Class.getTypePtr()); 402 // Add back the qualifiers. 403 QT = Ctx.getQualifiedType(QT, Quals); 404 return QT; 405 } 406 407 // In case of myType& we need to strip the reference first, fully 408 // qualify and attach the reference once again. 409 if (isa<ReferenceType>(QT.getTypePtr())) { 410 // Get the qualifiers. 411 bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr()); 412 Qualifiers Quals = QT.getQualifiers(); 413 QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); 414 // Add the r- or l-value reference type back to the fully 415 // qualified one. 416 if (IsLValueRefTy) 417 QT = Ctx.getLValueReferenceType(QT); 418 else 419 QT = Ctx.getRValueReferenceType(QT); 420 // Add back the qualifiers. 421 QT = Ctx.getQualifiedType(QT, Quals); 422 return QT; 423 } 424 425 // We don't consider the alias introduced by `using a::X` as a new type. 426 // The qualified name is still a::X. 427 if (isa<UsingType>(QT.getTypePtr())) { 428 return getFullyQualifiedType(QT.getSingleStepDesugaredType(Ctx), Ctx, 429 WithGlobalNsPrefix); 430 } 431 432 // Remove the part of the type related to the type being a template 433 // parameter (we won't report it as part of the 'type name' and it 434 // is actually make the code below to be more complex (to handle 435 // those) 436 while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) { 437 // Get the qualifiers. 438 Qualifiers Quals = QT.getQualifiers(); 439 440 QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar(); 441 442 // Add back the qualifiers. 443 QT = Ctx.getQualifiedType(QT, Quals); 444 } 445 446 NestedNameSpecifier *Prefix = nullptr; 447 // Local qualifiers are attached to the QualType outside of the 448 // elaborated type. Retrieve them before descending into the 449 // elaborated type. 450 Qualifiers PrefixQualifiers = QT.getLocalQualifiers(); 451 QT = QualType(QT.getTypePtr(), 0); 452 ElaboratedTypeKeyword Keyword = ETK_None; 453 if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) { 454 QT = ETypeInput->getNamedType(); 455 assert(!QT.hasLocalQualifiers()); 456 Keyword = ETypeInput->getKeyword(); 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 != ETK_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