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