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