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