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