1 //===- ExtractAPI/ExtractAPIConsumer.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 ExtractAPIAction, and ASTVisitor/Consumer to
11 /// collect API information.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "clang/AST/ASTConsumer.h"
16 #include "clang/AST/ASTContext.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/DeclCXX.h"
19 #include "clang/AST/ParentMapContext.h"
20 #include "clang/AST/RawCommentList.h"
21 #include "clang/AST/RecursiveASTVisitor.h"
22 #include "clang/Basic/TargetInfo.h"
23 #include "clang/ExtractAPI/API.h"
24 #include "clang/ExtractAPI/AvailabilityInfo.h"
25 #include "clang/ExtractAPI/DeclarationFragments.h"
26 #include "clang/ExtractAPI/FrontendActions.h"
27 #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
28 #include "clang/Frontend/ASTConsumers.h"
29 #include "clang/Frontend/CompilerInstance.h"
30 #include "clang/Frontend/FrontendOptions.h"
31 #include "clang/Lex/MacroInfo.h"
32 #include "clang/Lex/PPCallbacks.h"
33 #include "clang/Lex/PreprocessorOptions.h"
34 #include "llvm/ADT/STLExtras.h"
35 #include "llvm/ADT/SmallVector.h"
36 #include "llvm/Support/MemoryBuffer.h"
37 #include "llvm/Support/raw_ostream.h"
38 
39 using namespace clang;
40 using namespace extractapi;
41 
42 namespace {
43 
44 /// The RecursiveASTVisitor to traverse symbol declarations and collect API
45 /// information.
46 class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
47 public:
48   ExtractAPIVisitor(ASTContext &Context, APISet &API)
49       : Context(Context), API(API) {}
50 
51   const APISet &getAPI() const { return API; }
52 
53   bool 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     // Collect symbol information.
72     StringRef Name = Decl->getName();
73     StringRef USR = API.recordUSR(Decl);
74     PresumedLoc Loc =
75         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
76     AvailabilityInfo Availability = getAvailability(Decl);
77     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
78     DocComment Comment;
79     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
80       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
81                                               Context.getDiagnostics());
82 
83     // Build declaration fragments and sub-heading for the variable.
84     DeclarationFragments Declaration =
85         DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
86     DeclarationFragments SubHeading =
87         DeclarationFragmentsBuilder::getSubHeading(Decl);
88 
89     // Add the global variable record to the API set.
90     API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment,
91                      Declaration, SubHeading);
92     return true;
93   }
94 
95   bool VisitFunctionDecl(const FunctionDecl *Decl) {
96     if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
97       // Skip member function in class templates.
98       if (Method->getParent()->getDescribedClassTemplate() != nullptr)
99         return true;
100 
101       // Skip methods in records.
102       for (auto P : Context.getParents(*Method)) {
103         if (P.get<CXXRecordDecl>())
104           return true;
105       }
106 
107       // Skip ConstructorDecl and DestructorDecl.
108       if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
109         return true;
110     }
111 
112     // Skip templated functions.
113     switch (Decl->getTemplatedKind()) {
114     case FunctionDecl::TK_NonTemplate:
115       break;
116     case FunctionDecl::TK_MemberSpecialization:
117     case FunctionDecl::TK_FunctionTemplateSpecialization:
118       if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
119         if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
120           return true;
121       }
122       break;
123     case FunctionDecl::TK_FunctionTemplate:
124     case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
125       return true;
126     }
127 
128     // Collect symbol information.
129     StringRef Name = Decl->getName();
130     StringRef USR = API.recordUSR(Decl);
131     PresumedLoc Loc =
132         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
133     AvailabilityInfo Availability = getAvailability(Decl);
134     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
135     DocComment Comment;
136     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
137       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
138                                               Context.getDiagnostics());
139 
140     // Build declaration fragments, sub-heading, and signature of the function.
141     DeclarationFragments Declaration =
142         DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
143     DeclarationFragments SubHeading =
144         DeclarationFragmentsBuilder::getSubHeading(Decl);
145     FunctionSignature Signature =
146         DeclarationFragmentsBuilder::getFunctionSignature(Decl);
147 
148     // Add the function record to the API set.
149     API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration,
150                     SubHeading, Signature);
151     return true;
152   }
153 
154   bool VisitEnumDecl(const EnumDecl *Decl) {
155     if (!Decl->isComplete())
156       return true;
157 
158     // Skip forward declaration.
159     if (!Decl->isThisDeclarationADefinition())
160       return true;
161 
162     // Collect symbol information.
163     StringRef Name = Decl->getName();
164     StringRef USR = API.recordUSR(Decl);
165     PresumedLoc Loc =
166         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
167     AvailabilityInfo Availability = getAvailability(Decl);
168     DocComment Comment;
169     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
170       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
171                                               Context.getDiagnostics());
172 
173     // Build declaration fragments and sub-heading for the enum.
174     DeclarationFragments Declaration =
175         DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
176     DeclarationFragments SubHeading =
177         DeclarationFragmentsBuilder::getSubHeading(Decl);
178 
179     EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment,
180                                          Declaration, SubHeading);
181 
182     // Now collect information about the enumerators in this enum.
183     recordEnumConstants(EnumRecord, Decl->enumerators());
184 
185     return true;
186   }
187 
188   bool VisitRecordDecl(const RecordDecl *Decl) {
189     if (!Decl->isCompleteDefinition())
190       return true;
191 
192     // Skip C++ structs/classes/unions
193     // TODO: support C++ records
194     if (isa<CXXRecordDecl>(Decl))
195       return true;
196 
197     // Collect symbol information.
198     StringRef Name = Decl->getName();
199     StringRef USR = API.recordUSR(Decl);
200     PresumedLoc Loc =
201         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
202     AvailabilityInfo Availability = getAvailability(Decl);
203     DocComment Comment;
204     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
205       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
206                                               Context.getDiagnostics());
207 
208     // Build declaration fragments and sub-heading for the struct.
209     DeclarationFragments Declaration =
210         DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
211     DeclarationFragments SubHeading =
212         DeclarationFragmentsBuilder::getSubHeading(Decl);
213 
214     StructRecord *StructRecord = API.addStruct(
215         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
216 
217     // Now collect information about the fields in this struct.
218     recordStructFields(StructRecord, Decl->fields());
219 
220     return true;
221   }
222 
223   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
224     // Skip forward declaration for classes (@class)
225     if (!Decl->isThisDeclarationADefinition())
226       return true;
227 
228     // Collect symbol information.
229     StringRef Name = Decl->getName();
230     StringRef USR = API.recordUSR(Decl);
231     PresumedLoc Loc =
232         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
233     AvailabilityInfo Availability = getAvailability(Decl);
234     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
235     DocComment Comment;
236     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
237       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
238                                               Context.getDiagnostics());
239 
240     // Build declaration fragments and sub-heading for the interface.
241     DeclarationFragments Declaration =
242         DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
243     DeclarationFragments SubHeading =
244         DeclarationFragmentsBuilder::getSubHeading(Decl);
245 
246     // Collect super class information.
247     SymbolReference SuperClass;
248     if (const auto *SuperClassDecl = Decl->getSuperClass()) {
249       SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
250       SuperClass.USR = API.recordUSR(SuperClassDecl);
251     }
252 
253     ObjCInterfaceRecord *ObjCInterfaceRecord =
254         API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment,
255                              Declaration, SubHeading, SuperClass);
256 
257     // Record all methods (selectors). This doesn't include automatically
258     // synthesized property methods.
259     recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
260     recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
261     recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
262     recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
263 
264     return true;
265   }
266 
267   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) {
268     // Skip forward declaration for protocols (@protocol).
269     if (!Decl->isThisDeclarationADefinition())
270       return true;
271 
272     // Collect symbol information.
273     StringRef Name = Decl->getName();
274     StringRef USR = API.recordUSR(Decl);
275     PresumedLoc Loc =
276         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
277     AvailabilityInfo Availability = getAvailability(Decl);
278     DocComment Comment;
279     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
280       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
281                                               Context.getDiagnostics());
282 
283     // Build declaration fragments and sub-heading for the protocol.
284     DeclarationFragments Declaration =
285         DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
286     DeclarationFragments SubHeading =
287         DeclarationFragmentsBuilder::getSubHeading(Decl);
288 
289     ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
290         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
291 
292     recordObjCMethods(ObjCProtocolRecord, Decl->methods());
293     recordObjCProperties(ObjCProtocolRecord, Decl->properties());
294     recordObjCProtocols(ObjCProtocolRecord, Decl->protocols());
295 
296     return true;
297   }
298 
299 private:
300   /// Get availability information of the declaration \p D.
301   AvailabilityInfo getAvailability(const Decl *D) const {
302     StringRef PlatformName = Context.getTargetInfo().getPlatformName();
303 
304     AvailabilityInfo Availability;
305     // Collect availability attributes from all redeclarations.
306     for (const auto *RD : D->redecls()) {
307       for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
308         if (A->getPlatform()->getName() != PlatformName)
309           continue;
310         Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(),
311                                         A->getObsoleted(), A->getUnavailable(),
312                                         /* UnconditionallyDeprecated */ false,
313                                         /* UnconditionallyUnavailable */ false);
314         break;
315       }
316 
317       if (const auto *A = RD->getAttr<UnavailableAttr>())
318         if (!A->isImplicit()) {
319           Availability.Unavailable = true;
320           Availability.UnconditionallyUnavailable = true;
321         }
322 
323       if (const auto *A = RD->getAttr<DeprecatedAttr>())
324         if (!A->isImplicit())
325           Availability.UnconditionallyDeprecated = true;
326     }
327 
328     return Availability;
329   }
330 
331   /// Collect API information for the enum constants and associate with the
332   /// parent enum.
333   void recordEnumConstants(EnumRecord *EnumRecord,
334                            const EnumDecl::enumerator_range Constants) {
335     for (const auto *Constant : Constants) {
336       // Collect symbol information.
337       StringRef Name = Constant->getName();
338       StringRef USR = API.recordUSR(Constant);
339       PresumedLoc Loc =
340           Context.getSourceManager().getPresumedLoc(Constant->getLocation());
341       AvailabilityInfo Availability = getAvailability(Constant);
342       DocComment Comment;
343       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
344         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
345                                                 Context.getDiagnostics());
346 
347       // Build declaration fragments and sub-heading for the enum constant.
348       DeclarationFragments Declaration =
349           DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
350       DeclarationFragments SubHeading =
351           DeclarationFragmentsBuilder::getSubHeading(Constant);
352 
353       API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
354                           Declaration, SubHeading);
355     }
356   }
357 
358   /// Collect API information for the struct fields and associate with the
359   /// parent struct.
360   void recordStructFields(StructRecord *StructRecord,
361                           const RecordDecl::field_range Fields) {
362     for (const auto *Field : Fields) {
363       // Collect symbol information.
364       StringRef Name = Field->getName();
365       StringRef USR = API.recordUSR(Field);
366       PresumedLoc Loc =
367           Context.getSourceManager().getPresumedLoc(Field->getLocation());
368       AvailabilityInfo Availability = getAvailability(Field);
369       DocComment Comment;
370       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
371         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
372                                                 Context.getDiagnostics());
373 
374       // Build declaration fragments and sub-heading for the struct field.
375       DeclarationFragments Declaration =
376           DeclarationFragmentsBuilder::getFragmentsForField(Field);
377       DeclarationFragments SubHeading =
378           DeclarationFragmentsBuilder::getSubHeading(Field);
379 
380       API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
381                          Declaration, SubHeading);
382     }
383   }
384 
385   /// Collect API information for the Objective-C methods and associate with the
386   /// parent container.
387   void recordObjCMethods(ObjCContainerRecord *Container,
388                          const ObjCContainerDecl::method_range Methods) {
389     for (const auto *Method : Methods) {
390       // Don't record selectors for properties.
391       if (Method->isPropertyAccessor())
392         continue;
393 
394       StringRef Name = API.copyString(Method->getSelector().getAsString());
395       StringRef USR = API.recordUSR(Method);
396       PresumedLoc Loc =
397           Context.getSourceManager().getPresumedLoc(Method->getLocation());
398       AvailabilityInfo Availability = getAvailability(Method);
399       DocComment Comment;
400       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
401         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
402                                                 Context.getDiagnostics());
403 
404       // Build declaration fragments, sub-heading, and signature for the method.
405       DeclarationFragments Declaration =
406           DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
407       DeclarationFragments SubHeading =
408           DeclarationFragmentsBuilder::getSubHeading(Method);
409       FunctionSignature Signature =
410           DeclarationFragmentsBuilder::getFunctionSignature(Method);
411 
412       API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment,
413                         Declaration, SubHeading, Signature,
414                         Method->isInstanceMethod());
415     }
416   }
417 
418   void recordObjCProperties(ObjCContainerRecord *Container,
419                             const ObjCContainerDecl::prop_range Properties) {
420     for (const auto *Property : Properties) {
421       StringRef Name = Property->getName();
422       StringRef USR = API.recordUSR(Property);
423       PresumedLoc Loc =
424           Context.getSourceManager().getPresumedLoc(Property->getLocation());
425       AvailabilityInfo Availability = getAvailability(Property);
426       DocComment Comment;
427       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
428         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
429                                                 Context.getDiagnostics());
430 
431       // Build declaration fragments and sub-heading for the property.
432       DeclarationFragments Declaration =
433           DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
434       DeclarationFragments SubHeading =
435           DeclarationFragmentsBuilder::getSubHeading(Property);
436 
437       StringRef GetterName =
438           API.copyString(Property->getGetterName().getAsString());
439       StringRef SetterName =
440           API.copyString(Property->getSetterName().getAsString());
441 
442       // Get the attributes for property.
443       unsigned Attributes = ObjCPropertyRecord::NoAttr;
444       if (Property->getPropertyAttributes() &
445           ObjCPropertyAttribute::kind_readonly)
446         Attributes |= ObjCPropertyRecord::ReadOnly;
447       if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class)
448         Attributes |= ObjCPropertyRecord::Class;
449 
450       API.addObjCProperty(
451           Container, Name, USR, Loc, Availability, Comment, Declaration,
452           SubHeading,
453           static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
454           GetterName, SetterName, Property->isOptional());
455     }
456   }
457 
458   void recordObjCInstanceVariables(
459       ObjCContainerRecord *Container,
460       const llvm::iterator_range<
461           DeclContext::specific_decl_iterator<ObjCIvarDecl>>
462           Ivars) {
463     for (const auto *Ivar : Ivars) {
464       StringRef Name = Ivar->getName();
465       StringRef USR = API.recordUSR(Ivar);
466       PresumedLoc Loc =
467           Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
468       AvailabilityInfo Availability = getAvailability(Ivar);
469       DocComment Comment;
470       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
471         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
472                                                 Context.getDiagnostics());
473 
474       // Build declaration fragments and sub-heading for the instance variable.
475       DeclarationFragments Declaration =
476           DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
477       DeclarationFragments SubHeading =
478           DeclarationFragmentsBuilder::getSubHeading(Ivar);
479 
480       ObjCInstanceVariableRecord::AccessControl Access =
481           Ivar->getCanonicalAccessControl();
482 
483       API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability,
484                                   Comment, Declaration, SubHeading, Access);
485     }
486   }
487 
488   void recordObjCProtocols(ObjCContainerRecord *Container,
489                            ObjCInterfaceDecl::protocol_range Protocols) {
490     for (const auto *Protocol : Protocols)
491       Container->Protocols.emplace_back(Protocol->getName(),
492                                         API.recordUSR(Protocol));
493   }
494 
495   ASTContext &Context;
496   APISet &API;
497 };
498 
499 class ExtractAPIConsumer : public ASTConsumer {
500 public:
501   ExtractAPIConsumer(ASTContext &Context, APISet &API)
502       : Visitor(Context, API) {}
503 
504   void HandleTranslationUnit(ASTContext &Context) override {
505     // Use ExtractAPIVisitor to traverse symbol declarations in the context.
506     Visitor.TraverseDecl(Context.getTranslationUnitDecl());
507   }
508 
509 private:
510   ExtractAPIVisitor Visitor;
511 };
512 
513 class MacroCallback : public PPCallbacks {
514 public:
515   MacroCallback(const SourceManager &SM, APISet &API) : SM(SM), API(API) {}
516 
517   void MacroDefined(const Token &MacroNameToken,
518                     const MacroDirective *MD) override {
519     auto *MacroInfo = MD->getMacroInfo();
520 
521     if (MacroInfo->isBuiltinMacro())
522       return;
523 
524     auto SourceLoc = MacroNameToken.getLocation();
525     if (SM.isWrittenInBuiltinFile(SourceLoc) ||
526         SM.isWrittenInCommandLineFile(SourceLoc))
527       return;
528 
529     PendingMacros.emplace_back(MacroNameToken, MD);
530   }
531 
532   // If a macro gets undefined at some point during preprocessing of the inputs
533   // it means that it isn't an exposed API and we should therefore not add a
534   // macro definition for it.
535   void MacroUndefined(const Token &MacroNameToken, const MacroDefinition &MD,
536                       const MacroDirective *Undef) override {
537     llvm::erase_if(PendingMacros, [&MD](const PendingMacro &PM) {
538       return MD.getMacroInfo()->getDefinitionLoc() ==
539              PM.MD->getMacroInfo()->getDefinitionLoc();
540     });
541   }
542 
543   void EndOfMainFile() override {
544     for (auto &PM : PendingMacros) {
545       // `isUsedForHeaderGuard` is only set when the preprocessor leaves the
546       // file so check for it here.
547       if (PM.MD->getMacroInfo()->isUsedForHeaderGuard())
548         continue;
549 
550       StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName();
551       PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation());
552       StringRef USR =
553           API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM);
554 
555       API.addMacroDefinition(
556           Name, USR, Loc,
557           DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD),
558           DeclarationFragmentsBuilder::getSubHeadingForMacro(Name));
559     }
560 
561     PendingMacros.clear();
562   }
563 
564 private:
565   struct PendingMacro {
566     Token MacroNameToken;
567     const MacroDirective *MD;
568 
569     PendingMacro(const Token &MacroNameToken, const MacroDirective *MD)
570         : MacroNameToken(MacroNameToken), MD(MD) {}
571   };
572 
573   const SourceManager &SM;
574   APISet &API;
575   llvm::SmallVector<PendingMacro> PendingMacros;
576 };
577 
578 } // namespace
579 
580 std::unique_ptr<ASTConsumer>
581 ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
582   OS = CreateOutputFile(CI, InFile);
583   if (!OS)
584     return nullptr;
585 
586   ProductName = CI.getFrontendOpts().ProductName;
587 
588   // Now that we have enough information about the language options and the
589   // target triple, let's create the APISet before anyone uses it.
590   API = std::make_unique<APISet>(
591       CI.getTarget().getTriple(),
592       CI.getFrontendOpts().Inputs.back().getKind().getLanguage());
593 
594   // Register preprocessor callbacks that will add macro definitions to API.
595   CI.getPreprocessor().addPPCallbacks(
596       std::make_unique<MacroCallback>(CI.getSourceManager(), *API));
597 
598   return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(), *API);
599 }
600 
601 bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) {
602   auto &Inputs = CI.getFrontendOpts().Inputs;
603   if (Inputs.empty())
604     return true;
605 
606   auto Kind = Inputs[0].getKind();
607 
608   // Convert the header file inputs into a single input buffer.
609   SmallString<256> HeaderContents;
610   for (const FrontendInputFile &FIF : Inputs) {
611     if (Kind.isObjectiveC())
612       HeaderContents += "#import";
613     else
614       HeaderContents += "#include";
615     HeaderContents += " \"";
616     HeaderContents += FIF.getFile();
617     HeaderContents += "\"\n";
618   }
619 
620   Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
621                                                 getInputBufferName());
622 
623   // Set that buffer up as our "real" input in the CompilerInstance.
624   Inputs.clear();
625   Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false);
626 
627   return true;
628 }
629 
630 void ExtractAPIAction::EndSourceFileAction() {
631   if (!OS)
632     return;
633 
634   // Setup a SymbolGraphSerializer to write out collected API information in
635   // the Symbol Graph format.
636   // FIXME: Make the kind of APISerializer configurable.
637   SymbolGraphSerializer SGSerializer(*API, ProductName);
638   SGSerializer.serialize(*OS);
639   OS->flush();
640 }
641 
642 std::unique_ptr<raw_pwrite_stream>
643 ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
644   std::unique_ptr<raw_pwrite_stream> OS =
645       CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json",
646                                  /*RemoveFileOnSignal=*/false);
647   if (!OS)
648     return nullptr;
649   return OS;
650 }
651