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