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