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