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