xref: /openbsd-src/gnu/llvm/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1*12c85518Srobert //===- ExtractAPI/ExtractAPIVisitor.cpp -------------------------*- C++ -*-===//
2*12c85518Srobert //
3*12c85518Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*12c85518Srobert // See https://llvm.org/LICENSE.txt for license information.
5*12c85518Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*12c85518Srobert //
7*12c85518Srobert //===----------------------------------------------------------------------===//
8*12c85518Srobert ///
9*12c85518Srobert /// \file
10*12c85518Srobert /// This file implements the ExtractAPIVisitor an ASTVisitor to collect API
11*12c85518Srobert /// information.
12*12c85518Srobert ///
13*12c85518Srobert //===----------------------------------------------------------------------===//
14*12c85518Srobert 
15*12c85518Srobert #include "clang/ExtractAPI/ExtractAPIVisitor.h"
16*12c85518Srobert 
17*12c85518Srobert #include "TypedefUnderlyingTypeResolver.h"
18*12c85518Srobert #include "clang/AST/ASTConsumer.h"
19*12c85518Srobert #include "clang/AST/ASTContext.h"
20*12c85518Srobert #include "clang/AST/Decl.h"
21*12c85518Srobert #include "clang/AST/DeclCXX.h"
22*12c85518Srobert #include "clang/AST/ParentMapContext.h"
23*12c85518Srobert #include "clang/AST/RawCommentList.h"
24*12c85518Srobert #include "clang/Basic/SourceLocation.h"
25*12c85518Srobert #include "clang/Basic/SourceManager.h"
26*12c85518Srobert #include "clang/Basic/TargetInfo.h"
27*12c85518Srobert #include "clang/ExtractAPI/API.h"
28*12c85518Srobert #include "clang/ExtractAPI/AvailabilityInfo.h"
29*12c85518Srobert #include "clang/ExtractAPI/DeclarationFragments.h"
30*12c85518Srobert #include "clang/Frontend/ASTConsumers.h"
31*12c85518Srobert #include "clang/Frontend/FrontendOptions.h"
32*12c85518Srobert #include "llvm/Support/raw_ostream.h"
33*12c85518Srobert 
34*12c85518Srobert using namespace clang;
35*12c85518Srobert using namespace extractapi;
36*12c85518Srobert 
37*12c85518Srobert namespace {
38*12c85518Srobert 
getTypedefName(const TagDecl * Decl)39*12c85518Srobert StringRef getTypedefName(const TagDecl *Decl) {
40*12c85518Srobert   if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl())
41*12c85518Srobert     return TypedefDecl->getName();
42*12c85518Srobert 
43*12c85518Srobert   return {};
44*12c85518Srobert }
45*12c85518Srobert 
46*12c85518Srobert template <class DeclTy>
isInSystemHeader(const ASTContext & Context,const DeclTy * D)47*12c85518Srobert bool isInSystemHeader(const ASTContext &Context, const DeclTy *D) {
48*12c85518Srobert   return Context.getSourceManager().isInSystemHeader(D->getLocation());
49*12c85518Srobert }
50*12c85518Srobert 
51*12c85518Srobert } // namespace
52*12c85518Srobert 
VisitVarDecl(const VarDecl * Decl)53*12c85518Srobert bool ExtractAPIVisitor::VisitVarDecl(const VarDecl *Decl) {
54*12c85518Srobert   // skip function parameters.
55*12c85518Srobert   if (isa<ParmVarDecl>(Decl))
56*12c85518Srobert     return true;
57*12c85518Srobert 
58*12c85518Srobert   // Skip non-global variables in records (struct/union/class).
59*12c85518Srobert   if (Decl->getDeclContext()->isRecord())
60*12c85518Srobert     return true;
61*12c85518Srobert 
62*12c85518Srobert   // Skip local variables inside function or method.
63*12c85518Srobert   if (!Decl->isDefinedOutsideFunctionOrMethod())
64*12c85518Srobert     return true;
65*12c85518Srobert 
66*12c85518Srobert   // If this is a template but not specialization or instantiation, skip.
67*12c85518Srobert   if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
68*12c85518Srobert       Decl->getTemplateSpecializationKind() == TSK_Undeclared)
69*12c85518Srobert     return true;
70*12c85518Srobert 
71*12c85518Srobert   if (!LocationChecker(Decl->getLocation()))
72*12c85518Srobert     return true;
73*12c85518Srobert 
74*12c85518Srobert   // Collect symbol information.
75*12c85518Srobert   StringRef Name = Decl->getName();
76*12c85518Srobert   StringRef USR = API.recordUSR(Decl);
77*12c85518Srobert   PresumedLoc Loc =
78*12c85518Srobert       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
79*12c85518Srobert   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
80*12c85518Srobert   DocComment Comment;
81*12c85518Srobert   if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
82*12c85518Srobert     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
83*12c85518Srobert                                             Context.getDiagnostics());
84*12c85518Srobert 
85*12c85518Srobert   // Build declaration fragments and sub-heading for the variable.
86*12c85518Srobert   DeclarationFragments Declaration =
87*12c85518Srobert       DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
88*12c85518Srobert   DeclarationFragments SubHeading =
89*12c85518Srobert       DeclarationFragmentsBuilder::getSubHeading(Decl);
90*12c85518Srobert 
91*12c85518Srobert   // Add the global variable record to the API set.
92*12c85518Srobert   API.addGlobalVar(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
93*12c85518Srobert                    Declaration, SubHeading, isInSystemHeader(Context, Decl));
94*12c85518Srobert   return true;
95*12c85518Srobert }
96*12c85518Srobert 
VisitFunctionDecl(const FunctionDecl * Decl)97*12c85518Srobert bool ExtractAPIVisitor::VisitFunctionDecl(const FunctionDecl *Decl) {
98*12c85518Srobert   if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
99*12c85518Srobert     // Skip member function in class templates.
100*12c85518Srobert     if (Method->getParent()->getDescribedClassTemplate() != nullptr)
101*12c85518Srobert       return true;
102*12c85518Srobert 
103*12c85518Srobert     // Skip methods in records.
104*12c85518Srobert     for (auto P : Context.getParents(*Method)) {
105*12c85518Srobert       if (P.get<CXXRecordDecl>())
106*12c85518Srobert         return true;
107*12c85518Srobert     }
108*12c85518Srobert 
109*12c85518Srobert     // Skip ConstructorDecl and DestructorDecl.
110*12c85518Srobert     if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
111*12c85518Srobert       return true;
112*12c85518Srobert   }
113*12c85518Srobert 
114*12c85518Srobert   // Skip templated functions.
115*12c85518Srobert   switch (Decl->getTemplatedKind()) {
116*12c85518Srobert   case FunctionDecl::TK_NonTemplate:
117*12c85518Srobert   case FunctionDecl::TK_DependentNonTemplate:
118*12c85518Srobert     break;
119*12c85518Srobert   case FunctionDecl::TK_MemberSpecialization:
120*12c85518Srobert   case FunctionDecl::TK_FunctionTemplateSpecialization:
121*12c85518Srobert     if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
122*12c85518Srobert       if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
123*12c85518Srobert         return true;
124*12c85518Srobert     }
125*12c85518Srobert     break;
126*12c85518Srobert   case FunctionDecl::TK_FunctionTemplate:
127*12c85518Srobert   case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
128*12c85518Srobert     return true;
129*12c85518Srobert   }
130*12c85518Srobert 
131*12c85518Srobert   if (!LocationChecker(Decl->getLocation()))
132*12c85518Srobert     return true;
133*12c85518Srobert 
134*12c85518Srobert   // Collect symbol information.
135*12c85518Srobert   StringRef Name = Decl->getName();
136*12c85518Srobert   StringRef USR = API.recordUSR(Decl);
137*12c85518Srobert   PresumedLoc Loc =
138*12c85518Srobert       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
139*12c85518Srobert   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
140*12c85518Srobert   DocComment Comment;
141*12c85518Srobert   if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
142*12c85518Srobert     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
143*12c85518Srobert                                             Context.getDiagnostics());
144*12c85518Srobert 
145*12c85518Srobert   // Build declaration fragments, sub-heading, and signature of the function.
146*12c85518Srobert   DeclarationFragments Declaration =
147*12c85518Srobert       DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
148*12c85518Srobert   DeclarationFragments SubHeading =
149*12c85518Srobert       DeclarationFragmentsBuilder::getSubHeading(Decl);
150*12c85518Srobert   FunctionSignature Signature =
151*12c85518Srobert       DeclarationFragmentsBuilder::getFunctionSignature(Decl);
152*12c85518Srobert 
153*12c85518Srobert   // Add the function record to the API set.
154*12c85518Srobert   API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
155*12c85518Srobert                         Declaration, SubHeading, Signature,
156*12c85518Srobert                         isInSystemHeader(Context, Decl));
157*12c85518Srobert   return true;
158*12c85518Srobert }
159*12c85518Srobert 
VisitEnumDecl(const EnumDecl * Decl)160*12c85518Srobert bool ExtractAPIVisitor::VisitEnumDecl(const EnumDecl *Decl) {
161*12c85518Srobert   if (!Decl->isComplete())
162*12c85518Srobert     return true;
163*12c85518Srobert 
164*12c85518Srobert   // Skip forward declaration.
165*12c85518Srobert   if (!Decl->isThisDeclarationADefinition())
166*12c85518Srobert     return true;
167*12c85518Srobert 
168*12c85518Srobert   if (!LocationChecker(Decl->getLocation()))
169*12c85518Srobert     return true;
170*12c85518Srobert 
171*12c85518Srobert   SmallString<128> QualifiedNameBuffer;
172*12c85518Srobert   // Collect symbol information.
173*12c85518Srobert   StringRef Name = Decl->getName();
174*12c85518Srobert   if (Name.empty())
175*12c85518Srobert     Name = getTypedefName(Decl);
176*12c85518Srobert   if (Name.empty()) {
177*12c85518Srobert     llvm::raw_svector_ostream OS(QualifiedNameBuffer);
178*12c85518Srobert     Decl->printQualifiedName(OS);
179*12c85518Srobert     Name = QualifiedNameBuffer.str();
180*12c85518Srobert   }
181*12c85518Srobert 
182*12c85518Srobert   StringRef USR = API.recordUSR(Decl);
183*12c85518Srobert   PresumedLoc Loc =
184*12c85518Srobert       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
185*12c85518Srobert   DocComment Comment;
186*12c85518Srobert   if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
187*12c85518Srobert     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
188*12c85518Srobert                                             Context.getDiagnostics());
189*12c85518Srobert 
190*12c85518Srobert   // Build declaration fragments and sub-heading for the enum.
191*12c85518Srobert   DeclarationFragments Declaration =
192*12c85518Srobert       DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
193*12c85518Srobert   DeclarationFragments SubHeading =
194*12c85518Srobert       DeclarationFragmentsBuilder::getSubHeading(Decl);
195*12c85518Srobert 
196*12c85518Srobert   EnumRecord *EnumRecord = API.addEnum(
197*12c85518Srobert       API.copyString(Name), USR, Loc, AvailabilitySet(Decl), Comment,
198*12c85518Srobert       Declaration, SubHeading, isInSystemHeader(Context, Decl));
199*12c85518Srobert 
200*12c85518Srobert   // Now collect information about the enumerators in this enum.
201*12c85518Srobert   recordEnumConstants(EnumRecord, Decl->enumerators());
202*12c85518Srobert 
203*12c85518Srobert   return true;
204*12c85518Srobert }
205*12c85518Srobert 
VisitRecordDecl(const RecordDecl * Decl)206*12c85518Srobert bool ExtractAPIVisitor::VisitRecordDecl(const RecordDecl *Decl) {
207*12c85518Srobert   if (!Decl->isCompleteDefinition())
208*12c85518Srobert     return true;
209*12c85518Srobert 
210*12c85518Srobert   // Skip C++ structs/classes/unions
211*12c85518Srobert   // TODO: support C++ records
212*12c85518Srobert   if (isa<CXXRecordDecl>(Decl))
213*12c85518Srobert     return true;
214*12c85518Srobert 
215*12c85518Srobert   if (!LocationChecker(Decl->getLocation()))
216*12c85518Srobert     return true;
217*12c85518Srobert 
218*12c85518Srobert   // Collect symbol information.
219*12c85518Srobert   StringRef Name = Decl->getName();
220*12c85518Srobert   if (Name.empty())
221*12c85518Srobert     Name = getTypedefName(Decl);
222*12c85518Srobert   if (Name.empty())
223*12c85518Srobert     return true;
224*12c85518Srobert 
225*12c85518Srobert   StringRef USR = API.recordUSR(Decl);
226*12c85518Srobert   PresumedLoc Loc =
227*12c85518Srobert       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
228*12c85518Srobert   DocComment Comment;
229*12c85518Srobert   if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
230*12c85518Srobert     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
231*12c85518Srobert                                             Context.getDiagnostics());
232*12c85518Srobert 
233*12c85518Srobert   // Build declaration fragments and sub-heading for the struct.
234*12c85518Srobert   DeclarationFragments Declaration =
235*12c85518Srobert       DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
236*12c85518Srobert   DeclarationFragments SubHeading =
237*12c85518Srobert       DeclarationFragmentsBuilder::getSubHeading(Decl);
238*12c85518Srobert 
239*12c85518Srobert   StructRecord *StructRecord =
240*12c85518Srobert       API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
241*12c85518Srobert                     SubHeading, isInSystemHeader(Context, Decl));
242*12c85518Srobert 
243*12c85518Srobert   // Now collect information about the fields in this struct.
244*12c85518Srobert   recordStructFields(StructRecord, Decl->fields());
245*12c85518Srobert 
246*12c85518Srobert   return true;
247*12c85518Srobert }
248*12c85518Srobert 
VisitObjCInterfaceDecl(const ObjCInterfaceDecl * Decl)249*12c85518Srobert bool ExtractAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
250*12c85518Srobert   // Skip forward declaration for classes (@class)
251*12c85518Srobert   if (!Decl->isThisDeclarationADefinition())
252*12c85518Srobert     return true;
253*12c85518Srobert 
254*12c85518Srobert   if (!LocationChecker(Decl->getLocation()))
255*12c85518Srobert     return true;
256*12c85518Srobert 
257*12c85518Srobert   // Collect symbol information.
258*12c85518Srobert   StringRef Name = Decl->getName();
259*12c85518Srobert   StringRef USR = API.recordUSR(Decl);
260*12c85518Srobert   PresumedLoc Loc =
261*12c85518Srobert       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
262*12c85518Srobert   LinkageInfo Linkage = Decl->getLinkageAndVisibility();
263*12c85518Srobert   DocComment Comment;
264*12c85518Srobert   if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
265*12c85518Srobert     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
266*12c85518Srobert                                             Context.getDiagnostics());
267*12c85518Srobert 
268*12c85518Srobert   // Build declaration fragments and sub-heading for the interface.
269*12c85518Srobert   DeclarationFragments Declaration =
270*12c85518Srobert       DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
271*12c85518Srobert   DeclarationFragments SubHeading =
272*12c85518Srobert       DeclarationFragmentsBuilder::getSubHeading(Decl);
273*12c85518Srobert 
274*12c85518Srobert   // Collect super class information.
275*12c85518Srobert   SymbolReference SuperClass;
276*12c85518Srobert   if (const auto *SuperClassDecl = Decl->getSuperClass()) {
277*12c85518Srobert     SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
278*12c85518Srobert     SuperClass.USR = API.recordUSR(SuperClassDecl);
279*12c85518Srobert   }
280*12c85518Srobert 
281*12c85518Srobert   ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface(
282*12c85518Srobert       Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration,
283*12c85518Srobert       SubHeading, SuperClass, isInSystemHeader(Context, Decl));
284*12c85518Srobert 
285*12c85518Srobert   // Record all methods (selectors). This doesn't include automatically
286*12c85518Srobert   // synthesized property methods.
287*12c85518Srobert   recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
288*12c85518Srobert   recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
289*12c85518Srobert   recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
290*12c85518Srobert   recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
291*12c85518Srobert 
292*12c85518Srobert   return true;
293*12c85518Srobert }
294*12c85518Srobert 
VisitObjCProtocolDecl(const ObjCProtocolDecl * Decl)295*12c85518Srobert bool ExtractAPIVisitor::VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) {
296*12c85518Srobert   // Skip forward declaration for protocols (@protocol).
297*12c85518Srobert   if (!Decl->isThisDeclarationADefinition())
298*12c85518Srobert     return true;
299*12c85518Srobert 
300*12c85518Srobert   if (!LocationChecker(Decl->getLocation()))
301*12c85518Srobert     return true;
302*12c85518Srobert 
303*12c85518Srobert   // Collect symbol information.
304*12c85518Srobert   StringRef Name = Decl->getName();
305*12c85518Srobert   StringRef USR = API.recordUSR(Decl);
306*12c85518Srobert   PresumedLoc Loc =
307*12c85518Srobert       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
308*12c85518Srobert   DocComment Comment;
309*12c85518Srobert   if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
310*12c85518Srobert     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
311*12c85518Srobert                                             Context.getDiagnostics());
312*12c85518Srobert 
313*12c85518Srobert   // Build declaration fragments and sub-heading for the protocol.
314*12c85518Srobert   DeclarationFragments Declaration =
315*12c85518Srobert       DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
316*12c85518Srobert   DeclarationFragments SubHeading =
317*12c85518Srobert       DeclarationFragmentsBuilder::getSubHeading(Decl);
318*12c85518Srobert 
319*12c85518Srobert   ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
320*12c85518Srobert       Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
321*12c85518Srobert       isInSystemHeader(Context, Decl));
322*12c85518Srobert 
323*12c85518Srobert   recordObjCMethods(ObjCProtocolRecord, Decl->methods());
324*12c85518Srobert   recordObjCProperties(ObjCProtocolRecord, Decl->properties());
325*12c85518Srobert   recordObjCProtocols(ObjCProtocolRecord, Decl->protocols());
326*12c85518Srobert 
327*12c85518Srobert   return true;
328*12c85518Srobert }
329*12c85518Srobert 
VisitTypedefNameDecl(const TypedefNameDecl * Decl)330*12c85518Srobert bool ExtractAPIVisitor::VisitTypedefNameDecl(const TypedefNameDecl *Decl) {
331*12c85518Srobert   // Skip ObjC Type Parameter for now.
332*12c85518Srobert   if (isa<ObjCTypeParamDecl>(Decl))
333*12c85518Srobert     return true;
334*12c85518Srobert 
335*12c85518Srobert   if (!Decl->isDefinedOutsideFunctionOrMethod())
336*12c85518Srobert     return true;
337*12c85518Srobert 
338*12c85518Srobert   if (!LocationChecker(Decl->getLocation()))
339*12c85518Srobert     return true;
340*12c85518Srobert 
341*12c85518Srobert   PresumedLoc Loc =
342*12c85518Srobert       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
343*12c85518Srobert   StringRef Name = Decl->getName();
344*12c85518Srobert   StringRef USR = API.recordUSR(Decl);
345*12c85518Srobert   DocComment Comment;
346*12c85518Srobert   if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
347*12c85518Srobert     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
348*12c85518Srobert                                             Context.getDiagnostics());
349*12c85518Srobert 
350*12c85518Srobert   QualType Type = Decl->getUnderlyingType();
351*12c85518Srobert   SymbolReference SymRef =
352*12c85518Srobert       TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
353*12c85518Srobert                                                                        API);
354*12c85518Srobert 
355*12c85518Srobert   API.addTypedef(Name, USR, Loc, AvailabilitySet(Decl), Comment,
356*12c85518Srobert                  DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
357*12c85518Srobert                  DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef,
358*12c85518Srobert                  isInSystemHeader(Context, Decl));
359*12c85518Srobert 
360*12c85518Srobert   return true;
361*12c85518Srobert }
362*12c85518Srobert 
VisitObjCCategoryDecl(const ObjCCategoryDecl * Decl)363*12c85518Srobert bool ExtractAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) {
364*12c85518Srobert   // Collect symbol information.
365*12c85518Srobert   StringRef Name = Decl->getName();
366*12c85518Srobert   StringRef USR = API.recordUSR(Decl);
367*12c85518Srobert   PresumedLoc Loc =
368*12c85518Srobert       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
369*12c85518Srobert   DocComment Comment;
370*12c85518Srobert   if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
371*12c85518Srobert     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
372*12c85518Srobert                                             Context.getDiagnostics());
373*12c85518Srobert   // Build declaration fragments and sub-heading for the category.
374*12c85518Srobert   DeclarationFragments Declaration =
375*12c85518Srobert       DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
376*12c85518Srobert   DeclarationFragments SubHeading =
377*12c85518Srobert       DeclarationFragmentsBuilder::getSubHeading(Decl);
378*12c85518Srobert 
379*12c85518Srobert   const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
380*12c85518Srobert   SymbolReference Interface(InterfaceDecl->getName(),
381*12c85518Srobert                             API.recordUSR(InterfaceDecl));
382*12c85518Srobert 
383*12c85518Srobert   ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory(
384*12c85518Srobert       Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
385*12c85518Srobert       Interface, isInSystemHeader(Context, Decl));
386*12c85518Srobert 
387*12c85518Srobert   recordObjCMethods(ObjCCategoryRecord, Decl->methods());
388*12c85518Srobert   recordObjCProperties(ObjCCategoryRecord, Decl->properties());
389*12c85518Srobert   recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars());
390*12c85518Srobert   recordObjCProtocols(ObjCCategoryRecord, Decl->protocols());
391*12c85518Srobert 
392*12c85518Srobert   return true;
393*12c85518Srobert }
394*12c85518Srobert 
395*12c85518Srobert /// Collect API information for the enum constants and associate with the
396*12c85518Srobert /// parent enum.
recordEnumConstants(EnumRecord * EnumRecord,const EnumDecl::enumerator_range Constants)397*12c85518Srobert void ExtractAPIVisitor::recordEnumConstants(
398*12c85518Srobert     EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) {
399*12c85518Srobert   for (const auto *Constant : Constants) {
400*12c85518Srobert     // Collect symbol information.
401*12c85518Srobert     StringRef Name = Constant->getName();
402*12c85518Srobert     StringRef USR = API.recordUSR(Constant);
403*12c85518Srobert     PresumedLoc Loc =
404*12c85518Srobert         Context.getSourceManager().getPresumedLoc(Constant->getLocation());
405*12c85518Srobert     DocComment Comment;
406*12c85518Srobert     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
407*12c85518Srobert       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
408*12c85518Srobert                                               Context.getDiagnostics());
409*12c85518Srobert 
410*12c85518Srobert     // Build declaration fragments and sub-heading for the enum constant.
411*12c85518Srobert     DeclarationFragments Declaration =
412*12c85518Srobert         DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
413*12c85518Srobert     DeclarationFragments SubHeading =
414*12c85518Srobert         DeclarationFragmentsBuilder::getSubHeading(Constant);
415*12c85518Srobert 
416*12c85518Srobert     API.addEnumConstant(EnumRecord, Name, USR, Loc, AvailabilitySet(Constant),
417*12c85518Srobert                         Comment, Declaration, SubHeading,
418*12c85518Srobert                         isInSystemHeader(Context, Constant));
419*12c85518Srobert   }
420*12c85518Srobert }
421*12c85518Srobert 
422*12c85518Srobert /// Collect API information for the struct fields and associate with the
423*12c85518Srobert /// parent struct.
recordStructFields(StructRecord * StructRecord,const RecordDecl::field_range Fields)424*12c85518Srobert void ExtractAPIVisitor::recordStructFields(
425*12c85518Srobert     StructRecord *StructRecord, const RecordDecl::field_range Fields) {
426*12c85518Srobert   for (const auto *Field : Fields) {
427*12c85518Srobert     // Collect symbol information.
428*12c85518Srobert     StringRef Name = Field->getName();
429*12c85518Srobert     StringRef USR = API.recordUSR(Field);
430*12c85518Srobert     PresumedLoc Loc =
431*12c85518Srobert         Context.getSourceManager().getPresumedLoc(Field->getLocation());
432*12c85518Srobert     DocComment Comment;
433*12c85518Srobert     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
434*12c85518Srobert       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
435*12c85518Srobert                                               Context.getDiagnostics());
436*12c85518Srobert 
437*12c85518Srobert     // Build declaration fragments and sub-heading for the struct field.
438*12c85518Srobert     DeclarationFragments Declaration =
439*12c85518Srobert         DeclarationFragmentsBuilder::getFragmentsForField(Field);
440*12c85518Srobert     DeclarationFragments SubHeading =
441*12c85518Srobert         DeclarationFragmentsBuilder::getSubHeading(Field);
442*12c85518Srobert 
443*12c85518Srobert     API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field),
444*12c85518Srobert                        Comment, Declaration, SubHeading,
445*12c85518Srobert                        isInSystemHeader(Context, Field));
446*12c85518Srobert   }
447*12c85518Srobert }
448*12c85518Srobert 
449*12c85518Srobert /// Collect API information for the Objective-C methods and associate with the
450*12c85518Srobert /// parent container.
recordObjCMethods(ObjCContainerRecord * Container,const ObjCContainerDecl::method_range Methods)451*12c85518Srobert void ExtractAPIVisitor::recordObjCMethods(
452*12c85518Srobert     ObjCContainerRecord *Container,
453*12c85518Srobert     const ObjCContainerDecl::method_range Methods) {
454*12c85518Srobert   for (const auto *Method : Methods) {
455*12c85518Srobert     // Don't record selectors for properties.
456*12c85518Srobert     if (Method->isPropertyAccessor())
457*12c85518Srobert       continue;
458*12c85518Srobert 
459*12c85518Srobert     StringRef Name = API.copyString(Method->getSelector().getAsString());
460*12c85518Srobert     StringRef USR = API.recordUSR(Method);
461*12c85518Srobert     PresumedLoc Loc =
462*12c85518Srobert         Context.getSourceManager().getPresumedLoc(Method->getLocation());
463*12c85518Srobert     DocComment Comment;
464*12c85518Srobert     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
465*12c85518Srobert       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
466*12c85518Srobert                                               Context.getDiagnostics());
467*12c85518Srobert 
468*12c85518Srobert     // Build declaration fragments, sub-heading, and signature for the method.
469*12c85518Srobert     DeclarationFragments Declaration =
470*12c85518Srobert         DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
471*12c85518Srobert     DeclarationFragments SubHeading =
472*12c85518Srobert         DeclarationFragmentsBuilder::getSubHeading(Method);
473*12c85518Srobert     FunctionSignature Signature =
474*12c85518Srobert         DeclarationFragmentsBuilder::getFunctionSignature(Method);
475*12c85518Srobert 
476*12c85518Srobert     API.addObjCMethod(Container, Name, USR, Loc, AvailabilitySet(Method),
477*12c85518Srobert                       Comment, Declaration, SubHeading, Signature,
478*12c85518Srobert                       Method->isInstanceMethod(),
479*12c85518Srobert                       isInSystemHeader(Context, Method));
480*12c85518Srobert   }
481*12c85518Srobert }
482*12c85518Srobert 
recordObjCProperties(ObjCContainerRecord * Container,const ObjCContainerDecl::prop_range Properties)483*12c85518Srobert void ExtractAPIVisitor::recordObjCProperties(
484*12c85518Srobert     ObjCContainerRecord *Container,
485*12c85518Srobert     const ObjCContainerDecl::prop_range Properties) {
486*12c85518Srobert   for (const auto *Property : Properties) {
487*12c85518Srobert     StringRef Name = Property->getName();
488*12c85518Srobert     StringRef USR = API.recordUSR(Property);
489*12c85518Srobert     PresumedLoc Loc =
490*12c85518Srobert         Context.getSourceManager().getPresumedLoc(Property->getLocation());
491*12c85518Srobert     DocComment Comment;
492*12c85518Srobert     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
493*12c85518Srobert       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
494*12c85518Srobert                                               Context.getDiagnostics());
495*12c85518Srobert 
496*12c85518Srobert     // Build declaration fragments and sub-heading for the property.
497*12c85518Srobert     DeclarationFragments Declaration =
498*12c85518Srobert         DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
499*12c85518Srobert     DeclarationFragments SubHeading =
500*12c85518Srobert         DeclarationFragmentsBuilder::getSubHeading(Property);
501*12c85518Srobert 
502*12c85518Srobert     StringRef GetterName =
503*12c85518Srobert         API.copyString(Property->getGetterName().getAsString());
504*12c85518Srobert     StringRef SetterName =
505*12c85518Srobert         API.copyString(Property->getSetterName().getAsString());
506*12c85518Srobert 
507*12c85518Srobert     // Get the attributes for property.
508*12c85518Srobert     unsigned Attributes = ObjCPropertyRecord::NoAttr;
509*12c85518Srobert     if (Property->getPropertyAttributes() &
510*12c85518Srobert         ObjCPropertyAttribute::kind_readonly)
511*12c85518Srobert       Attributes |= ObjCPropertyRecord::ReadOnly;
512*12c85518Srobert 
513*12c85518Srobert     API.addObjCProperty(
514*12c85518Srobert         Container, Name, USR, Loc, AvailabilitySet(Property), Comment,
515*12c85518Srobert         Declaration, SubHeading,
516*12c85518Srobert         static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), GetterName,
517*12c85518Srobert         SetterName, Property->isOptional(),
518*12c85518Srobert         !(Property->getPropertyAttributes() &
519*12c85518Srobert           ObjCPropertyAttribute::kind_class),
520*12c85518Srobert         isInSystemHeader(Context, Property));
521*12c85518Srobert   }
522*12c85518Srobert }
523*12c85518Srobert 
recordObjCInstanceVariables(ObjCContainerRecord * Container,const llvm::iterator_range<DeclContext::specific_decl_iterator<ObjCIvarDecl>> Ivars)524*12c85518Srobert void ExtractAPIVisitor::recordObjCInstanceVariables(
525*12c85518Srobert     ObjCContainerRecord *Container,
526*12c85518Srobert     const llvm::iterator_range<
527*12c85518Srobert         DeclContext::specific_decl_iterator<ObjCIvarDecl>>
528*12c85518Srobert         Ivars) {
529*12c85518Srobert   for (const auto *Ivar : Ivars) {
530*12c85518Srobert     StringRef Name = Ivar->getName();
531*12c85518Srobert     StringRef USR = API.recordUSR(Ivar);
532*12c85518Srobert     PresumedLoc Loc =
533*12c85518Srobert         Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
534*12c85518Srobert     DocComment Comment;
535*12c85518Srobert     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
536*12c85518Srobert       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
537*12c85518Srobert                                               Context.getDiagnostics());
538*12c85518Srobert 
539*12c85518Srobert     // Build declaration fragments and sub-heading for the instance variable.
540*12c85518Srobert     DeclarationFragments Declaration =
541*12c85518Srobert         DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
542*12c85518Srobert     DeclarationFragments SubHeading =
543*12c85518Srobert         DeclarationFragmentsBuilder::getSubHeading(Ivar);
544*12c85518Srobert 
545*12c85518Srobert     ObjCInstanceVariableRecord::AccessControl Access =
546*12c85518Srobert         Ivar->getCanonicalAccessControl();
547*12c85518Srobert 
548*12c85518Srobert     API.addObjCInstanceVariable(
549*12c85518Srobert         Container, Name, USR, Loc, AvailabilitySet(Ivar), Comment, Declaration,
550*12c85518Srobert         SubHeading, Access, isInSystemHeader(Context, Ivar));
551*12c85518Srobert   }
552*12c85518Srobert }
553*12c85518Srobert 
recordObjCProtocols(ObjCContainerRecord * Container,ObjCInterfaceDecl::protocol_range Protocols)554*12c85518Srobert void ExtractAPIVisitor::recordObjCProtocols(
555*12c85518Srobert     ObjCContainerRecord *Container,
556*12c85518Srobert     ObjCInterfaceDecl::protocol_range Protocols) {
557*12c85518Srobert   for (const auto *Protocol : Protocols)
558*12c85518Srobert     Container->Protocols.emplace_back(Protocol->getName(),
559*12c85518Srobert                                       API.recordUSR(Protocol));
560*12c85518Srobert }
561