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

source code of clang/include/clang/ExtractAPI/ExtractAPIVisitor.h