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 "llvm/ADT/FunctionExtras.h"
18 
19 #include "clang/AST/ASTContext.h"
20 #include "clang/AST/ParentMapContext.h"
21 #include "clang/AST/RecursiveASTVisitor.h"
22 #include "clang/Basic/SourceManager.h"
23 #include "clang/ExtractAPI/API.h"
24 #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
25 #include "llvm/ADT/StringRef.h"
26 #include <type_traits>
27 
28 namespace clang {
29 namespace extractapi {
30 namespace impl {
31 
32 template <typename Derived>
33 class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
34 protected:
35   ExtractAPIVisitorBase(ASTContext &Context, APISet &API)
36       : Context(Context), API(API) {}
37 
38 public:
39   const APISet &getAPI() const { return API; }
40 
41   bool VisitVarDecl(const VarDecl *Decl);
42 
43   bool VisitFunctionDecl(const FunctionDecl *Decl);
44 
45   bool VisitEnumDecl(const EnumDecl *Decl);
46 
47   bool VisitRecordDecl(const RecordDecl *Decl);
48 
49   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl);
50 
51   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl);
52 
53   bool VisitTypedefNameDecl(const TypedefNameDecl *Decl);
54 
55   bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl);
56 
57   bool shouldDeclBeIncluded(const Decl *Decl) const;
58 
59   const RawComment *fetchRawCommentForDecl(const Decl *Decl) const;
60 
61 protected:
62   /// Collect API information for the enum constants and associate with the
63   /// parent enum.
64   void recordEnumConstants(EnumRecord *EnumRecord,
65                            const EnumDecl::enumerator_range Constants);
66 
67   /// Collect API information for the struct fields and associate with the
68   /// parent struct.
69   void recordStructFields(StructRecord *StructRecord,
70                           const RecordDecl::field_range Fields);
71 
72   /// Collect API information for the Objective-C methods and associate with the
73   /// parent container.
74   void recordObjCMethods(ObjCContainerRecord *Container,
75                          const ObjCContainerDecl::method_range Methods);
76 
77   void recordObjCProperties(ObjCContainerRecord *Container,
78                             const ObjCContainerDecl::prop_range Properties);
79 
80   void recordObjCInstanceVariables(
81       ObjCContainerRecord *Container,
82       const llvm::iterator_range<
83           DeclContext::specific_decl_iterator<ObjCIvarDecl>>
84           Ivars);
85 
86   void recordObjCProtocols(ObjCContainerRecord *Container,
87                            ObjCInterfaceDecl::protocol_range Protocols);
88 
89   ASTContext &Context;
90   APISet &API;
91 
92   StringRef getTypedefName(const TagDecl *Decl) {
93     if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl())
94       return TypedefDecl->getName();
95 
96     return {};
97   }
98 
99   bool isInSystemHeader(const Decl *D) {
100     return Context.getSourceManager().isInSystemHeader(D->getLocation());
101   }
102 
103 private:
104   Derived &getDerivedExtractAPIVisitor() {
105     return *static_cast<Derived *>(this);
106   }
107 };
108 
109 template <typename T>
110 static void modifyRecords(const T &Records, const StringRef &Name) {
111   for (const auto &Record : Records) {
112     if (Name == Record.second.get()->Name) {
113       auto &DeclFragment = Record.second->Declaration;
114       DeclFragment.insert(DeclFragment.begin(), " ",
115                           DeclarationFragments::FragmentKind::Text);
116       DeclFragment.insert(DeclFragment.begin(), "typedef",
117                           DeclarationFragments::FragmentKind::Keyword, "",
118                           nullptr);
119       DeclFragment.insert(--DeclFragment.end(), " { ... } ",
120                           DeclarationFragments::FragmentKind::Text);
121       DeclFragment.insert(--DeclFragment.end(), Name,
122                           DeclarationFragments::FragmentKind::Identifier);
123       break;
124     }
125   }
126 }
127 
128 template <typename Derived>
129 bool ExtractAPIVisitorBase<Derived>::VisitVarDecl(const VarDecl *Decl) {
130   // skip function parameters.
131   if (isa<ParmVarDecl>(Decl))
132     return true;
133 
134   // Skip non-global variables in records (struct/union/class).
135   if (Decl->getDeclContext()->isRecord())
136     return true;
137 
138   // Skip local variables inside function or method.
139   if (!Decl->isDefinedOutsideFunctionOrMethod())
140     return true;
141 
142   // If this is a template but not specialization or instantiation, skip.
143   if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
144       Decl->getTemplateSpecializationKind() == TSK_Undeclared)
145     return true;
146 
147   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
148     return true;
149 
150   // Collect symbol information.
151   StringRef Name = Decl->getName();
152   StringRef USR = API.recordUSR(Decl);
153   PresumedLoc Loc =
154       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
155   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
156   DocComment Comment;
157   if (auto *RawComment =
158           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
159     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
160                                             Context.getDiagnostics());
161 
162   // Build declaration fragments and sub-heading for the variable.
163   DeclarationFragments Declaration =
164       DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
165   DeclarationFragments SubHeading =
166       DeclarationFragmentsBuilder::getSubHeading(Decl);
167 
168   // Add the global variable record to the API set.
169   API.addGlobalVar(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
170                    Declaration, SubHeading, isInSystemHeader(Decl));
171   return true;
172 }
173 
174 template <typename Derived>
175 bool ExtractAPIVisitorBase<Derived>::VisitFunctionDecl(
176     const FunctionDecl *Decl) {
177   if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
178     // Skip member function in class templates.
179     if (Method->getParent()->getDescribedClassTemplate() != nullptr)
180       return true;
181 
182     // Skip methods in records.
183     for (const auto &P : Context.getParents(*Method)) {
184       if (P.template get<CXXRecordDecl>())
185         return true;
186     }
187 
188     // Skip ConstructorDecl and DestructorDecl.
189     if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
190       return true;
191   }
192 
193   // Skip templated functions.
194   switch (Decl->getTemplatedKind()) {
195   case FunctionDecl::TK_NonTemplate:
196   case FunctionDecl::TK_DependentNonTemplate:
197     break;
198   case FunctionDecl::TK_MemberSpecialization:
199   case FunctionDecl::TK_FunctionTemplateSpecialization:
200     if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
201       if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
202         return true;
203     }
204     break;
205   case FunctionDecl::TK_FunctionTemplate:
206   case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
207     return true;
208   }
209 
210   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
211     return true;
212 
213   // Collect symbol information.
214   StringRef Name = Decl->getName();
215   StringRef USR = API.recordUSR(Decl);
216   PresumedLoc Loc =
217       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
218   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
219   DocComment Comment;
220   if (auto *RawComment =
221           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
222     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
223                                             Context.getDiagnostics());
224 
225   // Build declaration fragments, sub-heading, and signature of the function.
226   DeclarationFragments Declaration =
227       DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
228   DeclarationFragments SubHeading =
229       DeclarationFragmentsBuilder::getSubHeading(Decl);
230   FunctionSignature Signature =
231       DeclarationFragmentsBuilder::getFunctionSignature(Decl);
232 
233   // Add the function record to the API set.
234   API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
235                         Declaration, SubHeading, Signature,
236                         isInSystemHeader(Decl));
237   return true;
238 }
239 
240 template <typename Derived>
241 bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
242   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
243     return true;
244 
245   SmallString<128> QualifiedNameBuffer;
246   // Collect symbol information.
247   StringRef Name = Decl->getName();
248   if (Name.empty())
249     Name = getTypedefName(Decl);
250   if (Name.empty()) {
251     llvm::raw_svector_ostream OS(QualifiedNameBuffer);
252     Decl->printQualifiedName(OS);
253     Name = QualifiedNameBuffer.str();
254   }
255 
256   StringRef USR = API.recordUSR(Decl);
257   PresumedLoc Loc =
258       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
259   DocComment Comment;
260   if (auto *RawComment =
261           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
262     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
263                                             Context.getDiagnostics());
264 
265   // Build declaration fragments and sub-heading for the enum.
266   DeclarationFragments Declaration =
267       DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
268   DeclarationFragments SubHeading =
269       DeclarationFragmentsBuilder::getSubHeading(Decl);
270 
271   EnumRecord *EnumRecord =
272       API.addEnum(API.copyString(Name), USR, Loc, AvailabilitySet(Decl),
273                   Comment, Declaration, SubHeading, isInSystemHeader(Decl));
274 
275   // Now collect information about the enumerators in this enum.
276   getDerivedExtractAPIVisitor().recordEnumConstants(EnumRecord,
277                                                     Decl->enumerators());
278 
279   return true;
280 }
281 
282 template <typename Derived>
283 bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) {
284   // Skip C++ structs/classes/unions
285   // TODO: support C++ records
286   if (isa<CXXRecordDecl>(Decl))
287     return true;
288 
289   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
290     return true;
291 
292   // Collect symbol information.
293   StringRef Name = Decl->getName();
294   if (Name.empty())
295     Name = getTypedefName(Decl);
296   if (Name.empty())
297     return true;
298 
299   StringRef USR = API.recordUSR(Decl);
300   PresumedLoc Loc =
301       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
302   DocComment Comment;
303   if (auto *RawComment =
304           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
305     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
306                                             Context.getDiagnostics());
307 
308   // Build declaration fragments and sub-heading for the struct.
309   DeclarationFragments Declaration =
310       DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
311   DeclarationFragments SubHeading =
312       DeclarationFragmentsBuilder::getSubHeading(Decl);
313 
314   StructRecord *StructRecord =
315       API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
316                     SubHeading, isInSystemHeader(Decl));
317 
318   // Now collect information about the fields in this struct.
319   getDerivedExtractAPIVisitor().recordStructFields(StructRecord,
320                                                    Decl->fields());
321 
322   return true;
323 }
324 
325 template <typename Derived>
326 bool ExtractAPIVisitorBase<Derived>::VisitObjCInterfaceDecl(
327     const ObjCInterfaceDecl *Decl) {
328   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
329     return true;
330 
331   // Collect symbol information.
332   StringRef Name = Decl->getName();
333   StringRef USR = API.recordUSR(Decl);
334   PresumedLoc Loc =
335       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
336   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
337   DocComment Comment;
338   if (auto *RawComment =
339           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
340     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
341                                             Context.getDiagnostics());
342 
343   // Build declaration fragments and sub-heading for the interface.
344   DeclarationFragments Declaration =
345       DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
346   DeclarationFragments SubHeading =
347       DeclarationFragmentsBuilder::getSubHeading(Decl);
348 
349   // Collect super class information.
350   SymbolReference SuperClass;
351   if (const auto *SuperClassDecl = Decl->getSuperClass()) {
352     SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
353     SuperClass.USR = API.recordUSR(SuperClassDecl);
354   }
355 
356   ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface(
357       Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration,
358       SubHeading, SuperClass, isInSystemHeader(Decl));
359 
360   // Record all methods (selectors). This doesn't include automatically
361   // synthesized property methods.
362   getDerivedExtractAPIVisitor().recordObjCMethods(ObjCInterfaceRecord,
363                                                   Decl->methods());
364   getDerivedExtractAPIVisitor().recordObjCProperties(ObjCInterfaceRecord,
365                                                      Decl->properties());
366   getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCInterfaceRecord,
367                                                             Decl->ivars());
368   getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCInterfaceRecord,
369                                                     Decl->protocols());
370 
371   return true;
372 }
373 
374 template <typename Derived>
375 bool ExtractAPIVisitorBase<Derived>::VisitObjCProtocolDecl(
376     const ObjCProtocolDecl *Decl) {
377   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
378     return true;
379 
380   // Collect symbol information.
381   StringRef Name = Decl->getName();
382   StringRef USR = API.recordUSR(Decl);
383   PresumedLoc Loc =
384       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
385   DocComment Comment;
386   if (auto *RawComment =
387           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
388     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
389                                             Context.getDiagnostics());
390 
391   // Build declaration fragments and sub-heading for the protocol.
392   DeclarationFragments Declaration =
393       DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
394   DeclarationFragments SubHeading =
395       DeclarationFragmentsBuilder::getSubHeading(Decl);
396 
397   ObjCProtocolRecord *ObjCProtocolRecord =
398       API.addObjCProtocol(Name, USR, Loc, AvailabilitySet(Decl), Comment,
399                           Declaration, SubHeading, isInSystemHeader(Decl));
400 
401   getDerivedExtractAPIVisitor().recordObjCMethods(ObjCProtocolRecord,
402                                                   Decl->methods());
403   getDerivedExtractAPIVisitor().recordObjCProperties(ObjCProtocolRecord,
404                                                      Decl->properties());
405   getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCProtocolRecord,
406                                                     Decl->protocols());
407 
408   return true;
409 }
410 
411 template <typename Derived>
412 bool ExtractAPIVisitorBase<Derived>::VisitTypedefNameDecl(
413     const TypedefNameDecl *Decl) {
414   // Skip ObjC Type Parameter for now.
415   if (isa<ObjCTypeParamDecl>(Decl))
416     return true;
417 
418   if (!Decl->isDefinedOutsideFunctionOrMethod())
419     return true;
420 
421   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
422     return true;
423 
424   // Add the notion of typedef for tag type (struct or enum) of the same name.
425   if (const ElaboratedType *ET =
426           dyn_cast<ElaboratedType>(Decl->getUnderlyingType())) {
427     if (const TagType *TagTy = dyn_cast<TagType>(ET->desugar())) {
428       if (Decl->getName() == TagTy->getDecl()->getName()) {
429         if (TagTy->getDecl()->isStruct()) {
430           modifyRecords(API.getStructs(), Decl->getName());
431         }
432         if (TagTy->getDecl()->isEnum()) {
433           modifyRecords(API.getEnums(), Decl->getName());
434         }
435       }
436     }
437   }
438 
439   PresumedLoc Loc =
440       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
441   StringRef Name = Decl->getName();
442   StringRef USR = API.recordUSR(Decl);
443   DocComment Comment;
444   if (auto *RawComment =
445           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
446     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
447                                             Context.getDiagnostics());
448 
449   QualType Type = Decl->getUnderlyingType();
450   SymbolReference SymRef =
451       TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
452                                                                        API);
453 
454   API.addTypedef(Name, USR, Loc, AvailabilitySet(Decl), Comment,
455                  DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
456                  DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef,
457                  isInSystemHeader(Decl));
458 
459   return true;
460 }
461 
462 template <typename Derived>
463 bool ExtractAPIVisitorBase<Derived>::VisitObjCCategoryDecl(
464     const ObjCCategoryDecl *Decl) {
465   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
466     return true;
467 
468   StringRef Name = Decl->getName();
469   StringRef USR = API.recordUSR(Decl);
470   PresumedLoc Loc =
471       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
472   DocComment Comment;
473   if (auto *RawComment =
474           getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
475     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
476                                             Context.getDiagnostics());
477   // Build declaration fragments and sub-heading for the category.
478   DeclarationFragments Declaration =
479       DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
480   DeclarationFragments SubHeading =
481       DeclarationFragmentsBuilder::getSubHeading(Decl);
482 
483   const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
484   SymbolReference Interface(InterfaceDecl->getName(),
485                             API.recordUSR(InterfaceDecl));
486 
487   ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory(
488       Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
489       Interface, isInSystemHeader(Decl));
490 
491   getDerivedExtractAPIVisitor().recordObjCMethods(ObjCCategoryRecord,
492                                                   Decl->methods());
493   getDerivedExtractAPIVisitor().recordObjCProperties(ObjCCategoryRecord,
494                                                      Decl->properties());
495   getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCCategoryRecord,
496                                                             Decl->ivars());
497   getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCCategoryRecord,
498                                                     Decl->protocols());
499 
500   return true;
501 }
502 
503 /// Collect API information for the enum constants and associate with the
504 /// parent enum.
505 template <typename Derived>
506 void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
507     EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) {
508   for (const auto *Constant : Constants) {
509     // Collect symbol information.
510     StringRef Name = Constant->getName();
511     StringRef USR = API.recordUSR(Constant);
512     PresumedLoc Loc =
513         Context.getSourceManager().getPresumedLoc(Constant->getLocation());
514     DocComment Comment;
515     if (auto *RawComment =
516             getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Constant))
517       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
518                                               Context.getDiagnostics());
519 
520     // Build declaration fragments and sub-heading for the enum constant.
521     DeclarationFragments Declaration =
522         DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
523     DeclarationFragments SubHeading =
524         DeclarationFragmentsBuilder::getSubHeading(Constant);
525 
526     API.addEnumConstant(EnumRecord, Name, USR, Loc, AvailabilitySet(Constant),
527                         Comment, Declaration, SubHeading,
528                         isInSystemHeader(Constant));
529   }
530 }
531 
532 /// Collect API information for the struct fields and associate with the
533 /// parent struct.
534 template <typename Derived>
535 void ExtractAPIVisitorBase<Derived>::recordStructFields(
536     StructRecord *StructRecord, const RecordDecl::field_range Fields) {
537   for (const auto *Field : Fields) {
538     // Collect symbol information.
539     StringRef Name = Field->getName();
540     StringRef USR = API.recordUSR(Field);
541     PresumedLoc Loc =
542         Context.getSourceManager().getPresumedLoc(Field->getLocation());
543     DocComment Comment;
544     if (auto *RawComment =
545             getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Field))
546       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
547                                               Context.getDiagnostics());
548 
549     // Build declaration fragments and sub-heading for the struct field.
550     DeclarationFragments Declaration =
551         DeclarationFragmentsBuilder::getFragmentsForField(Field);
552     DeclarationFragments SubHeading =
553         DeclarationFragmentsBuilder::getSubHeading(Field);
554 
555     API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field),
556                        Comment, Declaration, SubHeading,
557                        isInSystemHeader(Field));
558   }
559 }
560 
561 /// Collect API information for the Objective-C methods and associate with the
562 /// parent container.
563 template <typename Derived>
564 void ExtractAPIVisitorBase<Derived>::recordObjCMethods(
565     ObjCContainerRecord *Container,
566     const ObjCContainerDecl::method_range Methods) {
567   for (const auto *Method : Methods) {
568     // Don't record selectors for properties.
569     if (Method->isPropertyAccessor())
570       continue;
571 
572     StringRef Name = API.copyString(Method->getSelector().getAsString());
573     StringRef USR = API.recordUSR(Method);
574     PresumedLoc Loc =
575         Context.getSourceManager().getPresumedLoc(Method->getLocation());
576     DocComment Comment;
577     if (auto *RawComment =
578             getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Method))
579       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
580                                               Context.getDiagnostics());
581 
582     // Build declaration fragments, sub-heading, and signature for the method.
583     DeclarationFragments Declaration =
584         DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
585     DeclarationFragments SubHeading =
586         DeclarationFragmentsBuilder::getSubHeading(Method);
587     FunctionSignature Signature =
588         DeclarationFragmentsBuilder::getFunctionSignature(Method);
589 
590     API.addObjCMethod(Container, Name, USR, Loc, AvailabilitySet(Method),
591                       Comment, Declaration, SubHeading, Signature,
592                       Method->isInstanceMethod(), isInSystemHeader(Method));
593   }
594 }
595 
596 template <typename Derived>
597 void ExtractAPIVisitorBase<Derived>::recordObjCProperties(
598     ObjCContainerRecord *Container,
599     const ObjCContainerDecl::prop_range Properties) {
600   for (const auto *Property : Properties) {
601     StringRef Name = Property->getName();
602     StringRef USR = API.recordUSR(Property);
603     PresumedLoc Loc =
604         Context.getSourceManager().getPresumedLoc(Property->getLocation());
605     DocComment Comment;
606     if (auto *RawComment =
607             getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Property))
608       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
609                                               Context.getDiagnostics());
610 
611     // Build declaration fragments and sub-heading for the property.
612     DeclarationFragments Declaration =
613         DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
614     DeclarationFragments SubHeading =
615         DeclarationFragmentsBuilder::getSubHeading(Property);
616 
617     StringRef GetterName =
618         API.copyString(Property->getGetterName().getAsString());
619     StringRef SetterName =
620         API.copyString(Property->getSetterName().getAsString());
621 
622     // Get the attributes for property.
623     unsigned Attributes = ObjCPropertyRecord::NoAttr;
624     if (Property->getPropertyAttributes() &
625         ObjCPropertyAttribute::kind_readonly)
626       Attributes |= ObjCPropertyRecord::ReadOnly;
627 
628     API.addObjCProperty(
629         Container, Name, USR, Loc, AvailabilitySet(Property), Comment,
630         Declaration, SubHeading,
631         static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), GetterName,
632         SetterName, Property->isOptional(),
633         !(Property->getPropertyAttributes() &
634           ObjCPropertyAttribute::kind_class),
635         isInSystemHeader(Property));
636   }
637 }
638 
639 template <typename Derived>
640 void ExtractAPIVisitorBase<Derived>::recordObjCInstanceVariables(
641     ObjCContainerRecord *Container,
642     const llvm::iterator_range<
643         DeclContext::specific_decl_iterator<ObjCIvarDecl>>
644         Ivars) {
645   for (const auto *Ivar : Ivars) {
646     StringRef Name = Ivar->getName();
647     StringRef USR = API.recordUSR(Ivar);
648     PresumedLoc Loc =
649         Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
650     DocComment Comment;
651     if (auto *RawComment =
652             getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Ivar))
653       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
654                                               Context.getDiagnostics());
655 
656     // Build declaration fragments and sub-heading for the instance variable.
657     DeclarationFragments Declaration =
658         DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
659     DeclarationFragments SubHeading =
660         DeclarationFragmentsBuilder::getSubHeading(Ivar);
661 
662     ObjCInstanceVariableRecord::AccessControl Access =
663         Ivar->getCanonicalAccessControl();
664 
665     API.addObjCInstanceVariable(Container, Name, USR, Loc,
666                                 AvailabilitySet(Ivar), Comment, Declaration,
667                                 SubHeading, Access, isInSystemHeader(Ivar));
668   }
669 }
670 
671 template <typename Derived>
672 void ExtractAPIVisitorBase<Derived>::recordObjCProtocols(
673     ObjCContainerRecord *Container,
674     ObjCInterfaceDecl::protocol_range Protocols) {
675   for (const auto *Protocol : Protocols)
676     Container->Protocols.emplace_back(Protocol->getName(),
677                                       API.recordUSR(Protocol));
678 }
679 
680 } // namespace impl
681 
682 /// The RecursiveASTVisitor to traverse symbol declarations and collect API
683 /// information.
684 template <typename Derived = void>
685 class ExtractAPIVisitor
686     : public impl::ExtractAPIVisitorBase<std::conditional_t<
687           std::is_same_v<Derived, void>, ExtractAPIVisitor<>, Derived>> {
688   using Base = impl::ExtractAPIVisitorBase<std::conditional_t<
689       std::is_same_v<Derived, void>, ExtractAPIVisitor<>, Derived>>;
690 
691 public:
692   ExtractAPIVisitor(ASTContext &Context, APISet &API) : Base(Context, API) {}
693 
694   bool shouldDeclBeIncluded(const Decl *D) const { return true; }
695   const RawComment *fetchRawCommentForDecl(const Decl *D) const {
696     return this->Context.getRawCommentForDeclNoCache(D);
697   }
698 };
699 
700 } // namespace extractapi
701 } // namespace clang
702 
703 #endif // LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
704