xref: /freebsd/contrib/llvm-project/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- ExtractAPI/ExtractAPIVisitor.h ---------------------------*- C++ -*-===//
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 /// \file
10 /// This file defines the ExtractAPVisitor AST visitation interface.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
15 #define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
16 
17 #include "clang/AST/ASTContext.h"
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/DeclCXX.h"
20 #include "clang/AST/DeclObjC.h"
21 #include "clang/AST/DeclTemplate.h"
22 #include "clang/AST/ParentMapContext.h"
23 #include "clang/AST/RecursiveASTVisitor.h"
24 #include "clang/Basic/LLVM.h"
25 #include "clang/Basic/Module.h"
26 #include "clang/Basic/SourceManager.h"
27 #include "clang/Basic/Specifiers.h"
28 #include "clang/ExtractAPI/API.h"
29 #include "clang/ExtractAPI/DeclarationFragments.h"
30 #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
31 #include "clang/Index/USRGeneration.h"
32 #include "llvm/ADT/SmallString.h"
33 #include "llvm/ADT/StringRef.h"
34 #include "llvm/Support/Casting.h"
35 #include <type_traits>
36 
37 namespace clang {
38 namespace extractapi {
39 namespace impl {
40 
41 template <typename Derived>
42 class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
43   using Base = RecursiveASTVisitor<Derived>;
44 
45 protected:
ExtractAPIVisitorBase(ASTContext & Context,APISet & API)46   ExtractAPIVisitorBase(ASTContext &Context, APISet &API)
47       : Context(Context), API(API) {}
48 
49 public:
getAPI()50   const APISet &getAPI() const { return API; }
51 
52   bool VisitVarDecl(const VarDecl *Decl);
53 
54   bool VisitFunctionDecl(const FunctionDecl *Decl);
55 
56   bool VisitEnumDecl(const EnumDecl *Decl);
57 
58   bool WalkUpFromFunctionDecl(const FunctionDecl *Decl);
59 
60   bool WalkUpFromRecordDecl(const RecordDecl *Decl);
61 
62   bool WalkUpFromCXXRecordDecl(const CXXRecordDecl *Decl);
63 
64   bool WalkUpFromCXXMethodDecl(const CXXMethodDecl *Decl);
65 
66   bool WalkUpFromClassTemplateSpecializationDecl(
67       const ClassTemplateSpecializationDecl *Decl);
68 
69   bool WalkUpFromClassTemplatePartialSpecializationDecl(
70       const ClassTemplatePartialSpecializationDecl *Decl);
71 
72   bool WalkUpFromVarTemplateDecl(const VarTemplateDecl *Decl);
73 
74   bool WalkUpFromVarTemplateSpecializationDecl(
75       const VarTemplateSpecializationDecl *Decl);
76 
77   bool WalkUpFromVarTemplatePartialSpecializationDecl(
78       const VarTemplatePartialSpecializationDecl *Decl);
79 
80   bool WalkUpFromFunctionTemplateDecl(const FunctionTemplateDecl *Decl);
81 
82   bool WalkUpFromNamespaceDecl(const NamespaceDecl *Decl);
83 
84   bool VisitNamespaceDecl(const NamespaceDecl *Decl);
85 
86   bool TraverseRecordDecl(RecordDecl *Decl);
87   bool VisitRecordDecl(const RecordDecl *Decl);
88 
89   bool TraverseCXXRecordDecl(CXXRecordDecl *Decl);
90   bool VisitCXXRecordDecl(const CXXRecordDecl *Decl);
91 
92   bool VisitCXXMethodDecl(const CXXMethodDecl *Decl);
93 
94   bool VisitFieldDecl(const FieldDecl *Decl);
95 
96   bool VisitCXXConversionDecl(const CXXConversionDecl *Decl);
97 
98   bool VisitCXXConstructorDecl(const CXXConstructorDecl *Decl);
99 
100   bool VisitCXXDestructorDecl(const CXXDestructorDecl *Decl);
101 
102   bool VisitConceptDecl(const ConceptDecl *Decl);
103 
104   bool VisitClassTemplateSpecializationDecl(
105       const ClassTemplateSpecializationDecl *Decl);
106 
107   bool VisitClassTemplatePartialSpecializationDecl(
108       const ClassTemplatePartialSpecializationDecl *Decl);
109 
110   bool VisitVarTemplateDecl(const VarTemplateDecl *Decl);
111 
112   bool
113   VisitVarTemplateSpecializationDecl(const VarTemplateSpecializationDecl *Decl);
114 
115   bool VisitVarTemplatePartialSpecializationDecl(
116       const VarTemplatePartialSpecializationDecl *Decl);
117 
118   bool VisitFunctionTemplateDecl(const FunctionTemplateDecl *Decl);
119 
120   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl);
121 
122   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl);
123 
124   bool VisitTypedefNameDecl(const TypedefNameDecl *Decl);
125 
126   bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl);
127 
128   bool shouldDeclBeIncluded(const Decl *Decl) const;
129 
130   const RawComment *fetchRawCommentForDecl(const Decl *Decl) const;
131 
132 protected:
133   /// Collect API information for the enum constants and associate with the
134   /// parent enum.
135   void recordEnumConstants(SymbolReference Container,
136                            const EnumDecl::enumerator_range Constants);
137 
138   /// Collect API information for the Objective-C methods and associate with the
139   /// parent container.
140   void recordObjCMethods(ObjCContainerRecord *Container,
141                          const ObjCContainerDecl::method_range Methods);
142 
143   void recordObjCProperties(ObjCContainerRecord *Container,
144                             const ObjCContainerDecl::prop_range Properties);
145 
146   void recordObjCInstanceVariables(
147       ObjCContainerRecord *Container,
148       const llvm::iterator_range<
149           DeclContext::specific_decl_iterator<ObjCIvarDecl>>
150           Ivars);
151 
152   void recordObjCProtocols(ObjCContainerRecord *Container,
153                            ObjCInterfaceDecl::protocol_range Protocols);
154 
155   ASTContext &Context;
156   APISet &API;
157 
getTypedefName(const TagDecl * Decl)158   StringRef getTypedefName(const TagDecl *Decl) {
159     if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl())
160       return TypedefDecl->getName();
161 
162     return {};
163   }
164 
isInSystemHeader(const Decl * D)165   bool isInSystemHeader(const Decl *D) {
166     return Context.getSourceManager().isInSystemHeader(D->getLocation());
167   }
168 
169 private:
getDerivedExtractAPIVisitor()170   Derived &getDerivedExtractAPIVisitor() {
171     return *static_cast<Derived *>(this);
172   }
173 
174 protected:
getBases(const CXXRecordDecl * Decl)175   SmallVector<SymbolReference> getBases(const CXXRecordDecl *Decl) {
176     if (!Decl->isCompleteDefinition()) {
177       return {};
178     }
179 
180     // FIXME: store AccessSpecifier given by inheritance
181     SmallVector<SymbolReference> Bases;
182     for (const auto &BaseSpecifier : Decl->bases()) {
183       // skip classes not inherited as public
184       if (BaseSpecifier.getAccessSpecifier() != AccessSpecifier::AS_public)
185         continue;
186       if (auto *BaseDecl = BaseSpecifier.getType()->getAsTagDecl()) {
187         Bases.emplace_back(createSymbolReferenceForDecl(*BaseDecl));
188       } else {
189         SymbolReference BaseClass;
190         BaseClass.Name = API.copyString(BaseSpecifier.getType().getAsString(
191             Decl->getASTContext().getPrintingPolicy()));
192 
193         if (BaseSpecifier.getType().getTypePtr()->isTemplateTypeParmType()) {
194           if (auto *TTPTD = BaseSpecifier.getType()
195                                 ->getAs<TemplateTypeParmType>()
196                                 ->getDecl()) {
197             SmallString<128> USR;
198             index::generateUSRForDecl(TTPTD, USR);
199             BaseClass.USR = API.copyString(USR);
200             BaseClass.Source = API.copyString(getOwningModuleName(*TTPTD));
201           }
202         }
203         Bases.emplace_back(BaseClass);
204       }
205     }
206     return Bases;
207   }
208 
getKindForDisplay(const CXXRecordDecl * Decl)209   APIRecord::RecordKind getKindForDisplay(const CXXRecordDecl *Decl) {
210     if (Decl->isUnion())
211       return APIRecord::RK_Union;
212     if (Decl->isStruct())
213       return APIRecord::RK_Struct;
214 
215     return APIRecord::RK_CXXClass;
216   }
217 
getOwningModuleName(const Decl & D)218   StringRef getOwningModuleName(const Decl &D) {
219     if (auto *OwningModule = D.getImportedOwningModule())
220       return OwningModule->getTopLevelModule()->Name;
221 
222     return {};
223   }
224 
createHierarchyInformationForDecl(const Decl & D)225   SymbolReference createHierarchyInformationForDecl(const Decl &D) {
226     const auto *Context = cast_if_present<Decl>(D.getDeclContext());
227 
228     if (!Context || isa<TranslationUnitDecl>(Context))
229       return {};
230 
231     return createSymbolReferenceForDecl(*Context);
232   }
233 
createSymbolReferenceForDecl(const Decl & D)234   SymbolReference createSymbolReferenceForDecl(const Decl &D) {
235     SmallString<128> USR;
236     index::generateUSRForDecl(&D, USR);
237 
238     APIRecord *Record = API.findRecordForUSR(USR);
239     if (Record)
240       return SymbolReference(Record);
241 
242     StringRef Name;
243     if (auto *ND = dyn_cast<NamedDecl>(&D))
244       Name = ND->getName();
245 
246     return API.createSymbolReference(Name, USR, getOwningModuleName(D));
247   }
248 
isEmbeddedInVarDeclarator(const TagDecl & D)249   bool isEmbeddedInVarDeclarator(const TagDecl &D) {
250     return D.getName().empty() && getTypedefName(&D).empty() &&
251            D.isEmbeddedInDeclarator() && !D.isFreeStanding();
252   }
253 
maybeMergeWithAnonymousTag(const DeclaratorDecl & D,RecordContext * NewRecordContext)254   void maybeMergeWithAnonymousTag(const DeclaratorDecl &D,
255                                   RecordContext *NewRecordContext) {
256     if (!NewRecordContext)
257       return;
258     auto *Tag = D.getType()->getAsTagDecl();
259     if (!Tag) {
260       if (const auto *AT = D.getASTContext().getAsArrayType(D.getType())) {
261         Tag = AT->getElementType()->getAsTagDecl();
262       }
263     }
264     SmallString<128> TagUSR;
265     clang::index::generateUSRForDecl(Tag, TagUSR);
266     if (auto *Record = llvm::dyn_cast_if_present<TagRecord>(
267             API.findRecordForUSR(TagUSR))) {
268       if (Record->IsEmbeddedInVarDeclarator) {
269         NewRecordContext->stealRecordChain(*Record);
270         API.removeRecord(Record);
271       }
272     }
273   }
274 };
275 
276 template <typename Derived>
VisitVarDecl(const VarDecl * Decl)277 bool ExtractAPIVisitorBase<Derived>::VisitVarDecl(const VarDecl *Decl) {
278   // skip function parameters.
279   if (isa<ParmVarDecl>(Decl))
280     return true;
281 
282   // Skip non-global variables in records (struct/union/class) but not static
283   // members.
284   if (Decl->getDeclContext()->isRecord() && !Decl->isStaticDataMember())
285     return true;
286 
287   // Skip local variables inside function or method.
288   if (!Decl->isDefinedOutsideFunctionOrMethod())
289     return true;
290 
291   // If this is a template but not specialization or instantiation, skip.
292   if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
293       Decl->getTemplateSpecializationKind() == TSK_Undeclared)
294     return true;
295 
296   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
297     return true;
298 
299   // Collect symbol information.
300   StringRef Name = Decl->getName();
301   SmallString<128> USR;
302   index::generateUSRForDecl(Decl, USR);
303   PresumedLoc Loc =
304       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
305   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
306   DocComment Comment;
307   if (auto *RawComment =
308           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
309     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
310                                             Context.getDiagnostics());
311 
312   // Build declaration fragments and sub-heading for the variable.
313   DeclarationFragments Declaration =
314       DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
315   DeclarationFragments SubHeading =
316       DeclarationFragmentsBuilder::getSubHeading(Decl);
317   if (Decl->isStaticDataMember()) {
318     auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
319     API.createRecord<StaticFieldRecord>(
320         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
321         AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
322         SubHeading, Access, isInSystemHeader(Decl));
323   } else {
324     // Add the global variable record to the API set.
325     auto *NewRecord = API.createRecord<GlobalVariableRecord>(
326         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
327         AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
328         SubHeading, isInSystemHeader(Decl));
329 
330     // If this global variable has a non typedef'd anonymous tag type let's
331     // pretend the type's child records are under us in the hierarchy.
332     maybeMergeWithAnonymousTag(*Decl, NewRecord);
333   }
334 
335   return true;
336 }
337 
338 template <typename Derived>
VisitFunctionDecl(const FunctionDecl * Decl)339 bool ExtractAPIVisitorBase<Derived>::VisitFunctionDecl(
340     const FunctionDecl *Decl) {
341   if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
342     // Skip member function in class templates.
343     if (Method->getParent()->getDescribedClassTemplate() != nullptr)
344       return true;
345 
346     // Skip methods in records.
347     for (const auto &P : Context.getParents(*Method)) {
348       if (P.template get<CXXRecordDecl>())
349         return true;
350     }
351 
352     // Skip ConstructorDecl and DestructorDecl.
353     if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
354       return true;
355   }
356 
357   // Skip templated functions that aren't processed here.
358   switch (Decl->getTemplatedKind()) {
359   case FunctionDecl::TK_NonTemplate:
360   case FunctionDecl::TK_DependentNonTemplate:
361   case FunctionDecl::TK_FunctionTemplateSpecialization:
362     break;
363   case FunctionDecl::TK_FunctionTemplate:
364   case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
365   case FunctionDecl::TK_MemberSpecialization:
366     return true;
367   }
368 
369   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
370     return true;
371 
372   // Collect symbol information.
373   auto Name = Decl->getNameAsString();
374   SmallString<128> USR;
375   index::generateUSRForDecl(Decl, USR);
376   PresumedLoc Loc =
377       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
378   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
379   DocComment Comment;
380   if (auto *RawComment =
381           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
382     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
383                                             Context.getDiagnostics());
384 
385   // Build declaration fragments, sub-heading, and signature of the function.
386   DeclarationFragments SubHeading =
387       DeclarationFragmentsBuilder::getSubHeading(Decl);
388   FunctionSignature Signature =
389       DeclarationFragmentsBuilder::getFunctionSignature(Decl);
390   if (Decl->getTemplateSpecializationInfo())
391     API.createRecord<GlobalFunctionTemplateSpecializationRecord>(
392         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
393         AvailabilityInfo::createFromDecl(Decl), Linkage, Comment,
394         DeclarationFragmentsBuilder::
395             getFragmentsForFunctionTemplateSpecialization(Decl),
396         SubHeading, Signature, isInSystemHeader(Decl));
397   else
398     // Add the function record to the API set.
399     API.createRecord<GlobalFunctionRecord>(
400         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
401         AvailabilityInfo::createFromDecl(Decl), Linkage, Comment,
402         DeclarationFragmentsBuilder::getFragmentsForFunction(Decl), SubHeading,
403         Signature, isInSystemHeader(Decl));
404   return true;
405 }
406 
407 template <typename Derived>
VisitEnumDecl(const EnumDecl * Decl)408 bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
409   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
410     return true;
411 
412   SmallString<128> USR;
413   index::generateUSRForDecl(Decl, USR);
414   PresumedLoc Loc =
415       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
416   DocComment Comment;
417   if (auto *RawComment =
418           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
419     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
420                                             Context.getDiagnostics());
421 
422   // Build declaration fragments and sub-heading for the enum.
423   DeclarationFragments Declaration =
424       DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
425   DeclarationFragments SubHeading =
426       DeclarationFragmentsBuilder::getSubHeading(Decl);
427 
428   // Collect symbol information.
429   SymbolReference ParentContainer;
430 
431   if (Decl->hasNameForLinkage()) {
432     StringRef Name = Decl->getName();
433     if (Name.empty())
434       Name = getTypedefName(Decl);
435 
436     auto *ER = API.createRecord<EnumRecord>(
437         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
438         AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
439         SubHeading, isInSystemHeader(Decl), false);
440     ParentContainer = SymbolReference(ER);
441   } else {
442     // If this an anonymous enum then the parent scope of the constants is the
443     // top level namespace.
444     ParentContainer = {};
445   }
446 
447   // Now collect information about the enumerators in this enum.
448   getDerivedExtractAPIVisitor().recordEnumConstants(ParentContainer,
449                                                     Decl->enumerators());
450 
451   return true;
452 }
453 
454 template <typename Derived>
WalkUpFromFunctionDecl(const FunctionDecl * Decl)455 bool ExtractAPIVisitorBase<Derived>::WalkUpFromFunctionDecl(
456     const FunctionDecl *Decl) {
457   getDerivedExtractAPIVisitor().VisitFunctionDecl(Decl);
458   return true;
459 }
460 
461 template <typename Derived>
WalkUpFromRecordDecl(const RecordDecl * Decl)462 bool ExtractAPIVisitorBase<Derived>::WalkUpFromRecordDecl(
463     const RecordDecl *Decl) {
464   getDerivedExtractAPIVisitor().VisitRecordDecl(Decl);
465   return true;
466 }
467 
468 template <typename Derived>
WalkUpFromCXXRecordDecl(const CXXRecordDecl * Decl)469 bool ExtractAPIVisitorBase<Derived>::WalkUpFromCXXRecordDecl(
470     const CXXRecordDecl *Decl) {
471   getDerivedExtractAPIVisitor().VisitCXXRecordDecl(Decl);
472   return true;
473 }
474 
475 template <typename Derived>
WalkUpFromCXXMethodDecl(const CXXMethodDecl * Decl)476 bool ExtractAPIVisitorBase<Derived>::WalkUpFromCXXMethodDecl(
477     const CXXMethodDecl *Decl) {
478   getDerivedExtractAPIVisitor().VisitCXXMethodDecl(Decl);
479   return true;
480 }
481 
482 template <typename Derived>
WalkUpFromClassTemplateSpecializationDecl(const ClassTemplateSpecializationDecl * Decl)483 bool ExtractAPIVisitorBase<Derived>::WalkUpFromClassTemplateSpecializationDecl(
484     const ClassTemplateSpecializationDecl *Decl) {
485   getDerivedExtractAPIVisitor().VisitClassTemplateSpecializationDecl(Decl);
486   return true;
487 }
488 
489 template <typename Derived>
490 bool ExtractAPIVisitorBase<Derived>::
WalkUpFromClassTemplatePartialSpecializationDecl(const ClassTemplatePartialSpecializationDecl * Decl)491     WalkUpFromClassTemplatePartialSpecializationDecl(
492         const ClassTemplatePartialSpecializationDecl *Decl) {
493   getDerivedExtractAPIVisitor().VisitClassTemplatePartialSpecializationDecl(
494       Decl);
495   return true;
496 }
497 
498 template <typename Derived>
WalkUpFromVarTemplateDecl(const VarTemplateDecl * Decl)499 bool ExtractAPIVisitorBase<Derived>::WalkUpFromVarTemplateDecl(
500     const VarTemplateDecl *Decl) {
501   getDerivedExtractAPIVisitor().VisitVarTemplateDecl(Decl);
502   return true;
503 }
504 
505 template <typename Derived>
WalkUpFromVarTemplateSpecializationDecl(const VarTemplateSpecializationDecl * Decl)506 bool ExtractAPIVisitorBase<Derived>::WalkUpFromVarTemplateSpecializationDecl(
507     const VarTemplateSpecializationDecl *Decl) {
508   getDerivedExtractAPIVisitor().VisitVarTemplateSpecializationDecl(Decl);
509   return true;
510 }
511 
512 template <typename Derived>
513 bool ExtractAPIVisitorBase<Derived>::
WalkUpFromVarTemplatePartialSpecializationDecl(const VarTemplatePartialSpecializationDecl * Decl)514     WalkUpFromVarTemplatePartialSpecializationDecl(
515         const VarTemplatePartialSpecializationDecl *Decl) {
516   getDerivedExtractAPIVisitor().VisitVarTemplatePartialSpecializationDecl(Decl);
517   return true;
518 }
519 
520 template <typename Derived>
WalkUpFromFunctionTemplateDecl(const FunctionTemplateDecl * Decl)521 bool ExtractAPIVisitorBase<Derived>::WalkUpFromFunctionTemplateDecl(
522     const FunctionTemplateDecl *Decl) {
523   getDerivedExtractAPIVisitor().VisitFunctionTemplateDecl(Decl);
524   return true;
525 }
526 
527 template <typename Derived>
WalkUpFromNamespaceDecl(const NamespaceDecl * Decl)528 bool ExtractAPIVisitorBase<Derived>::WalkUpFromNamespaceDecl(
529     const NamespaceDecl *Decl) {
530   getDerivedExtractAPIVisitor().VisitNamespaceDecl(Decl);
531   return true;
532 }
533 
534 template <typename Derived>
VisitNamespaceDecl(const NamespaceDecl * Decl)535 bool ExtractAPIVisitorBase<Derived>::VisitNamespaceDecl(
536     const NamespaceDecl *Decl) {
537   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
538     return true;
539   if (Decl->isAnonymousNamespace())
540     return true;
541   StringRef Name = Decl->getName();
542   SmallString<128> USR;
543   index::generateUSRForDecl(Decl, USR);
544   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
545   PresumedLoc Loc =
546       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
547   DocComment Comment;
548   if (auto *RawComment =
549           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
550     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
551                                             Context.getDiagnostics());
552 
553   // Build declaration fragments and sub-heading for the struct.
554   DeclarationFragments Declaration =
555       DeclarationFragmentsBuilder::getFragmentsForNamespace(Decl);
556   DeclarationFragments SubHeading =
557       DeclarationFragmentsBuilder::getSubHeading(Decl);
558   API.createRecord<NamespaceRecord>(
559       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
560       AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
561       SubHeading, isInSystemHeader(Decl));
562 
563   return true;
564 }
565 
566 template <typename Derived>
TraverseRecordDecl(RecordDecl * Decl)567 bool ExtractAPIVisitorBase<Derived>::TraverseRecordDecl(RecordDecl *Decl) {
568   bool Ret = Base::TraverseRecordDecl(Decl);
569 
570   if (!isEmbeddedInVarDeclarator(*Decl) && Decl->isAnonymousStructOrUnion()) {
571     SmallString<128> USR;
572     index::generateUSRForDecl(Decl, USR);
573     API.removeRecord(USR);
574   }
575 
576   return Ret;
577 }
578 
579 template <typename Derived>
VisitRecordDecl(const RecordDecl * Decl)580 bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) {
581   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
582     return true;
583 
584   // Collect symbol information.
585   StringRef Name = Decl->getName();
586   if (Name.empty())
587     Name = getTypedefName(Decl);
588 
589   SmallString<128> USR;
590   index::generateUSRForDecl(Decl, USR);
591   PresumedLoc Loc =
592       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
593   DocComment Comment;
594   if (auto *RawComment =
595           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
596     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
597                                             Context.getDiagnostics());
598 
599   // Build declaration fragments and sub-heading for the struct.
600   DeclarationFragments Declaration =
601       DeclarationFragmentsBuilder::getFragmentsForRecordDecl(Decl);
602   DeclarationFragments SubHeading =
603       DeclarationFragmentsBuilder::getSubHeading(Decl);
604 
605   if (Decl->isUnion())
606     API.createRecord<UnionRecord>(
607         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
608         AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
609         SubHeading, isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl));
610   else
611     API.createRecord<StructRecord>(
612         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
613         AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
614         SubHeading, isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl));
615 
616   return true;
617 }
618 
619 template <typename Derived>
TraverseCXXRecordDecl(CXXRecordDecl * Decl)620 bool ExtractAPIVisitorBase<Derived>::TraverseCXXRecordDecl(
621     CXXRecordDecl *Decl) {
622   bool Ret = Base::TraverseCXXRecordDecl(Decl);
623 
624   if (!isEmbeddedInVarDeclarator(*Decl) && Decl->isAnonymousStructOrUnion()) {
625     SmallString<128> USR;
626     index::generateUSRForDecl(Decl, USR);
627     API.removeRecord(USR);
628   }
629 
630   return Ret;
631 }
632 
633 template <typename Derived>
VisitCXXRecordDecl(const CXXRecordDecl * Decl)634 bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
635     const CXXRecordDecl *Decl) {
636   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) ||
637       Decl->isImplicit())
638     return true;
639 
640   StringRef Name = Decl->getName();
641   if (Name.empty())
642     Name = getTypedefName(Decl);
643 
644   SmallString<128> USR;
645   index::generateUSRForDecl(Decl, USR);
646   PresumedLoc Loc =
647       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
648   DocComment Comment;
649   if (auto *RawComment =
650           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
651     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
652                                             Context.getDiagnostics());
653   DeclarationFragments Declaration =
654       DeclarationFragmentsBuilder::getFragmentsForCXXClass(Decl);
655   DeclarationFragments SubHeading =
656       DeclarationFragmentsBuilder::getSubHeading(Decl);
657 
658   auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
659 
660   CXXClassRecord *Record;
661   if (Decl->getDescribedClassTemplate()) {
662     // Inject template fragments before class fragments.
663     Declaration.prepend(
664         DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(
665             Decl->getDescribedClassTemplate()));
666     Record = API.createRecord<ClassTemplateRecord>(
667         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
668         AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
669         SubHeading, Template(Decl->getDescribedClassTemplate()), Access,
670         isInSystemHeader(Decl));
671   } else {
672     Record = API.createRecord<CXXClassRecord>(
673         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
674         AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
675         SubHeading, APIRecord::RecordKind::RK_CXXClass, Access,
676         isInSystemHeader(Decl), isEmbeddedInVarDeclarator(*Decl));
677   }
678 
679   Record->KindForDisplay = getKindForDisplay(Decl);
680   Record->Bases = getBases(Decl);
681 
682   return true;
683 }
684 
685 template <typename Derived>
VisitCXXMethodDecl(const CXXMethodDecl * Decl)686 bool ExtractAPIVisitorBase<Derived>::VisitCXXMethodDecl(
687     const CXXMethodDecl *Decl) {
688   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) ||
689       Decl->isImplicit())
690     return true;
691 
692   if (isa<CXXConversionDecl>(Decl))
693     return true;
694   if (isa<CXXConstructorDecl>(Decl) || isa<CXXDestructorDecl>(Decl))
695     return true;
696 
697   SmallString<128> USR;
698   index::generateUSRForDecl(Decl, USR);
699   PresumedLoc Loc =
700       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
701   DocComment Comment;
702   if (auto *RawComment =
703           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
704     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
705                                             Context.getDiagnostics());
706   DeclarationFragments SubHeading =
707       DeclarationFragmentsBuilder::getSubHeading(Decl);
708   auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
709   auto Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl);
710 
711   if (FunctionTemplateDecl *TemplateDecl =
712           Decl->getDescribedFunctionTemplate()) {
713     API.createRecord<CXXMethodTemplateRecord>(
714         USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
715         Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
716         DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(
717             TemplateDecl),
718         SubHeading, DeclarationFragmentsBuilder::getFunctionSignature(Decl),
719         DeclarationFragmentsBuilder::getAccessControl(TemplateDecl),
720         Template(TemplateDecl), isInSystemHeader(Decl));
721   } else if (Decl->getTemplateSpecializationInfo())
722     API.createRecord<CXXMethodTemplateSpecializationRecord>(
723         USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
724         Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
725         DeclarationFragmentsBuilder::
726             getFragmentsForFunctionTemplateSpecialization(Decl),
727         SubHeading, Signature, Access, isInSystemHeader(Decl));
728   else if (Decl->isOverloadedOperator())
729     API.createRecord<CXXInstanceMethodRecord>(
730         USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
731         Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
732         DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator(Decl),
733         SubHeading, Signature, Access, isInSystemHeader(Decl));
734   else if (Decl->isStatic())
735     API.createRecord<CXXStaticMethodRecord>(
736         USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
737         Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
738         DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading,
739         Signature, Access, isInSystemHeader(Decl));
740   else
741     API.createRecord<CXXInstanceMethodRecord>(
742         USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl),
743         Loc, AvailabilityInfo::createFromDecl(Decl), Comment,
744         DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading,
745         Signature, Access, isInSystemHeader(Decl));
746 
747   return true;
748 }
749 
750 template <typename Derived>
VisitCXXConstructorDecl(const CXXConstructorDecl * Decl)751 bool ExtractAPIVisitorBase<Derived>::VisitCXXConstructorDecl(
752     const CXXConstructorDecl *Decl) {
753   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) ||
754       Decl->isImplicit())
755     return true;
756 
757   auto Name = Decl->getNameAsString();
758   SmallString<128> USR;
759   index::generateUSRForDecl(Decl, USR);
760   PresumedLoc Loc =
761       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
762   DocComment Comment;
763   if (auto *RawComment =
764           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
765     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
766                                             Context.getDiagnostics());
767 
768   // Build declaration fragments, sub-heading, and signature for the method.
769   DeclarationFragments Declaration =
770       DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod(Decl);
771   DeclarationFragments SubHeading =
772       DeclarationFragmentsBuilder::getSubHeading(Decl);
773   FunctionSignature Signature =
774       DeclarationFragmentsBuilder::getFunctionSignature(Decl);
775   AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
776 
777   API.createRecord<CXXConstructorRecord>(
778       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
779       AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
780       Signature, Access, isInSystemHeader(Decl));
781   return true;
782 }
783 
784 template <typename Derived>
VisitCXXDestructorDecl(const CXXDestructorDecl * Decl)785 bool ExtractAPIVisitorBase<Derived>::VisitCXXDestructorDecl(
786     const CXXDestructorDecl *Decl) {
787   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) ||
788       Decl->isImplicit())
789     return true;
790 
791   auto Name = Decl->getNameAsString();
792   SmallString<128> USR;
793   index::generateUSRForDecl(Decl, USR);
794   PresumedLoc Loc =
795       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
796   DocComment Comment;
797   if (auto *RawComment =
798           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
799     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
800                                             Context.getDiagnostics());
801 
802   // Build declaration fragments, sub-heading, and signature for the method.
803   DeclarationFragments Declaration =
804       DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod(Decl);
805   DeclarationFragments SubHeading =
806       DeclarationFragmentsBuilder::getSubHeading(Decl);
807   FunctionSignature Signature =
808       DeclarationFragmentsBuilder::getFunctionSignature(Decl);
809   AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
810   API.createRecord<CXXDestructorRecord>(
811       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
812       AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
813       Signature, Access, isInSystemHeader(Decl));
814   return true;
815 }
816 
817 template <typename Derived>
VisitConceptDecl(const ConceptDecl * Decl)818 bool ExtractAPIVisitorBase<Derived>::VisitConceptDecl(const ConceptDecl *Decl) {
819   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
820     return true;
821 
822   StringRef Name = Decl->getName();
823   SmallString<128> USR;
824   index::generateUSRForDecl(Decl, USR);
825   PresumedLoc Loc =
826       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
827   DocComment Comment;
828   if (auto *RawComment =
829           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
830     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
831                                             Context.getDiagnostics());
832   DeclarationFragments Declaration =
833       DeclarationFragmentsBuilder::getFragmentsForConcept(Decl);
834   DeclarationFragments SubHeading =
835       DeclarationFragmentsBuilder::getSubHeading(Decl);
836   API.createRecord<ConceptRecord>(
837       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
838       AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
839       Template(Decl), isInSystemHeader(Decl));
840   return true;
841 }
842 
843 template <typename Derived>
VisitClassTemplateSpecializationDecl(const ClassTemplateSpecializationDecl * Decl)844 bool ExtractAPIVisitorBase<Derived>::VisitClassTemplateSpecializationDecl(
845     const ClassTemplateSpecializationDecl *Decl) {
846   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
847     return true;
848 
849   StringRef Name = Decl->getName();
850   SmallString<128> USR;
851   index::generateUSRForDecl(Decl, USR);
852   PresumedLoc Loc =
853       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
854   DocComment Comment;
855   if (auto *RawComment =
856           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
857     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
858                                             Context.getDiagnostics());
859   DeclarationFragments Declaration =
860       DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization(
861           Decl);
862   DeclarationFragments SubHeading =
863       DeclarationFragmentsBuilder::getSubHeading(Decl);
864 
865   auto *CTSR = API.createRecord<ClassTemplateSpecializationRecord>(
866       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
867       AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
868       DeclarationFragmentsBuilder::getAccessControl(Decl),
869       isInSystemHeader(Decl));
870 
871   CTSR->Bases = getBases(Decl);
872 
873   return true;
874 }
875 
876 template <typename Derived>
877 bool ExtractAPIVisitorBase<Derived>::
VisitClassTemplatePartialSpecializationDecl(const ClassTemplatePartialSpecializationDecl * Decl)878     VisitClassTemplatePartialSpecializationDecl(
879         const ClassTemplatePartialSpecializationDecl *Decl) {
880   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
881     return true;
882 
883   StringRef Name = Decl->getName();
884   SmallString<128> USR;
885   index::generateUSRForDecl(Decl, USR);
886   PresumedLoc Loc =
887       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
888   DocComment Comment;
889   if (auto *RawComment =
890           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
891     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
892                                             Context.getDiagnostics());
893   DeclarationFragments Declaration = DeclarationFragmentsBuilder::
894       getFragmentsForClassTemplatePartialSpecialization(Decl);
895   DeclarationFragments SubHeading =
896       DeclarationFragmentsBuilder::getSubHeading(Decl);
897   auto *CTPSR = API.createRecord<ClassTemplatePartialSpecializationRecord>(
898       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
899       AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
900       Template(Decl), DeclarationFragmentsBuilder::getAccessControl(Decl),
901       isInSystemHeader(Decl));
902 
903   CTPSR->KindForDisplay = getKindForDisplay(Decl);
904   CTPSR->Bases = getBases(Decl);
905 
906   return true;
907 }
908 
909 template <typename Derived>
VisitVarTemplateDecl(const VarTemplateDecl * Decl)910 bool ExtractAPIVisitorBase<Derived>::VisitVarTemplateDecl(
911     const VarTemplateDecl *Decl) {
912   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
913     return true;
914 
915   // Collect symbol information.
916   StringRef Name = Decl->getName();
917   SmallString<128> USR;
918   index::generateUSRForDecl(Decl, USR);
919   PresumedLoc Loc =
920       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
921   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
922   DocComment Comment;
923   if (auto *RawComment =
924           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
925     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
926                                             Context.getDiagnostics());
927 
928   // Build declaration fragments and sub-heading for the variable.
929   DeclarationFragments Declaration;
930   Declaration
931       .append(DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate(
932           Decl))
933       .append(DeclarationFragmentsBuilder::getFragmentsForVarTemplate(
934           Decl->getTemplatedDecl()));
935   // Inject template fragments before var fragments.
936   DeclarationFragments SubHeading =
937       DeclarationFragmentsBuilder::getSubHeading(Decl);
938 
939   if (Decl->getDeclContext()->getDeclKind() == Decl::CXXRecord)
940     API.createRecord<CXXFieldTemplateRecord>(
941         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
942         AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
943         SubHeading, DeclarationFragmentsBuilder::getAccessControl(Decl),
944         Template(Decl), isInSystemHeader(Decl));
945   else
946     API.createRecord<GlobalVariableTemplateRecord>(
947         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
948         AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
949         SubHeading, Template(Decl), isInSystemHeader(Decl));
950   return true;
951 }
952 
953 template <typename Derived>
VisitVarTemplateSpecializationDecl(const VarTemplateSpecializationDecl * Decl)954 bool ExtractAPIVisitorBase<Derived>::VisitVarTemplateSpecializationDecl(
955     const VarTemplateSpecializationDecl *Decl) {
956   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
957     return true;
958 
959   // Collect symbol information.
960   StringRef Name = Decl->getName();
961   SmallString<128> USR;
962   index::generateUSRForDecl(Decl, USR);
963   PresumedLoc Loc =
964       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
965   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
966   DocComment Comment;
967   if (auto *RawComment =
968           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
969     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
970                                             Context.getDiagnostics());
971 
972   // Build declaration fragments and sub-heading for the variable.
973   DeclarationFragments Declaration =
974       DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization(
975           Decl);
976   DeclarationFragments SubHeading =
977       DeclarationFragmentsBuilder::getSubHeading(Decl);
978   API.createRecord<GlobalVariableTemplateSpecializationRecord>(
979       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
980       AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
981       SubHeading, isInSystemHeader(Decl));
982   return true;
983 }
984 
985 template <typename Derived>
VisitVarTemplatePartialSpecializationDecl(const VarTemplatePartialSpecializationDecl * Decl)986 bool ExtractAPIVisitorBase<Derived>::VisitVarTemplatePartialSpecializationDecl(
987     const VarTemplatePartialSpecializationDecl *Decl) {
988   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
989     return true;
990 
991   // Collect symbol information.
992   StringRef Name = Decl->getName();
993   SmallString<128> USR;
994   index::generateUSRForDecl(Decl, USR);
995   PresumedLoc Loc =
996       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
997   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
998   DocComment Comment;
999   if (auto *RawComment =
1000           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
1001     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1002                                             Context.getDiagnostics());
1003 
1004   // Build declaration fragments and sub-heading for the variable.
1005   DeclarationFragments Declaration = DeclarationFragmentsBuilder::
1006       getFragmentsForVarTemplatePartialSpecialization(Decl);
1007   DeclarationFragments SubHeading =
1008       DeclarationFragmentsBuilder::getSubHeading(Decl);
1009   API.createRecord<GlobalVariableTemplatePartialSpecializationRecord>(
1010       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
1011       AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
1012       SubHeading, Template(Decl), isInSystemHeader(Decl));
1013   return true;
1014 }
1015 
1016 template <typename Derived>
VisitFunctionTemplateDecl(const FunctionTemplateDecl * Decl)1017 bool ExtractAPIVisitorBase<Derived>::VisitFunctionTemplateDecl(
1018     const FunctionTemplateDecl *Decl) {
1019   if (isa<CXXMethodDecl>(Decl->getTemplatedDecl()))
1020     return true;
1021   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
1022     return true;
1023 
1024   // Collect symbol information.
1025   auto Name = Decl->getNameAsString();
1026   SmallString<128> USR;
1027   index::generateUSRForDecl(Decl, USR);
1028   PresumedLoc Loc =
1029       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
1030   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
1031   DocComment Comment;
1032   if (auto *RawComment =
1033           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
1034     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1035                                             Context.getDiagnostics());
1036 
1037   DeclarationFragments SubHeading =
1038       DeclarationFragmentsBuilder::getSubHeading(Decl);
1039   FunctionSignature Signature =
1040       DeclarationFragmentsBuilder::getFunctionSignature(
1041           Decl->getTemplatedDecl());
1042   API.createRecord<GlobalFunctionTemplateRecord>(
1043       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
1044       AvailabilityInfo::createFromDecl(Decl), Linkage, Comment,
1045       DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(Decl),
1046       SubHeading, Signature, Template(Decl), isInSystemHeader(Decl));
1047 
1048   return true;
1049 }
1050 
1051 template <typename Derived>
VisitObjCInterfaceDecl(const ObjCInterfaceDecl * Decl)1052 bool ExtractAPIVisitorBase<Derived>::VisitObjCInterfaceDecl(
1053     const ObjCInterfaceDecl *Decl) {
1054   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
1055     return true;
1056 
1057   // Collect symbol information.
1058   StringRef Name = Decl->getName();
1059   SmallString<128> USR;
1060   index::generateUSRForDecl(Decl, USR);
1061   PresumedLoc Loc =
1062       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
1063   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
1064   DocComment Comment;
1065   if (auto *RawComment =
1066           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
1067     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1068                                             Context.getDiagnostics());
1069 
1070   // Build declaration fragments and sub-heading for the interface.
1071   DeclarationFragments Declaration =
1072       DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
1073   DeclarationFragments SubHeading =
1074       DeclarationFragmentsBuilder::getSubHeading(Decl);
1075 
1076   // Collect super class information.
1077   SymbolReference SuperClass;
1078   if (const auto *SuperClassDecl = Decl->getSuperClass())
1079     SuperClass = createSymbolReferenceForDecl(*SuperClassDecl);
1080 
1081   auto *InterfaceRecord = API.createRecord<ObjCInterfaceRecord>(
1082       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
1083       AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration,
1084       SubHeading, SuperClass, isInSystemHeader(Decl));
1085 
1086   // Record all methods (selectors). This doesn't include automatically
1087   // synthesized property methods.
1088   getDerivedExtractAPIVisitor().recordObjCMethods(InterfaceRecord,
1089                                                   Decl->methods());
1090   getDerivedExtractAPIVisitor().recordObjCProperties(InterfaceRecord,
1091                                                      Decl->properties());
1092   getDerivedExtractAPIVisitor().recordObjCInstanceVariables(InterfaceRecord,
1093                                                             Decl->ivars());
1094   getDerivedExtractAPIVisitor().recordObjCProtocols(InterfaceRecord,
1095                                                     Decl->protocols());
1096 
1097   return true;
1098 }
1099 
1100 template <typename Derived>
VisitObjCProtocolDecl(const ObjCProtocolDecl * Decl)1101 bool ExtractAPIVisitorBase<Derived>::VisitObjCProtocolDecl(
1102     const ObjCProtocolDecl *Decl) {
1103   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
1104     return true;
1105 
1106   // Collect symbol information.
1107   StringRef Name = Decl->getName();
1108   SmallString<128> USR;
1109   index::generateUSRForDecl(Decl, USR);
1110   PresumedLoc Loc =
1111       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
1112   DocComment Comment;
1113   if (auto *RawComment =
1114           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
1115     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1116                                             Context.getDiagnostics());
1117 
1118   // Build declaration fragments and sub-heading for the protocol.
1119   DeclarationFragments Declaration =
1120       DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
1121   DeclarationFragments SubHeading =
1122       DeclarationFragmentsBuilder::getSubHeading(Decl);
1123 
1124   auto *ProtoRecord = API.createRecord<ObjCProtocolRecord>(
1125       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
1126       AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
1127       isInSystemHeader(Decl));
1128 
1129   getDerivedExtractAPIVisitor().recordObjCMethods(ProtoRecord, Decl->methods());
1130   getDerivedExtractAPIVisitor().recordObjCProperties(ProtoRecord,
1131                                                      Decl->properties());
1132   getDerivedExtractAPIVisitor().recordObjCProtocols(ProtoRecord,
1133                                                     Decl->protocols());
1134 
1135   return true;
1136 }
1137 
1138 template <typename Derived>
VisitTypedefNameDecl(const TypedefNameDecl * Decl)1139 bool ExtractAPIVisitorBase<Derived>::VisitTypedefNameDecl(
1140     const TypedefNameDecl *Decl) {
1141   // Skip ObjC Type Parameter for now.
1142   if (isa<ObjCTypeParamDecl>(Decl))
1143     return true;
1144 
1145   if (!Decl->isDefinedOutsideFunctionOrMethod())
1146     return true;
1147 
1148   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
1149     return true;
1150 
1151   StringRef Name = Decl->getName();
1152 
1153   auto nameMatches = [&Name](TagDecl *TagDecl) {
1154     StringRef TagName = TagDecl->getName();
1155 
1156     if (TagName == Name)
1157       return true;
1158 
1159     // Also check whether the tag decl's name is the same as the typedef name
1160     // with prefixed underscores
1161     if (TagName.starts_with('_')) {
1162       StringRef StrippedName = TagName.ltrim('_');
1163 
1164       if (StrippedName == Name)
1165         return true;
1166     }
1167 
1168     return false;
1169   };
1170 
1171   // If the underlying type was defined as part of the typedef modify it's
1172   // fragments directly and pretend the typedef doesn't exist.
1173   if (auto *TagDecl = Decl->getUnderlyingType()->getAsTagDecl()) {
1174     if (TagDecl->isEmbeddedInDeclarator() && TagDecl->isCompleteDefinition() &&
1175         nameMatches(TagDecl)) {
1176       SmallString<128> TagUSR;
1177       index::generateUSRForDecl(TagDecl, TagUSR);
1178       if (auto *Record = API.findRecordForUSR(TagUSR)) {
1179         DeclarationFragments LeadingFragments;
1180         LeadingFragments.append("typedef",
1181                                 DeclarationFragments::FragmentKind::Keyword);
1182         LeadingFragments.appendSpace();
1183         Record->Declaration.removeTrailingSemicolon()
1184             .prepend(std::move(LeadingFragments))
1185             .append(" { ... } ", DeclarationFragments::FragmentKind::Text)
1186             .append(Name, DeclarationFragments::FragmentKind::Identifier)
1187             .appendSemicolon();
1188 
1189         // Replace the name and subheading in case it's underscored so we can
1190         // use the non-underscored version
1191         Record->Name = Name;
1192         Record->SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl);
1193 
1194         return true;
1195       }
1196     }
1197   }
1198 
1199   PresumedLoc Loc =
1200       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
1201   SmallString<128> USR;
1202   index::generateUSRForDecl(Decl, USR);
1203   DocComment Comment;
1204   if (auto *RawComment =
1205           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
1206     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1207                                             Context.getDiagnostics());
1208 
1209   QualType Type = Decl->getUnderlyingType();
1210   SymbolReference SymRef =
1211       TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
1212                                                                        API);
1213 
1214   API.createRecord<TypedefRecord>(
1215       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
1216       AvailabilityInfo::createFromDecl(Decl), Comment,
1217       DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
1218       DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef,
1219       isInSystemHeader(Decl));
1220 
1221   return true;
1222 }
1223 
1224 template <typename Derived>
VisitObjCCategoryDecl(const ObjCCategoryDecl * Decl)1225 bool ExtractAPIVisitorBase<Derived>::VisitObjCCategoryDecl(
1226     const ObjCCategoryDecl *Decl) {
1227   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
1228     return true;
1229 
1230   StringRef Name = Decl->getName();
1231   SmallString<128> USR;
1232   index::generateUSRForDecl(Decl, USR);
1233   PresumedLoc Loc =
1234       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
1235   DocComment Comment;
1236   if (auto *RawComment =
1237           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
1238     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1239                                             Context.getDiagnostics());
1240   // Build declaration fragments and sub-heading for the category.
1241   DeclarationFragments Declaration =
1242       DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
1243   DeclarationFragments SubHeading =
1244       DeclarationFragmentsBuilder::getSubHeading(Decl);
1245 
1246   const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
1247   SymbolReference Interface = createSymbolReferenceForDecl(*InterfaceDecl);
1248 
1249   auto *CategoryRecord = API.createRecord<ObjCCategoryRecord>(
1250       USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
1251       AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading,
1252       Interface, isInSystemHeader(Decl));
1253 
1254   getDerivedExtractAPIVisitor().recordObjCMethods(CategoryRecord,
1255                                                   Decl->methods());
1256   getDerivedExtractAPIVisitor().recordObjCProperties(CategoryRecord,
1257                                                      Decl->properties());
1258   getDerivedExtractAPIVisitor().recordObjCInstanceVariables(CategoryRecord,
1259                                                             Decl->ivars());
1260   getDerivedExtractAPIVisitor().recordObjCProtocols(CategoryRecord,
1261                                                     Decl->protocols());
1262 
1263   return true;
1264 }
1265 
1266 /// Collect API information for the enum constants and associate with the
1267 /// parent enum.
1268 template <typename Derived>
recordEnumConstants(SymbolReference Container,const EnumDecl::enumerator_range Constants)1269 void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
1270     SymbolReference Container, const EnumDecl::enumerator_range Constants) {
1271   for (const auto *Constant : Constants) {
1272     // Collect symbol information.
1273     StringRef Name = Constant->getName();
1274     SmallString<128> USR;
1275     index::generateUSRForDecl(Constant, USR);
1276     PresumedLoc Loc =
1277         Context.getSourceManager().getPresumedLoc(Constant->getLocation());
1278     DocComment Comment;
1279     if (auto *RawComment =
1280             getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Constant))
1281       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1282                                               Context.getDiagnostics());
1283 
1284     // Build declaration fragments and sub-heading for the enum constant.
1285     DeclarationFragments Declaration =
1286         DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
1287     DeclarationFragments SubHeading =
1288         DeclarationFragmentsBuilder::getSubHeading(Constant);
1289 
1290     API.createRecord<EnumConstantRecord>(
1291         USR, Name, Container, Loc, AvailabilityInfo::createFromDecl(Constant),
1292         Comment, Declaration, SubHeading, isInSystemHeader(Constant));
1293   }
1294 }
1295 
1296 template <typename Derived>
VisitFieldDecl(const FieldDecl * Decl)1297 bool ExtractAPIVisitorBase<Derived>::VisitFieldDecl(const FieldDecl *Decl) {
1298   // ObjCIvars are handled separately
1299   if (isa<ObjCIvarDecl>(Decl) || isa<ObjCAtDefsFieldDecl>(Decl))
1300     return true;
1301 
1302   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
1303     return true;
1304 
1305   // Collect symbol information.
1306   StringRef Name = Decl->getName();
1307   SmallString<128> USR;
1308   index::generateUSRForDecl(Decl, USR);
1309   PresumedLoc Loc =
1310       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
1311   DocComment Comment;
1312   if (auto *RawComment =
1313           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
1314     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1315                                             Context.getDiagnostics());
1316 
1317   // Build declaration fragments and sub-heading for the struct field.
1318   DeclarationFragments Declaration =
1319       DeclarationFragmentsBuilder::getFragmentsForField(Decl);
1320   DeclarationFragments SubHeading =
1321       DeclarationFragmentsBuilder::getSubHeading(Decl);
1322 
1323   RecordContext *NewRecord = nullptr;
1324   if (isa<CXXRecordDecl>(Decl->getDeclContext())) {
1325     AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
1326 
1327     NewRecord = API.createRecord<CXXFieldRecord>(
1328         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
1329         AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
1330         SubHeading, Access, isInSystemHeader(Decl));
1331   } else if (auto *RD = dyn_cast<RecordDecl>(Decl->getDeclContext())) {
1332     if (RD->isUnion())
1333       NewRecord = API.createRecord<UnionFieldRecord>(
1334           USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
1335           AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
1336           SubHeading, isInSystemHeader(Decl));
1337     else
1338       NewRecord = API.createRecord<StructFieldRecord>(
1339           USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
1340           AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
1341           SubHeading, isInSystemHeader(Decl));
1342   }
1343 
1344   // If this field has a non typedef'd anonymous tag type let's pretend the
1345   // type's child records are under us in the hierarchy.
1346   maybeMergeWithAnonymousTag(*Decl, NewRecord);
1347 
1348   return true;
1349 }
1350 
1351 template <typename Derived>
VisitCXXConversionDecl(const CXXConversionDecl * Decl)1352 bool ExtractAPIVisitorBase<Derived>::VisitCXXConversionDecl(
1353     const CXXConversionDecl *Decl) {
1354   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) ||
1355       Decl->isImplicit())
1356     return true;
1357 
1358   auto Name = Decl->getNameAsString();
1359   SmallString<128> USR;
1360   index::generateUSRForDecl(Decl, USR);
1361   PresumedLoc Loc =
1362       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
1363   DocComment Comment;
1364   if (auto *RawComment =
1365           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
1366     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1367                                             Context.getDiagnostics());
1368 
1369   // Build declaration fragments, sub-heading, and signature for the method.
1370   DeclarationFragments Declaration =
1371       DeclarationFragmentsBuilder::getFragmentsForConversionFunction(Decl);
1372   DeclarationFragments SubHeading =
1373       DeclarationFragmentsBuilder::getSubHeading(Decl);
1374   FunctionSignature Signature =
1375       DeclarationFragmentsBuilder::getFunctionSignature(Decl);
1376   AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
1377 
1378   if (Decl->isStatic())
1379     API.createRecord<CXXStaticMethodRecord>(
1380         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
1381         AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
1382         SubHeading, Signature, Access, isInSystemHeader(Decl));
1383   else
1384     API.createRecord<CXXInstanceMethodRecord>(
1385         USR, Name, createHierarchyInformationForDecl(*Decl), Loc,
1386         AvailabilityInfo::createFromDecl(Decl), Comment, Declaration,
1387         SubHeading, Signature, Access, isInSystemHeader(Decl));
1388 
1389   return true;
1390 }
1391 
1392 /// Collect API information for the Objective-C methods and associate with the
1393 /// parent container.
1394 template <typename Derived>
recordObjCMethods(ObjCContainerRecord * Container,const ObjCContainerDecl::method_range Methods)1395 void ExtractAPIVisitorBase<Derived>::recordObjCMethods(
1396     ObjCContainerRecord *Container,
1397     const ObjCContainerDecl::method_range Methods) {
1398   for (const auto *Method : Methods) {
1399     // Don't record selectors for properties.
1400     if (Method->isPropertyAccessor())
1401       continue;
1402 
1403     auto Name = Method->getSelector().getAsString();
1404     SmallString<128> USR;
1405     index::generateUSRForDecl(Method, USR);
1406     PresumedLoc Loc =
1407         Context.getSourceManager().getPresumedLoc(Method->getLocation());
1408     DocComment Comment;
1409     if (auto *RawComment =
1410             getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Method))
1411       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1412                                               Context.getDiagnostics());
1413 
1414     // Build declaration fragments, sub-heading, and signature for the method.
1415     DeclarationFragments Declaration =
1416         DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
1417     DeclarationFragments SubHeading =
1418         DeclarationFragmentsBuilder::getSubHeading(Method);
1419     FunctionSignature Signature =
1420         DeclarationFragmentsBuilder::getFunctionSignature(Method);
1421 
1422     if (Method->isInstanceMethod())
1423       API.createRecord<ObjCInstanceMethodRecord>(
1424           USR, Name, createHierarchyInformationForDecl(*Method), Loc,
1425           AvailabilityInfo::createFromDecl(Method), Comment, Declaration,
1426           SubHeading, Signature, isInSystemHeader(Method));
1427     else
1428       API.createRecord<ObjCClassMethodRecord>(
1429           USR, Name, createHierarchyInformationForDecl(*Method), Loc,
1430           AvailabilityInfo::createFromDecl(Method), Comment, Declaration,
1431           SubHeading, Signature, isInSystemHeader(Method));
1432   }
1433 }
1434 
1435 template <typename Derived>
recordObjCProperties(ObjCContainerRecord * Container,const ObjCContainerDecl::prop_range Properties)1436 void ExtractAPIVisitorBase<Derived>::recordObjCProperties(
1437     ObjCContainerRecord *Container,
1438     const ObjCContainerDecl::prop_range Properties) {
1439   for (const auto *Property : Properties) {
1440     StringRef Name = Property->getName();
1441     SmallString<128> USR;
1442     index::generateUSRForDecl(Property, USR);
1443     PresumedLoc Loc =
1444         Context.getSourceManager().getPresumedLoc(Property->getLocation());
1445     DocComment Comment;
1446     if (auto *RawComment =
1447             getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Property))
1448       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1449                                               Context.getDiagnostics());
1450 
1451     // Build declaration fragments and sub-heading for the property.
1452     DeclarationFragments Declaration =
1453         DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
1454     DeclarationFragments SubHeading =
1455         DeclarationFragmentsBuilder::getSubHeading(Property);
1456 
1457     auto GetterName = Property->getGetterName().getAsString();
1458     auto SetterName = Property->getSetterName().getAsString();
1459 
1460     // Get the attributes for property.
1461     unsigned Attributes = ObjCPropertyRecord::NoAttr;
1462     if (Property->getPropertyAttributes() &
1463         ObjCPropertyAttribute::kind_readonly)
1464       Attributes |= ObjCPropertyRecord::ReadOnly;
1465 
1466     if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class)
1467       API.createRecord<ObjCClassPropertyRecord>(
1468           USR, Name, createHierarchyInformationForDecl(*Property), Loc,
1469           AvailabilityInfo::createFromDecl(Property), Comment, Declaration,
1470           SubHeading,
1471           static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
1472           GetterName, SetterName, Property->isOptional(),
1473           isInSystemHeader(Property));
1474     else
1475       API.createRecord<ObjCInstancePropertyRecord>(
1476           USR, Name, createHierarchyInformationForDecl(*Property), Loc,
1477           AvailabilityInfo::createFromDecl(Property), Comment, Declaration,
1478           SubHeading,
1479           static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
1480           GetterName, SetterName, Property->isOptional(),
1481           isInSystemHeader(Property));
1482   }
1483 }
1484 
1485 template <typename Derived>
recordObjCInstanceVariables(ObjCContainerRecord * Container,const llvm::iterator_range<DeclContext::specific_decl_iterator<ObjCIvarDecl>> Ivars)1486 void ExtractAPIVisitorBase<Derived>::recordObjCInstanceVariables(
1487     ObjCContainerRecord *Container,
1488     const llvm::iterator_range<
1489         DeclContext::specific_decl_iterator<ObjCIvarDecl>>
1490         Ivars) {
1491   for (const auto *Ivar : Ivars) {
1492     StringRef Name = Ivar->getName();
1493     SmallString<128> USR;
1494     index::generateUSRForDecl(Ivar, USR);
1495 
1496     PresumedLoc Loc =
1497         Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
1498     DocComment Comment;
1499     if (auto *RawComment =
1500             getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Ivar))
1501       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
1502                                               Context.getDiagnostics());
1503 
1504     // Build declaration fragments and sub-heading for the instance variable.
1505     DeclarationFragments Declaration =
1506         DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
1507     DeclarationFragments SubHeading =
1508         DeclarationFragmentsBuilder::getSubHeading(Ivar);
1509 
1510     API.createRecord<ObjCInstanceVariableRecord>(
1511         USR, Name, createHierarchyInformationForDecl(*Ivar), Loc,
1512         AvailabilityInfo::createFromDecl(Ivar), Comment, Declaration,
1513         SubHeading, isInSystemHeader(Ivar));
1514   }
1515 }
1516 
1517 template <typename Derived>
recordObjCProtocols(ObjCContainerRecord * Container,ObjCInterfaceDecl::protocol_range Protocols)1518 void ExtractAPIVisitorBase<Derived>::recordObjCProtocols(
1519     ObjCContainerRecord *Container,
1520     ObjCInterfaceDecl::protocol_range Protocols) {
1521   for (const auto *Protocol : Protocols)
1522     Container->Protocols.emplace_back(createSymbolReferenceForDecl(*Protocol));
1523 }
1524 
1525 } // namespace impl
1526 
1527 /// The RecursiveASTVisitor to traverse symbol declarations and collect API
1528 /// information.
1529 template <typename Derived = void>
1530 class ExtractAPIVisitor
1531     : public impl::ExtractAPIVisitorBase<std::conditional_t<
1532           std::is_same_v<Derived, void>, ExtractAPIVisitor<>, Derived>> {
1533   using Base = impl::ExtractAPIVisitorBase<std::conditional_t<
1534       std::is_same_v<Derived, void>, ExtractAPIVisitor<>, Derived>>;
1535 
1536 public:
ExtractAPIVisitor(ASTContext & Context,APISet & API)1537   ExtractAPIVisitor(ASTContext &Context, APISet &API) : Base(Context, API) {}
1538 
shouldDeclBeIncluded(const Decl * D)1539   bool shouldDeclBeIncluded(const Decl *D) const { return true; }
fetchRawCommentForDecl(const Decl * D)1540   const RawComment *fetchRawCommentForDecl(const Decl *D) const {
1541     if (const auto *Comment = this->Context.getRawCommentForDeclNoCache(D))
1542       return Comment;
1543 
1544     if (const auto *Declarator = dyn_cast<DeclaratorDecl>(D)) {
1545       const auto *TagTypeDecl = Declarator->getType()->getAsTagDecl();
1546       if (TagTypeDecl && TagTypeDecl->isEmbeddedInDeclarator() &&
1547           TagTypeDecl->isCompleteDefinition())
1548         return this->Context.getRawCommentForDeclNoCache(TagTypeDecl);
1549     }
1550 
1551     return nullptr;
1552   }
1553 };
1554 
1555 } // namespace extractapi
1556 } // namespace clang
1557 
1558 #endif // LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
1559