1284 lines · cpp
1//===- USRGeneration.cpp - Routines for USR generation --------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Index/USRGeneration.h"10#include "clang/AST/ASTContext.h"11#include "clang/AST/Attr.h"12#include "clang/AST/DeclCXX.h"13#include "clang/AST/DeclTemplate.h"14#include "clang/AST/DeclVisitor.h"15#include "clang/AST/ODRHash.h"16#include "clang/Lex/PreprocessingRecord.h"17#include "llvm/Support/Path.h"18#include "llvm/Support/raw_ostream.h"19 20using namespace clang;21using namespace clang::index;22 23//===----------------------------------------------------------------------===//24// USR generation.25//===----------------------------------------------------------------------===//26 27/// \returns true on error.28static bool printLoc(llvm::raw_ostream &OS, SourceLocation Loc,29 const SourceManager &SM, bool IncludeOffset) {30 if (Loc.isInvalid()) {31 return true;32 }33 Loc = SM.getExpansionLoc(Loc);34 const FileIDAndOffset &Decomposed = SM.getDecomposedLoc(Loc);35 OptionalFileEntryRef FE = SM.getFileEntryRefForID(Decomposed.first);36 if (FE) {37 OS << llvm::sys::path::filename(FE->getName());38 } else {39 // This case really isn't interesting.40 return true;41 }42 if (IncludeOffset) {43 // Use the offest into the FileID to represent the location. Using44 // a line/column can cause us to look back at the original source file,45 // which is expensive.46 OS << '@' << Decomposed.second;47 }48 return false;49}50 51static StringRef GetExternalSourceContainer(const NamedDecl *D) {52 if (!D)53 return StringRef();54 if (auto *attr = D->getExternalSourceSymbolAttr()) {55 return attr->getDefinedIn();56 }57 return StringRef();58}59 60namespace {61class USRGenerator : public ConstDeclVisitor<USRGenerator> {62 SmallVectorImpl<char> &Buf;63 llvm::raw_svector_ostream Out;64 ASTContext *Context;65 const LangOptions &LangOpts;66 bool IgnoreResults = false;67 bool generatedLoc = false;68 69 llvm::DenseMap<const Type *, unsigned> TypeSubstitutions;70 71public:72 USRGenerator(ASTContext *Ctx, SmallVectorImpl<char> &Buf,73 const LangOptions &LangOpts)74 : Buf(Buf), Out(Buf), Context(Ctx), LangOpts(LangOpts) {75 // Add the USR space prefix.76 Out << getUSRSpacePrefix();77 }78 79 bool ignoreResults() const { return IgnoreResults; }80 81 // Visitation methods from generating USRs from AST elements.82 void VisitDeclContext(const DeclContext *D);83 void VisitFieldDecl(const FieldDecl *D);84 void VisitFunctionDecl(const FunctionDecl *D);85 void VisitNamedDecl(const NamedDecl *D);86 void VisitNamespaceDecl(const NamespaceDecl *D);87 void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D);88 void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);89 void VisitClassTemplateDecl(const ClassTemplateDecl *D);90 void VisitObjCContainerDecl(const ObjCContainerDecl *CD,91 const ObjCCategoryDecl *CatD = nullptr);92 void VisitObjCMethodDecl(const ObjCMethodDecl *MD);93 void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);94 void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);95 void VisitTagDecl(const TagDecl *D);96 void VisitTypedefDecl(const TypedefDecl *D);97 void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);98 void VisitVarDecl(const VarDecl *D);99 void VisitBindingDecl(const BindingDecl *D);100 void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);101 void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);102 void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D);103 void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D);104 void VisitConceptDecl(const ConceptDecl *D);105 106 void VisitLinkageSpecDecl(const LinkageSpecDecl *D) {107 IgnoreResults = true; // No USRs for linkage specs themselves.108 }109 110 void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {111 IgnoreResults = true;112 }113 114 void VisitUsingDecl(const UsingDecl *D) {115 VisitDeclContext(D->getDeclContext());116 Out << "@UD@";117 118 bool EmittedDeclName = !EmitDeclName(D);119 assert(EmittedDeclName && "EmitDeclName can not fail for UsingDecls");120 (void)EmittedDeclName;121 }122 123 bool ShouldGenerateLocation(const NamedDecl *D);124 125 bool isLocal(const NamedDecl *D) {126 return D->getParentFunctionOrMethod() != nullptr;127 }128 129 void GenExtSymbolContainer(const NamedDecl *D);130 131 /// Generate the string component containing the location of the132 /// declaration.133 bool GenLoc(const Decl *D, bool IncludeOffset);134 135 /// String generation methods used both by the visitation methods136 /// and from other clients that want to directly generate USRs. These137 /// methods do not construct complete USRs (which incorporate the parents138 /// of an AST element), but only the fragments concerning the AST element139 /// itself.140 141 /// Generate a USR for an Objective-C class.142 void GenObjCClass(StringRef cls, StringRef ExtSymDefinedIn,143 StringRef CategoryContextExtSymbolDefinedIn) {144 generateUSRForObjCClass(cls, Out, ExtSymDefinedIn,145 CategoryContextExtSymbolDefinedIn);146 }147 148 /// Generate a USR for an Objective-C class category.149 void GenObjCCategory(StringRef cls, StringRef cat,150 StringRef clsExt, StringRef catExt) {151 generateUSRForObjCCategory(cls, cat, Out, clsExt, catExt);152 }153 154 /// Generate a USR fragment for an Objective-C property.155 void GenObjCProperty(StringRef prop, bool isClassProp) {156 generateUSRForObjCProperty(prop, isClassProp, Out);157 }158 159 /// Generate a USR for an Objective-C protocol.160 void GenObjCProtocol(StringRef prot, StringRef ext) {161 generateUSRForObjCProtocol(prot, Out, ext);162 }163 164 void VisitType(QualType T);165 void VisitTemplateParameterList(const TemplateParameterList *Params);166 void VisitTemplateName(TemplateName Name);167 void VisitTemplateArgument(const TemplateArgument &Arg);168 169 void VisitMSGuidDecl(const MSGuidDecl *D);170 171 /// Emit a Decl's name using NamedDecl::printName() and return true if172 /// the decl had no name.173 bool EmitDeclName(const NamedDecl *D);174};175} // end anonymous namespace176 177//===----------------------------------------------------------------------===//178// Generating USRs from ASTS.179//===----------------------------------------------------------------------===//180 181bool USRGenerator::EmitDeclName(const NamedDecl *D) {182 DeclarationName N = D->getDeclName();183 if (N.isEmpty())184 return true;185 Out << N;186 return false;187}188 189bool USRGenerator::ShouldGenerateLocation(const NamedDecl *D) {190 if (D->isExternallyVisible())191 return false;192 if (D->getParentFunctionOrMethod())193 return true;194 SourceLocation Loc = D->getLocation();195 if (Loc.isInvalid())196 return false;197 const SourceManager &SM = Context->getSourceManager();198 return !SM.isInSystemHeader(Loc);199}200 201void USRGenerator::VisitDeclContext(const DeclContext *DC) {202 if (const NamedDecl *D = dyn_cast<NamedDecl>(DC))203 Visit(D);204 else if (isa<LinkageSpecDecl>(DC)) // Linkage specs are transparent in USRs.205 VisitDeclContext(DC->getParent());206}207 208void USRGenerator::VisitFieldDecl(const FieldDecl *D) {209 // The USR for an ivar declared in a class extension is based on the210 // ObjCInterfaceDecl, not the ObjCCategoryDecl.211 if (const ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))212 Visit(ID);213 else214 VisitDeclContext(D->getDeclContext());215 Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@");216 if (EmitDeclName(D)) {217 // Bit fields can be anonymous.218 IgnoreResults = true;219 return;220 }221}222 223void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {224 if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))225 return;226 227 if (D->getType().isNull()) {228 IgnoreResults = true;229 return;230 }231 232 const unsigned StartSize = Buf.size();233 VisitDeclContext(D->getDeclContext());234 if (Buf.size() == StartSize)235 GenExtSymbolContainer(D);236 237 bool IsTemplate = false;238 if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) {239 IsTemplate = true;240 Out << "@FT@";241 VisitTemplateParameterList(FunTmpl->getTemplateParameters());242 } else243 Out << "@F@";244 245 PrintingPolicy Policy(LangOpts);246 // Forward references can have different template argument names. Suppress the247 // template argument names in constructors to make their USR more stable.248 Policy.SuppressTemplateArgsInCXXConstructors = true;249 D->getDeclName().print(Out, Policy);250 251 if ((!LangOpts.CPlusPlus || D->isExternC()) &&252 !D->hasAttr<OverloadableAttr>())253 return;254 255 if (D->isFunctionTemplateSpecialization()) {256 Out << '<';257 if (const TemplateArgumentList *SpecArgs =258 D->getTemplateSpecializationArgs()) {259 for (const auto &Arg : SpecArgs->asArray()) {260 Out << '#';261 VisitTemplateArgument(Arg);262 }263 } else if (const ASTTemplateArgumentListInfo *SpecArgsWritten =264 D->getTemplateSpecializationArgsAsWritten()) {265 for (const auto &ArgLoc : SpecArgsWritten->arguments()) {266 Out << '#';267 VisitTemplateArgument(ArgLoc.getArgument());268 }269 }270 Out << '>';271 }272 273 QualType CanonicalType = D->getType().getCanonicalType();274 // Mangle in type information for the arguments.275 if (const auto *FPT = CanonicalType->getAs<FunctionProtoType>()) {276 for (QualType PT : FPT->param_types()) {277 Out << '#';278 VisitType(PT);279 }280 }281 if (D->isVariadic())282 Out << '.';283 if (IsTemplate) {284 // Function templates can be overloaded by return type, for example:285 // \code286 // template <class T> typename T::A foo() {}287 // template <class T> typename T::B foo() {}288 // \endcode289 Out << '#';290 VisitType(D->getReturnType());291 }292 Out << '#';293 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {294 if (MD->isStatic())295 Out << 'S';296 // FIXME: OpenCL: Need to consider address spaces297 if (unsigned quals = MD->getMethodQualifiers().getCVRUQualifiers())298 Out << (char)('0' + quals);299 switch (MD->getRefQualifier()) {300 case RQ_None: break;301 case RQ_LValue: Out << '&'; break;302 case RQ_RValue: Out << "&&"; break;303 }304 }305}306 307void USRGenerator::VisitNamedDecl(const NamedDecl *D) {308 VisitDeclContext(D->getDeclContext());309 Out << "@";310 311 if (EmitDeclName(D)) {312 // The string can be empty if the declaration has no name; e.g., it is313 // the ParmDecl with no name for declaration of a function pointer type,314 // e.g.: void (*f)(void *);315 // In this case, don't generate a USR.316 IgnoreResults = true;317 }318}319 320void USRGenerator::VisitVarDecl(const VarDecl *D) {321 // VarDecls can be declared 'extern' within a function or method body,322 // but their enclosing DeclContext is the function, not the TU. We need323 // to check the storage class to correctly generate the USR.324 if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))325 return;326 327 VisitDeclContext(D->getDeclContext());328 329 if (VarTemplateDecl *VarTmpl = D->getDescribedVarTemplate()) {330 Out << "@VT";331 VisitTemplateParameterList(VarTmpl->getTemplateParameters());332 } else if (const VarTemplatePartialSpecializationDecl *PartialSpec333 = dyn_cast<VarTemplatePartialSpecializationDecl>(D)) {334 Out << "@VP";335 VisitTemplateParameterList(PartialSpec->getTemplateParameters());336 }337 338 // Variables always have simple names.339 StringRef s = D->getName();340 341 // The string can be empty if the declaration has no name; e.g., it is342 // the ParmDecl with no name for declaration of a function pointer type, e.g.:343 // void (*f)(void *);344 // In this case, don't generate a USR.345 if (s.empty())346 IgnoreResults = true;347 else348 Out << '@' << s;349 350 // For a template specialization, mangle the template arguments.351 if (const VarTemplateSpecializationDecl *Spec352 = dyn_cast<VarTemplateSpecializationDecl>(D)) {353 const TemplateArgumentList &Args = Spec->getTemplateArgs();354 Out << '>';355 for (unsigned I = 0, N = Args.size(); I != N; ++I) {356 Out << '#';357 VisitTemplateArgument(Args.get(I));358 }359 }360}361 362void USRGenerator::VisitBindingDecl(const BindingDecl *D) {363 if (isLocal(D) && GenLoc(D, /*IncludeOffset=*/true))364 return;365 VisitNamedDecl(D);366}367 368void USRGenerator::VisitNonTypeTemplateParmDecl(369 const NonTypeTemplateParmDecl *D) {370 GenLoc(D, /*IncludeOffset=*/true);371}372 373void USRGenerator::VisitTemplateTemplateParmDecl(374 const TemplateTemplateParmDecl *D) {375 GenLoc(D, /*IncludeOffset=*/true);376}377 378void USRGenerator::VisitNamespaceDecl(const NamespaceDecl *D) {379 if (IgnoreResults)380 return;381 VisitDeclContext(D->getDeclContext());382 if (D->isAnonymousNamespace()) {383 Out << "@aN";384 return;385 }386 Out << "@N@" << D->getName();387}388 389void USRGenerator::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {390 VisitFunctionDecl(D->getTemplatedDecl());391}392 393void USRGenerator::VisitClassTemplateDecl(const ClassTemplateDecl *D) {394 VisitTagDecl(D->getTemplatedDecl());395}396 397void USRGenerator::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {398 VisitDeclContext(D->getDeclContext());399 if (!IgnoreResults)400 Out << "@NA@" << D->getName();401}402 403static const ObjCCategoryDecl *getCategoryContext(const NamedDecl *D) {404 if (auto *CD = dyn_cast<ObjCCategoryDecl>(D->getDeclContext()))405 return CD;406 if (auto *ICD = dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext()))407 return ICD->getCategoryDecl();408 return nullptr;409}410 411void USRGenerator::VisitObjCMethodDecl(const ObjCMethodDecl *D) {412 const DeclContext *container = D->getDeclContext();413 if (const ObjCProtocolDecl *pd = dyn_cast<ObjCProtocolDecl>(container)) {414 Visit(pd);415 }416 else {417 // The USR for a method declared in a class extension or category is based on418 // the ObjCInterfaceDecl, not the ObjCCategoryDecl.419 const ObjCInterfaceDecl *ID = D->getClassInterface();420 if (!ID) {421 IgnoreResults = true;422 return;423 }424 auto *CD = getCategoryContext(D);425 VisitObjCContainerDecl(ID, CD);426 }427 // Ideally we would use 'GenObjCMethod', but this is such a hot path428 // for Objective-C code that we don't want to use429 // DeclarationName::getAsString().430 Out << (D->isInstanceMethod() ? "(im)" : "(cm)")431 << DeclarationName(D->getSelector());432}433 434void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D,435 const ObjCCategoryDecl *CatD) {436 switch (D->getKind()) {437 default:438 llvm_unreachable("Invalid ObjC container.");439 case Decl::ObjCInterface:440 case Decl::ObjCImplementation:441 GenObjCClass(D->getName(), GetExternalSourceContainer(D),442 GetExternalSourceContainer(CatD));443 break;444 case Decl::ObjCCategory: {445 const ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);446 const ObjCInterfaceDecl *ID = CD->getClassInterface();447 if (!ID) {448 // Handle invalid code where the @interface might not449 // have been specified.450 // FIXME: We should be able to generate this USR even if the451 // @interface isn't available.452 IgnoreResults = true;453 return;454 }455 // Specially handle class extensions, which are anonymous categories.456 // We want to mangle in the location to uniquely distinguish them.457 if (CD->IsClassExtension()) {458 Out << "objc(ext)" << ID->getName() << '@';459 GenLoc(CD, /*IncludeOffset=*/true);460 }461 else462 GenObjCCategory(ID->getName(), CD->getName(),463 GetExternalSourceContainer(ID),464 GetExternalSourceContainer(CD));465 466 break;467 }468 case Decl::ObjCCategoryImpl: {469 const ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);470 const ObjCInterfaceDecl *ID = CD->getClassInterface();471 if (!ID) {472 // Handle invalid code where the @interface might not473 // have been specified.474 // FIXME: We should be able to generate this USR even if the475 // @interface isn't available.476 IgnoreResults = true;477 return;478 }479 GenObjCCategory(ID->getName(), CD->getName(),480 GetExternalSourceContainer(ID),481 GetExternalSourceContainer(CD));482 break;483 }484 case Decl::ObjCProtocol: {485 const ObjCProtocolDecl *PD = cast<ObjCProtocolDecl>(D);486 GenObjCProtocol(PD->getName(), GetExternalSourceContainer(PD));487 break;488 }489 }490}491 492void USRGenerator::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {493 // The USR for a property declared in a class extension or category is based494 // on the ObjCInterfaceDecl, not the ObjCCategoryDecl.495 if (const ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))496 VisitObjCContainerDecl(ID, getCategoryContext(D));497 else498 Visit(cast<Decl>(D->getDeclContext()));499 GenObjCProperty(D->getName(), D->isClassProperty());500}501 502void USRGenerator::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {503 if (ObjCPropertyDecl *PD = D->getPropertyDecl()) {504 VisitObjCPropertyDecl(PD);505 return;506 }507 508 IgnoreResults = true;509}510 511void USRGenerator::VisitTagDecl(const TagDecl *D) {512 // Add the location of the tag decl to handle resolution across513 // translation units.514 if (!isa<EnumDecl>(D) &&515 ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))516 return;517 518 GenExtSymbolContainer(D);519 520 D = D->getCanonicalDecl();521 VisitDeclContext(D->getDeclContext());522 523 bool AlreadyStarted = false;524 if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {525 if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) {526 AlreadyStarted = true;527 528 switch (D->getTagKind()) {529 case TagTypeKind::Interface:530 case TagTypeKind::Class:531 case TagTypeKind::Struct:532 Out << "@ST";533 break;534 case TagTypeKind::Union:535 Out << "@UT";536 break;537 case TagTypeKind::Enum:538 llvm_unreachable("enum template");539 }540 VisitTemplateParameterList(ClassTmpl->getTemplateParameters());541 } else if (const ClassTemplatePartialSpecializationDecl *PartialSpec542 = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) {543 AlreadyStarted = true;544 545 switch (D->getTagKind()) {546 case TagTypeKind::Interface:547 case TagTypeKind::Class:548 case TagTypeKind::Struct:549 Out << "@SP";550 break;551 case TagTypeKind::Union:552 Out << "@UP";553 break;554 case TagTypeKind::Enum:555 llvm_unreachable("enum partial specialization");556 }557 VisitTemplateParameterList(PartialSpec->getTemplateParameters());558 }559 }560 561 if (!AlreadyStarted) {562 switch (D->getTagKind()) {563 case TagTypeKind::Interface:564 case TagTypeKind::Class:565 case TagTypeKind::Struct:566 Out << "@S";567 break;568 case TagTypeKind::Union:569 Out << "@U";570 break;571 case TagTypeKind::Enum:572 Out << "@E";573 break;574 }575 }576 577 Out << '@';578 assert(Buf.size() > 0);579 const unsigned off = Buf.size() - 1;580 581 if (EmitDeclName(D)) {582 if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) {583 Buf[off] = 'A';584 Out << '@' << *TD;585 } else {586 if (D->isEmbeddedInDeclarator() && !D->isFreeStanding()) {587 printLoc(Out, D->getLocation(), Context->getSourceManager(), true);588 } else {589 Buf[off] = 'a';590 if (auto *ED = dyn_cast<EnumDecl>(D)) {591 // Distinguish USRs of anonymous enums by using their first592 // enumerator.593 auto enum_range = ED->enumerators();594 if (enum_range.begin() != enum_range.end()) {595 Out << '@' << **enum_range.begin();596 }597 }598 }599 }600 }601 602 // For a class template specialization, mangle the template arguments.603 if (const ClassTemplateSpecializationDecl *Spec604 = dyn_cast<ClassTemplateSpecializationDecl>(D)) {605 const TemplateArgumentList &Args = Spec->getTemplateArgs();606 Out << '>';607 for (unsigned I = 0, N = Args.size(); I != N; ++I) {608 Out << '#';609 VisitTemplateArgument(Args.get(I));610 }611 }612}613 614void USRGenerator::VisitTypedefDecl(const TypedefDecl *D) {615 if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))616 return;617 const DeclContext *DC = D->getDeclContext();618 if (const NamedDecl *DCN = dyn_cast<NamedDecl>(DC))619 Visit(DCN);620 Out << "@T@";621 Out << D->getName();622}623 624void USRGenerator::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {625 GenLoc(D, /*IncludeOffset=*/true);626}627 628void USRGenerator::GenExtSymbolContainer(const NamedDecl *D) {629 StringRef Container = GetExternalSourceContainer(D);630 if (!Container.empty())631 Out << "@M@" << Container;632}633 634bool USRGenerator::GenLoc(const Decl *D, bool IncludeOffset) {635 if (generatedLoc)636 return IgnoreResults;637 generatedLoc = true;638 639 // Guard against null declarations in invalid code.640 if (!D) {641 IgnoreResults = true;642 return true;643 }644 645 // Use the location of canonical decl.646 D = D->getCanonicalDecl();647 648 IgnoreResults =649 IgnoreResults || printLoc(Out, D->getBeginLoc(),650 Context->getSourceManager(), IncludeOffset);651 652 return IgnoreResults;653}654 655static void printQualifier(llvm::raw_ostream &Out, const LangOptions &LangOpts,656 NestedNameSpecifier NNS) {657 // FIXME: Encode the qualifier, don't just print it.658 PrintingPolicy PO(LangOpts);659 PO.SuppressTagKeyword = true;660 PO.SuppressUnwrittenScope = true;661 PO.ConstantArraySizeAsWritten = false;662 PO.AnonymousTagLocations = false;663 NNS.print(Out, PO);664}665 666void USRGenerator::VisitType(QualType T) {667 // This method mangles in USR information for types. It can possibly668 // just reuse the naming-mangling logic used by codegen, although the669 // requirements for USRs might not be the same.670 ASTContext &Ctx = *Context;671 672 do {673 T = Ctx.getCanonicalType(T);674 Qualifiers Q = T.getQualifiers();675 unsigned qVal = 0;676 if (Q.hasConst())677 qVal |= 0x1;678 if (Q.hasVolatile())679 qVal |= 0x2;680 if (Q.hasRestrict())681 qVal |= 0x4;682 if(qVal)683 Out << ((char) ('0' + qVal));684 685 // Mangle in ObjC GC qualifiers?686 687 if (const PackExpansionType *Expansion = T->getAs<PackExpansionType>()) {688 Out << 'P';689 T = Expansion->getPattern();690 }691 692 if (const BuiltinType *BT = T->getAs<BuiltinType>()) {693 switch (BT->getKind()) {694 case BuiltinType::Void:695 Out << 'v'; break;696 case BuiltinType::Bool:697 Out << 'b'; break;698 case BuiltinType::UChar:699 Out << 'c'; break;700 case BuiltinType::Char8:701 Out << 'u'; break;702 case BuiltinType::Char16:703 Out << 'q'; break;704 case BuiltinType::Char32:705 Out << 'w'; break;706 case BuiltinType::UShort:707 Out << 's'; break;708 case BuiltinType::UInt:709 Out << 'i'; break;710 case BuiltinType::ULong:711 Out << 'l'; break;712 case BuiltinType::ULongLong:713 Out << 'k'; break;714 case BuiltinType::UInt128:715 Out << 'j'; break;716 case BuiltinType::Char_U:717 case BuiltinType::Char_S:718 Out << 'C'; break;719 case BuiltinType::SChar:720 Out << 'r'; break;721 case BuiltinType::WChar_S:722 case BuiltinType::WChar_U:723 Out << 'W'; break;724 case BuiltinType::Short:725 Out << 'S'; break;726 case BuiltinType::Int:727 Out << 'I'; break;728 case BuiltinType::Long:729 Out << 'L'; break;730 case BuiltinType::LongLong:731 Out << 'K'; break;732 case BuiltinType::Int128:733 Out << 'J'; break;734 case BuiltinType::Float16:735 case BuiltinType::Half:736 Out << 'h'; break;737 case BuiltinType::Float:738 Out << 'f'; break;739 case BuiltinType::Double:740 Out << 'd'; break;741 case BuiltinType::LongDouble:742 Out << 'D'; break;743 case BuiltinType::Float128:744 Out << 'Q'; break;745 case BuiltinType::NullPtr:746 Out << 'n'; break;747#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \748 case BuiltinType::Id: \749 Out << "@BT@" << #Suffix << "_" << #ImgType; break;750#include "clang/Basic/OpenCLImageTypes.def"751#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \752 case BuiltinType::Id: \753 Out << "@BT@" << #ExtType; break;754#include "clang/Basic/OpenCLExtensionTypes.def"755 case BuiltinType::OCLEvent:756 Out << "@BT@OCLEvent"; break;757 case BuiltinType::OCLClkEvent:758 Out << "@BT@OCLClkEvent"; break;759 case BuiltinType::OCLQueue:760 Out << "@BT@OCLQueue"; break;761 case BuiltinType::OCLReserveID:762 Out << "@BT@OCLReserveID"; break;763 case BuiltinType::OCLSampler:764 Out << "@BT@OCLSampler"; break;765#define SVE_TYPE(Name, Id, SingletonId) \766 case BuiltinType::Id: \767 Out << "@BT@" << #Name; \768 break;769#include "clang/Basic/AArch64ACLETypes.def"770#define PPC_VECTOR_TYPE(Name, Id, Size) \771 case BuiltinType::Id: \772 Out << "@BT@" << #Name; break;773#include "clang/Basic/PPCTypes.def"774#define RVV_TYPE(Name, Id, SingletonId) \775 case BuiltinType::Id: \776 Out << "@BT@" << Name; break;777#include "clang/Basic/RISCVVTypes.def"778#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:779#include "clang/Basic/WebAssemblyReferenceTypes.def"780#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \781 case BuiltinType::Id: \782 Out << "@BT@" << #Name; \783 break;784#include "clang/Basic/AMDGPUTypes.def"785#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) \786 case BuiltinType::Id: \787 Out << "@BT@" << #Name; \788 break;789#include "clang/Basic/HLSLIntangibleTypes.def"790 case BuiltinType::ShortAccum:791 Out << "@BT@ShortAccum"; break;792 case BuiltinType::Accum:793 Out << "@BT@Accum"; break;794 case BuiltinType::LongAccum:795 Out << "@BT@LongAccum"; break;796 case BuiltinType::UShortAccum:797 Out << "@BT@UShortAccum"; break;798 case BuiltinType::UAccum:799 Out << "@BT@UAccum"; break;800 case BuiltinType::ULongAccum:801 Out << "@BT@ULongAccum"; break;802 case BuiltinType::ShortFract:803 Out << "@BT@ShortFract"; break;804 case BuiltinType::Fract:805 Out << "@BT@Fract"; break;806 case BuiltinType::LongFract:807 Out << "@BT@LongFract"; break;808 case BuiltinType::UShortFract:809 Out << "@BT@UShortFract"; break;810 case BuiltinType::UFract:811 Out << "@BT@UFract"; break;812 case BuiltinType::ULongFract:813 Out << "@BT@ULongFract"; break;814 case BuiltinType::SatShortAccum:815 Out << "@BT@SatShortAccum"; break;816 case BuiltinType::SatAccum:817 Out << "@BT@SatAccum"; break;818 case BuiltinType::SatLongAccum:819 Out << "@BT@SatLongAccum"; break;820 case BuiltinType::SatUShortAccum:821 Out << "@BT@SatUShortAccum"; break;822 case BuiltinType::SatUAccum:823 Out << "@BT@SatUAccum"; break;824 case BuiltinType::SatULongAccum:825 Out << "@BT@SatULongAccum"; break;826 case BuiltinType::SatShortFract:827 Out << "@BT@SatShortFract"; break;828 case BuiltinType::SatFract:829 Out << "@BT@SatFract"; break;830 case BuiltinType::SatLongFract:831 Out << "@BT@SatLongFract"; break;832 case BuiltinType::SatUShortFract:833 Out << "@BT@SatUShortFract"; break;834 case BuiltinType::SatUFract:835 Out << "@BT@SatUFract"; break;836 case BuiltinType::SatULongFract:837 Out << "@BT@SatULongFract"; break;838 case BuiltinType::BFloat16:839 Out << "@BT@__bf16"; break;840 case BuiltinType::Ibm128:841 Out << "@BT@__ibm128"; break;842 case BuiltinType::ObjCId:843 Out << 'o'; break;844 case BuiltinType::ObjCClass:845 Out << 'O'; break;846 case BuiltinType::ObjCSel:847 Out << 'e'; break;848#define BUILTIN_TYPE(Id, SingletonId)849#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:850#include "clang/AST/BuiltinTypes.def"851 case BuiltinType::Dependent:852 // If you're adding a new builtin type, please add its name prefixed853 // with "@BT@" to `Out` (see cases above).854 IgnoreResults = true;855 break;856 }857 return;858 }859 860 // If we have already seen this (non-built-in) type, use a substitution861 // encoding. Otherwise, record this as a substitution.862 auto [Substitution, Inserted] =863 TypeSubstitutions.try_emplace(T.getTypePtr(), TypeSubstitutions.size());864 if (!Inserted) {865 Out << 'S' << Substitution->second << '_';866 return;867 }868 869 if (const PointerType *PT = T->getAs<PointerType>()) {870 Out << '*';871 T = PT->getPointeeType();872 continue;873 }874 if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) {875 Out << '*';876 T = OPT->getPointeeType();877 continue;878 }879 if (const RValueReferenceType *RT = T->getAs<RValueReferenceType>()) {880 Out << "&&";881 T = RT->getPointeeType();882 continue;883 }884 if (const ReferenceType *RT = T->getAs<ReferenceType>()) {885 Out << '&';886 T = RT->getPointeeType();887 continue;888 }889 if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) {890 Out << 'F';891 VisitType(FT->getReturnType());892 Out << '(';893 for (const auto &I : FT->param_types()) {894 Out << '#';895 VisitType(I);896 }897 Out << ')';898 if (FT->isVariadic())899 Out << '.';900 return;901 }902 if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {903 Out << 'B';904 T = BT->getPointeeType();905 continue;906 }907 if (const ComplexType *CT = T->getAs<ComplexType>()) {908 Out << '<';909 T = CT->getElementType();910 continue;911 }912 if (const TagType *TT = T->getAs<TagType>()) {913 if (const auto *ICNT = dyn_cast<InjectedClassNameType>(TT)) {914 T = ICNT->getDecl()->getCanonicalTemplateSpecializationType(Ctx);915 } else {916 Out << '$';917 VisitTagDecl(TT->getDecl());918 return;919 }920 }921 if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) {922 Out << '$';923 VisitObjCInterfaceDecl(OIT->getDecl());924 return;925 }926 if (const ObjCObjectType *OIT = T->getAs<ObjCObjectType>()) {927 Out << 'Q';928 VisitType(OIT->getBaseType());929 for (auto *Prot : OIT->getProtocols())930 VisitObjCProtocolDecl(Prot);931 return;932 }933 if (const TemplateTypeParmType *TTP =934 T->getAsCanonical<TemplateTypeParmType>()) {935 Out << 't' << TTP->getDepth() << '.' << TTP->getIndex();936 return;937 }938 if (const TemplateSpecializationType *Spec939 = T->getAs<TemplateSpecializationType>()) {940 Out << '>';941 VisitTemplateName(Spec->getTemplateName());942 Out << Spec->template_arguments().size();943 for (const auto &Arg : Spec->template_arguments())944 VisitTemplateArgument(Arg);945 return;946 }947 if (const DependentNameType *DNT = T->getAs<DependentNameType>()) {948 Out << '^';949 printQualifier(Out, LangOpts, DNT->getQualifier());950 Out << ':' << DNT->getIdentifier()->getName();951 return;952 }953 if (const auto *VT = T->getAs<VectorType>()) {954 Out << (T->isExtVectorType() ? ']' : '[');955 Out << VT->getNumElements();956 T = VT->getElementType();957 continue;958 }959 if (const auto *const AT = dyn_cast<ArrayType>(T)) {960 Out << '{';961 switch (AT->getSizeModifier()) {962 case ArraySizeModifier::Static:963 Out << 's';964 break;965 case ArraySizeModifier::Star:966 Out << '*';967 break;968 case ArraySizeModifier::Normal:969 Out << 'n';970 break;971 }972 if (const auto *const CAT = dyn_cast<ConstantArrayType>(T))973 Out << CAT->getSize();974 975 T = AT->getElementType();976 continue;977 }978 979 // Unhandled type.980 Out << ' ';981 break;982 } while (true);983}984 985void USRGenerator::VisitTemplateParameterList(986 const TemplateParameterList *Params) {987 if (!Params)988 return;989 Out << '>' << Params->size();990 for (TemplateParameterList::const_iterator P = Params->begin(),991 PEnd = Params->end();992 P != PEnd; ++P) {993 Out << '#';994 if (isa<TemplateTypeParmDecl>(*P)) {995 if (cast<TemplateTypeParmDecl>(*P)->isParameterPack())996 Out<< 'p';997 Out << 'T';998 continue;999 }1000 1001 if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {1002 if (NTTP->isParameterPack())1003 Out << 'p';1004 Out << 'N';1005 VisitType(NTTP->getType());1006 continue;1007 }1008 1009 TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);1010 if (TTP->isParameterPack())1011 Out << 'p';1012 Out << 't';1013 VisitTemplateParameterList(TTP->getTemplateParameters());1014 }1015}1016 1017void USRGenerator::VisitTemplateName(TemplateName Name) {1018 if (TemplateDecl *Template = Name.getAsTemplateDecl()) {1019 if (TemplateTemplateParmDecl *TTP1020 = dyn_cast<TemplateTemplateParmDecl>(Template)) {1021 Out << 't' << TTP->getDepth() << '.' << TTP->getIndex();1022 return;1023 }1024 1025 Visit(Template);1026 return;1027 }1028 1029 // FIXME: Visit dependent template names.1030}1031 1032void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {1033 switch (Arg.getKind()) {1034 case TemplateArgument::Null:1035 break;1036 1037 case TemplateArgument::Declaration:1038 Visit(Arg.getAsDecl());1039 break;1040 1041 case TemplateArgument::NullPtr:1042 break;1043 1044 case TemplateArgument::TemplateExpansion:1045 Out << 'P'; // pack expansion of...1046 [[fallthrough]];1047 case TemplateArgument::Template:1048 VisitTemplateName(Arg.getAsTemplateOrTemplatePattern());1049 break;1050 1051 case TemplateArgument::Expression:1052 // FIXME: Visit expressions.1053 break;1054 1055 case TemplateArgument::Pack:1056 Out << 'p' << Arg.pack_size();1057 for (const auto &P : Arg.pack_elements())1058 VisitTemplateArgument(P);1059 break;1060 1061 case TemplateArgument::Type:1062 VisitType(Arg.getAsType());1063 break;1064 1065 case TemplateArgument::Integral:1066 Out << 'V';1067 VisitType(Arg.getIntegralType());1068 Out << Arg.getAsIntegral();1069 break;1070 1071 case TemplateArgument::StructuralValue: {1072 Out << 'S';1073 VisitType(Arg.getStructuralValueType());1074 ODRHash Hash{};1075 Hash.AddStructuralValue(Arg.getAsStructuralValue());1076 Out << Hash.CalculateHash();1077 break;1078 }1079 }1080}1081 1082void USRGenerator::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {1083 if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))1084 return;1085 VisitDeclContext(D->getDeclContext());1086 Out << "@UUV@";1087 printQualifier(Out, LangOpts, D->getQualifier());1088 EmitDeclName(D);1089}1090 1091void USRGenerator::VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) {1092 if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))1093 return;1094 VisitDeclContext(D->getDeclContext());1095 Out << "@UUT@";1096 printQualifier(Out, LangOpts, D->getQualifier());1097 Out << D->getName(); // Simple name.1098}1099 1100void USRGenerator::VisitConceptDecl(const ConceptDecl *D) {1101 if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))1102 return;1103 VisitDeclContext(D->getDeclContext());1104 Out << "@CT@";1105 EmitDeclName(D);1106}1107 1108void USRGenerator::VisitMSGuidDecl(const MSGuidDecl *D) {1109 VisitDeclContext(D->getDeclContext());1110 Out << "@MG@";1111 D->NamedDecl::printName(Out);1112}1113 1114//===----------------------------------------------------------------------===//1115// USR generation functions.1116//===----------------------------------------------------------------------===//1117 1118static void combineClassAndCategoryExtContainers(StringRef ClsSymDefinedIn,1119 StringRef CatSymDefinedIn,1120 raw_ostream &OS) {1121 if (ClsSymDefinedIn.empty() && CatSymDefinedIn.empty())1122 return;1123 if (CatSymDefinedIn.empty()) {1124 OS << "@M@" << ClsSymDefinedIn << '@';1125 return;1126 }1127 OS << "@CM@" << CatSymDefinedIn << '@';1128 if (ClsSymDefinedIn != CatSymDefinedIn) {1129 OS << ClsSymDefinedIn << '@';1130 }1131}1132 1133void clang::index::generateUSRForObjCClass(StringRef Cls, raw_ostream &OS,1134 StringRef ExtSymDefinedIn,1135 StringRef CategoryContextExtSymbolDefinedIn) {1136 combineClassAndCategoryExtContainers(ExtSymDefinedIn,1137 CategoryContextExtSymbolDefinedIn, OS);1138 OS << "objc(cs)" << Cls;1139}1140 1141void clang::index::generateUSRForObjCCategory(StringRef Cls, StringRef Cat,1142 raw_ostream &OS,1143 StringRef ClsSymDefinedIn,1144 StringRef CatSymDefinedIn) {1145 combineClassAndCategoryExtContainers(ClsSymDefinedIn, CatSymDefinedIn, OS);1146 OS << "objc(cy)" << Cls << '@' << Cat;1147}1148 1149void clang::index::generateUSRForObjCIvar(StringRef Ivar, raw_ostream &OS) {1150 OS << '@' << Ivar;1151}1152 1153void clang::index::generateUSRForObjCMethod(StringRef Sel,1154 bool IsInstanceMethod,1155 raw_ostream &OS) {1156 OS << (IsInstanceMethod ? "(im)" : "(cm)") << Sel;1157}1158 1159void clang::index::generateUSRForObjCProperty(StringRef Prop, bool isClassProp,1160 raw_ostream &OS) {1161 OS << (isClassProp ? "(cpy)" : "(py)") << Prop;1162}1163 1164void clang::index::generateUSRForObjCProtocol(StringRef Prot, raw_ostream &OS,1165 StringRef ExtSymDefinedIn) {1166 if (!ExtSymDefinedIn.empty())1167 OS << "@M@" << ExtSymDefinedIn << '@';1168 OS << "objc(pl)" << Prot;1169}1170 1171void clang::index::generateUSRForGlobalEnum(StringRef EnumName, raw_ostream &OS,1172 StringRef ExtSymDefinedIn) {1173 if (!ExtSymDefinedIn.empty())1174 OS << "@M@" << ExtSymDefinedIn;1175 OS << "@E@" << EnumName;1176}1177 1178void clang::index::generateUSRForEnumConstant(StringRef EnumConstantName,1179 raw_ostream &OS) {1180 OS << '@' << EnumConstantName;1181}1182 1183bool clang::index::generateUSRForDecl(const Decl *D,1184 SmallVectorImpl<char> &Buf) {1185 if (!D)1186 return true;1187 return generateUSRForDecl(D, Buf, D->getASTContext().getLangOpts());1188}1189 1190bool clang::index::generateUSRForDecl(const Decl *D, SmallVectorImpl<char> &Buf,1191 const LangOptions &LangOpts) {1192 if (!D)1193 return true;1194 // We don't ignore decls with invalid source locations. Implicit decls, like1195 // C++'s operator new function, can have invalid locations but it is fine to1196 // create USRs that can identify them.1197 1198 // Check if the declaration has explicit external USR specified.1199 auto *CD = D->getCanonicalDecl();1200 if (auto *ExternalSymAttr = CD->getAttr<ExternalSourceSymbolAttr>()) {1201 if (!ExternalSymAttr->getUSR().empty()) {1202 llvm::raw_svector_ostream Out(Buf);1203 Out << ExternalSymAttr->getUSR();1204 return false;1205 }1206 }1207 USRGenerator UG(&D->getASTContext(), Buf, LangOpts);1208 UG.Visit(D);1209 return UG.ignoreResults();1210}1211 1212bool clang::index::generateUSRForMacro(const MacroDefinitionRecord *MD,1213 const SourceManager &SM,1214 SmallVectorImpl<char> &Buf) {1215 if (!MD)1216 return true;1217 return generateUSRForMacro(MD->getName()->getName(), MD->getLocation(),1218 SM, Buf);1219 1220}1221 1222bool clang::index::generateUSRForMacro(StringRef MacroName, SourceLocation Loc,1223 const SourceManager &SM,1224 SmallVectorImpl<char> &Buf) {1225 if (MacroName.empty())1226 return true;1227 1228 llvm::raw_svector_ostream Out(Buf);1229 1230 // Assume that system headers are sane. Don't put source location1231 // information into the USR if the macro comes from a system header.1232 bool ShouldGenerateLocation = Loc.isValid() && !SM.isInSystemHeader(Loc);1233 1234 Out << getUSRSpacePrefix();1235 if (ShouldGenerateLocation)1236 printLoc(Out, Loc, SM, /*IncludeOffset=*/true);1237 Out << "@macro@";1238 Out << MacroName;1239 return false;1240}1241 1242bool clang::index::generateUSRForType(QualType T, ASTContext &Ctx,1243 SmallVectorImpl<char> &Buf) {1244 return generateUSRForType(T, Ctx, Buf, Ctx.getLangOpts());1245}1246 1247bool clang::index::generateUSRForType(QualType T, ASTContext &Ctx,1248 SmallVectorImpl<char> &Buf,1249 const LangOptions &LangOpts) {1250 if (T.isNull())1251 return true;1252 T = T.getCanonicalType();1253 1254 USRGenerator UG(&Ctx, Buf, LangOpts);1255 UG.VisitType(T);1256 return UG.ignoreResults();1257}1258 1259bool clang::index::generateFullUSRForModule(const Module *Mod,1260 raw_ostream &OS) {1261 if (!Mod->Parent)1262 return generateFullUSRForTopLevelModuleName(Mod->Name, OS);1263 if (generateFullUSRForModule(Mod->Parent, OS))1264 return true;1265 return generateUSRFragmentForModule(Mod, OS);1266}1267 1268bool clang::index::generateFullUSRForTopLevelModuleName(StringRef ModName,1269 raw_ostream &OS) {1270 OS << getUSRSpacePrefix();1271 return generateUSRFragmentForModuleName(ModName, OS);1272}1273 1274bool clang::index::generateUSRFragmentForModule(const Module *Mod,1275 raw_ostream &OS) {1276 return generateUSRFragmentForModuleName(Mod->Name, OS);1277}1278 1279bool clang::index::generateUSRFragmentForModuleName(StringRef ModName,1280 raw_ostream &OS) {1281 OS << "@M@" << ModName;1282 return false;1283}1284