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