189f6b26fSZixu Wang //===- ExtractAPI/ExtractAPIConsumer.cpp ------------------------*- C++ -*-===//
289f6b26fSZixu Wang //
389f6b26fSZixu Wang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
489f6b26fSZixu Wang // See https://llvm.org/LICENSE.txt for license information.
589f6b26fSZixu Wang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
689f6b26fSZixu Wang //
789f6b26fSZixu Wang //===----------------------------------------------------------------------===//
889f6b26fSZixu Wang ///
989f6b26fSZixu Wang /// \file
1089f6b26fSZixu Wang /// This file implements the ExtractAPIAction, and ASTVisitor/Consumer to
1189f6b26fSZixu Wang /// collect API information.
1289f6b26fSZixu Wang ///
1389f6b26fSZixu Wang //===----------------------------------------------------------------------===//
1489f6b26fSZixu Wang 
1589f6b26fSZixu Wang #include "clang/AST/ASTConsumer.h"
1689f6b26fSZixu Wang #include "clang/AST/ASTContext.h"
1789f6b26fSZixu Wang #include "clang/AST/Decl.h"
1889f6b26fSZixu Wang #include "clang/AST/DeclCXX.h"
1989f6b26fSZixu Wang #include "clang/AST/ParentMapContext.h"
2089f6b26fSZixu Wang #include "clang/AST/RawCommentList.h"
2189f6b26fSZixu Wang #include "clang/AST/RecursiveASTVisitor.h"
2289f6b26fSZixu Wang #include "clang/Basic/TargetInfo.h"
2389f6b26fSZixu Wang #include "clang/ExtractAPI/API.h"
2489f6b26fSZixu Wang #include "clang/ExtractAPI/AvailabilityInfo.h"
2589f6b26fSZixu Wang #include "clang/ExtractAPI/DeclarationFragments.h"
2689f6b26fSZixu Wang #include "clang/ExtractAPI/FrontendActions.h"
2789f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
2889f6b26fSZixu Wang #include "clang/Frontend/ASTConsumers.h"
2989f6b26fSZixu Wang #include "clang/Frontend/CompilerInstance.h"
30*f833aab0SDaniel Grumberg #include "clang/Frontend/FrontendOptions.h"
31*f833aab0SDaniel Grumberg #include "llvm/ADT/SmallVector.h"
32*f833aab0SDaniel Grumberg #include "llvm/Support/MemoryBuffer.h"
3389f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h"
3489f6b26fSZixu Wang 
3589f6b26fSZixu Wang using namespace clang;
3689f6b26fSZixu Wang using namespace extractapi;
3789f6b26fSZixu Wang 
3889f6b26fSZixu Wang namespace {
3989f6b26fSZixu Wang 
4089f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API
4189f6b26fSZixu Wang /// information.
4289f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
4389f6b26fSZixu Wang public:
4489f6b26fSZixu Wang   explicit ExtractAPIVisitor(ASTContext &Context)
4589f6b26fSZixu Wang       : Context(Context),
4689f6b26fSZixu Wang         API(Context.getTargetInfo().getTriple(), Context.getLangOpts()) {}
4789f6b26fSZixu Wang 
4889f6b26fSZixu Wang   const APISet &getAPI() const { return API; }
4989f6b26fSZixu Wang 
5089f6b26fSZixu Wang   bool VisitVarDecl(const VarDecl *Decl) {
5189f6b26fSZixu Wang     // Skip function parameters.
5289f6b26fSZixu Wang     if (isa<ParmVarDecl>(Decl))
5389f6b26fSZixu Wang       return true;
5489f6b26fSZixu Wang 
5589f6b26fSZixu Wang     // Skip non-global variables in records (struct/union/class).
5689f6b26fSZixu Wang     if (Decl->getDeclContext()->isRecord())
5789f6b26fSZixu Wang       return true;
5889f6b26fSZixu Wang 
5989f6b26fSZixu Wang     // Skip local variables inside function or method.
6089f6b26fSZixu Wang     if (!Decl->isDefinedOutsideFunctionOrMethod())
6189f6b26fSZixu Wang       return true;
6289f6b26fSZixu Wang 
6389f6b26fSZixu Wang     // If this is a template but not specialization or instantiation, skip.
6489f6b26fSZixu Wang     if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
6589f6b26fSZixu Wang         Decl->getTemplateSpecializationKind() == TSK_Undeclared)
6689f6b26fSZixu Wang       return true;
6789f6b26fSZixu Wang 
6889f6b26fSZixu Wang     // Collect symbol information.
6989f6b26fSZixu Wang     StringRef Name = Decl->getName();
7089f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
7189f6b26fSZixu Wang     PresumedLoc Loc =
7289f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
7389f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
7489f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
7589f6b26fSZixu Wang     DocComment Comment;
7689f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
7789f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
7889f6b26fSZixu Wang                                               Context.getDiagnostics());
7989f6b26fSZixu Wang 
8089f6b26fSZixu Wang     // Build declaration fragments and sub-heading for the variable.
8189f6b26fSZixu Wang     DeclarationFragments Declaration =
8289f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
8389f6b26fSZixu Wang     DeclarationFragments SubHeading =
8489f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
8589f6b26fSZixu Wang 
8689f6b26fSZixu Wang     // Add the global variable record to the API set.
8789f6b26fSZixu Wang     API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment,
8889f6b26fSZixu Wang                      Declaration, SubHeading);
8989f6b26fSZixu Wang     return true;
9089f6b26fSZixu Wang   }
9189f6b26fSZixu Wang 
9289f6b26fSZixu Wang   bool VisitFunctionDecl(const FunctionDecl *Decl) {
9389f6b26fSZixu Wang     if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
9489f6b26fSZixu Wang       // Skip member function in class templates.
9589f6b26fSZixu Wang       if (Method->getParent()->getDescribedClassTemplate() != nullptr)
9689f6b26fSZixu Wang         return true;
9789f6b26fSZixu Wang 
9889f6b26fSZixu Wang       // Skip methods in records.
9989f6b26fSZixu Wang       for (auto P : Context.getParents(*Method)) {
10089f6b26fSZixu Wang         if (P.get<CXXRecordDecl>())
10189f6b26fSZixu Wang           return true;
10289f6b26fSZixu Wang       }
10389f6b26fSZixu Wang 
10489f6b26fSZixu Wang       // Skip ConstructorDecl and DestructorDecl.
10589f6b26fSZixu Wang       if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
10689f6b26fSZixu Wang         return true;
10789f6b26fSZixu Wang     }
10889f6b26fSZixu Wang 
10989f6b26fSZixu Wang     // Skip templated functions.
11089f6b26fSZixu Wang     switch (Decl->getTemplatedKind()) {
11189f6b26fSZixu Wang     case FunctionDecl::TK_NonTemplate:
11289f6b26fSZixu Wang       break;
11389f6b26fSZixu Wang     case FunctionDecl::TK_MemberSpecialization:
11489f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplateSpecialization:
11589f6b26fSZixu Wang       if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
11689f6b26fSZixu Wang         if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
11789f6b26fSZixu Wang           return true;
11889f6b26fSZixu Wang       }
11989f6b26fSZixu Wang       break;
12089f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplate:
12189f6b26fSZixu Wang     case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
12289f6b26fSZixu Wang       return true;
12389f6b26fSZixu Wang     }
12489f6b26fSZixu Wang 
12589f6b26fSZixu Wang     // Collect symbol information.
12689f6b26fSZixu Wang     StringRef Name = Decl->getName();
12789f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
12889f6b26fSZixu Wang     PresumedLoc Loc =
12989f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
13089f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
13189f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
13289f6b26fSZixu Wang     DocComment Comment;
13389f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
13489f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
13589f6b26fSZixu Wang                                               Context.getDiagnostics());
13689f6b26fSZixu Wang 
13789f6b26fSZixu Wang     // Build declaration fragments, sub-heading, and signature of the function.
13889f6b26fSZixu Wang     DeclarationFragments Declaration =
13989f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
14089f6b26fSZixu Wang     DeclarationFragments SubHeading =
14189f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
14289f6b26fSZixu Wang     FunctionSignature Signature =
14389f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFunctionSignature(Decl);
14489f6b26fSZixu Wang 
14589f6b26fSZixu Wang     // Add the function record to the API set.
14689f6b26fSZixu Wang     API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration,
14789f6b26fSZixu Wang                     SubHeading, Signature);
14889f6b26fSZixu Wang     return true;
14989f6b26fSZixu Wang   }
15089f6b26fSZixu Wang 
15171b4c226SZixu Wang   bool VisitEnumDecl(const EnumDecl *Decl) {
15271b4c226SZixu Wang     if (!Decl->isComplete())
15371b4c226SZixu Wang       return true;
15471b4c226SZixu Wang 
15571b4c226SZixu Wang     // Skip forward declaration.
15671b4c226SZixu Wang     if (!Decl->isThisDeclarationADefinition())
15771b4c226SZixu Wang       return true;
15871b4c226SZixu Wang 
15971b4c226SZixu Wang     // Collect symbol information.
16071b4c226SZixu Wang     StringRef Name = Decl->getName();
16171b4c226SZixu Wang     StringRef USR = API.recordUSR(Decl);
16271b4c226SZixu Wang     PresumedLoc Loc =
16371b4c226SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
16471b4c226SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
16571b4c226SZixu Wang     DocComment Comment;
16671b4c226SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
16771b4c226SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
16871b4c226SZixu Wang                                               Context.getDiagnostics());
16971b4c226SZixu Wang 
17071b4c226SZixu Wang     // Build declaration fragments and sub-heading for the enum.
17171b4c226SZixu Wang     DeclarationFragments Declaration =
17271b4c226SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
17371b4c226SZixu Wang     DeclarationFragments SubHeading =
17471b4c226SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
17571b4c226SZixu Wang 
17671b4c226SZixu Wang     EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment,
17771b4c226SZixu Wang                                          Declaration, SubHeading);
17871b4c226SZixu Wang 
17971b4c226SZixu Wang     // Now collect information about the enumerators in this enum.
18071b4c226SZixu Wang     recordEnumConstants(EnumRecord, Decl->enumerators());
18171b4c226SZixu Wang 
18271b4c226SZixu Wang     return true;
18371b4c226SZixu Wang   }
18471b4c226SZixu Wang 
1855bb5704cSZixu Wang   bool VisitRecordDecl(const RecordDecl *Decl) {
1865bb5704cSZixu Wang     if (!Decl->isCompleteDefinition())
1875bb5704cSZixu Wang       return true;
1885bb5704cSZixu Wang 
1895bb5704cSZixu Wang     // Skip C++ structs/classes/unions
1905bb5704cSZixu Wang     // TODO: support C++ records
1915bb5704cSZixu Wang     if (isa<CXXRecordDecl>(Decl))
1925bb5704cSZixu Wang       return true;
1935bb5704cSZixu Wang 
1945bb5704cSZixu Wang     // Collect symbol information.
1955bb5704cSZixu Wang     StringRef Name = Decl->getName();
1965bb5704cSZixu Wang     StringRef USR = API.recordUSR(Decl);
1975bb5704cSZixu Wang     PresumedLoc Loc =
1985bb5704cSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
1995bb5704cSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
2005bb5704cSZixu Wang     DocComment Comment;
2015bb5704cSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
2025bb5704cSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
2035bb5704cSZixu Wang                                               Context.getDiagnostics());
2045bb5704cSZixu Wang 
2055bb5704cSZixu Wang     // Build declaration fragments and sub-heading for the struct.
2065bb5704cSZixu Wang     DeclarationFragments Declaration =
2075bb5704cSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
2085bb5704cSZixu Wang     DeclarationFragments SubHeading =
2095bb5704cSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
2105bb5704cSZixu Wang 
2115bb5704cSZixu Wang     StructRecord *StructRecord = API.addStruct(
2125bb5704cSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
2135bb5704cSZixu Wang 
2145bb5704cSZixu Wang     // Now collect information about the fields in this struct.
2155bb5704cSZixu Wang     recordStructFields(StructRecord, Decl->fields());
2165bb5704cSZixu Wang 
2175bb5704cSZixu Wang     return true;
2185bb5704cSZixu Wang   }
2195bb5704cSZixu Wang 
22089f6b26fSZixu Wang private:
22189f6b26fSZixu Wang   /// Get availability information of the declaration \p D.
22289f6b26fSZixu Wang   AvailabilityInfo getAvailability(const Decl *D) const {
22389f6b26fSZixu Wang     StringRef PlatformName = Context.getTargetInfo().getPlatformName();
22489f6b26fSZixu Wang 
22589f6b26fSZixu Wang     AvailabilityInfo Availability;
22689f6b26fSZixu Wang     // Collect availability attributes from all redeclarations.
22789f6b26fSZixu Wang     for (const auto *RD : D->redecls()) {
22889f6b26fSZixu Wang       for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
22989f6b26fSZixu Wang         if (A->getPlatform()->getName() != PlatformName)
23089f6b26fSZixu Wang           continue;
23189f6b26fSZixu Wang         Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(),
23289f6b26fSZixu Wang                                         A->getObsoleted(), A->getUnavailable(),
23389f6b26fSZixu Wang                                         /* UnconditionallyDeprecated */ false,
23489f6b26fSZixu Wang                                         /* UnconditionallyUnavailable */ false);
23589f6b26fSZixu Wang         break;
23689f6b26fSZixu Wang       }
23789f6b26fSZixu Wang 
23889f6b26fSZixu Wang       if (const auto *A = RD->getAttr<UnavailableAttr>())
23989f6b26fSZixu Wang         if (!A->isImplicit()) {
24089f6b26fSZixu Wang           Availability.Unavailable = true;
24189f6b26fSZixu Wang           Availability.UnconditionallyUnavailable = true;
24289f6b26fSZixu Wang         }
24389f6b26fSZixu Wang 
24489f6b26fSZixu Wang       if (const auto *A = RD->getAttr<DeprecatedAttr>())
24589f6b26fSZixu Wang         if (!A->isImplicit())
24689f6b26fSZixu Wang           Availability.UnconditionallyDeprecated = true;
24789f6b26fSZixu Wang     }
24889f6b26fSZixu Wang 
24989f6b26fSZixu Wang     return Availability;
25089f6b26fSZixu Wang   }
25189f6b26fSZixu Wang 
25271b4c226SZixu Wang   /// Collect API information for the enum constants and associate with the
25371b4c226SZixu Wang   /// parent enum.
25471b4c226SZixu Wang   void recordEnumConstants(EnumRecord *EnumRecord,
25571b4c226SZixu Wang                            const EnumDecl::enumerator_range Constants) {
25671b4c226SZixu Wang     for (const auto *Constant : Constants) {
25771b4c226SZixu Wang       // Collect symbol information.
25871b4c226SZixu Wang       StringRef Name = Constant->getName();
25971b4c226SZixu Wang       StringRef USR = API.recordUSR(Constant);
26071b4c226SZixu Wang       PresumedLoc Loc =
26171b4c226SZixu Wang           Context.getSourceManager().getPresumedLoc(Constant->getLocation());
26271b4c226SZixu Wang       AvailabilityInfo Availability = getAvailability(Constant);
26371b4c226SZixu Wang       DocComment Comment;
26471b4c226SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
26571b4c226SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
26671b4c226SZixu Wang                                                 Context.getDiagnostics());
26771b4c226SZixu Wang 
26871b4c226SZixu Wang       // Build declaration fragments and sub-heading for the enum constant.
26971b4c226SZixu Wang       DeclarationFragments Declaration =
27071b4c226SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
27171b4c226SZixu Wang       DeclarationFragments SubHeading =
27271b4c226SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Constant);
27371b4c226SZixu Wang 
27471b4c226SZixu Wang       API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
27571b4c226SZixu Wang                           Declaration, SubHeading);
27671b4c226SZixu Wang     }
27771b4c226SZixu Wang   }
27871b4c226SZixu Wang 
2795bb5704cSZixu Wang   /// Collect API information for the struct fields and associate with the
2805bb5704cSZixu Wang   /// parent struct.
2815bb5704cSZixu Wang   void recordStructFields(StructRecord *StructRecord,
2825bb5704cSZixu Wang                           const RecordDecl::field_range Fields) {
2835bb5704cSZixu Wang     for (const auto *Field : Fields) {
2845bb5704cSZixu Wang       // Collect symbol information.
2855bb5704cSZixu Wang       StringRef Name = Field->getName();
2865bb5704cSZixu Wang       StringRef USR = API.recordUSR(Field);
2875bb5704cSZixu Wang       PresumedLoc Loc =
2885bb5704cSZixu Wang           Context.getSourceManager().getPresumedLoc(Field->getLocation());
2895bb5704cSZixu Wang       AvailabilityInfo Availability = getAvailability(Field);
2905bb5704cSZixu Wang       DocComment Comment;
2915bb5704cSZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
2925bb5704cSZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
2935bb5704cSZixu Wang                                                 Context.getDiagnostics());
2945bb5704cSZixu Wang 
2955bb5704cSZixu Wang       // Build declaration fragments and sub-heading for the struct field.
2965bb5704cSZixu Wang       DeclarationFragments Declaration =
2975bb5704cSZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Field);
2985bb5704cSZixu Wang       DeclarationFragments SubHeading =
2995bb5704cSZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Field);
3005bb5704cSZixu Wang 
3015bb5704cSZixu Wang       API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
3025bb5704cSZixu Wang                          Declaration, SubHeading);
3035bb5704cSZixu Wang     }
3045bb5704cSZixu Wang   }
3055bb5704cSZixu Wang 
30689f6b26fSZixu Wang   ASTContext &Context;
30789f6b26fSZixu Wang   APISet API;
30889f6b26fSZixu Wang };
30989f6b26fSZixu Wang 
31089f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer {
31189f6b26fSZixu Wang public:
3125ef2ec7eSDaniel Grumberg   ExtractAPIConsumer(ASTContext &Context, StringRef ProductName,
3135ef2ec7eSDaniel Grumberg                      std::unique_ptr<raw_pwrite_stream> OS)
3145ef2ec7eSDaniel Grumberg       : Visitor(Context), ProductName(ProductName), OS(std::move(OS)) {}
31589f6b26fSZixu Wang 
31689f6b26fSZixu Wang   void HandleTranslationUnit(ASTContext &Context) override {
31789f6b26fSZixu Wang     // Use ExtractAPIVisitor to traverse symbol declarations in the context.
31889f6b26fSZixu Wang     Visitor.TraverseDecl(Context.getTranslationUnitDecl());
31989f6b26fSZixu Wang 
32089f6b26fSZixu Wang     // Setup a SymbolGraphSerializer to write out collected API information in
32189f6b26fSZixu Wang     // the Symbol Graph format.
32289f6b26fSZixu Wang     // FIXME: Make the kind of APISerializer configurable.
3235ef2ec7eSDaniel Grumberg     SymbolGraphSerializer SGSerializer(Visitor.getAPI(), ProductName);
32489f6b26fSZixu Wang     SGSerializer.serialize(*OS);
32589f6b26fSZixu Wang   }
32689f6b26fSZixu Wang 
32789f6b26fSZixu Wang private:
32889f6b26fSZixu Wang   ExtractAPIVisitor Visitor;
3295ef2ec7eSDaniel Grumberg   std::string ProductName;
33089f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS;
33189f6b26fSZixu Wang };
33289f6b26fSZixu Wang 
33389f6b26fSZixu Wang } // namespace
33489f6b26fSZixu Wang 
33589f6b26fSZixu Wang std::unique_ptr<ASTConsumer>
33689f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
33789f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile);
33889f6b26fSZixu Wang   if (!OS)
33989f6b26fSZixu Wang     return nullptr;
3405ef2ec7eSDaniel Grumberg   return std::make_unique<ExtractAPIConsumer>(
3415ef2ec7eSDaniel Grumberg       CI.getASTContext(), CI.getInvocation().getFrontendOpts().ProductName,
34289f6b26fSZixu Wang       std::move(OS));
34389f6b26fSZixu Wang }
34489f6b26fSZixu Wang 
345*f833aab0SDaniel Grumberg bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) {
346*f833aab0SDaniel Grumberg   auto &Inputs = CI.getFrontendOpts().Inputs;
347*f833aab0SDaniel Grumberg   if (Inputs.empty())
348*f833aab0SDaniel Grumberg     return true;
349*f833aab0SDaniel Grumberg 
350*f833aab0SDaniel Grumberg   auto Kind = Inputs[0].getKind();
351*f833aab0SDaniel Grumberg 
352*f833aab0SDaniel Grumberg   // Convert the header file inputs into a single input buffer.
353*f833aab0SDaniel Grumberg   SmallString<256> HeaderContents;
354*f833aab0SDaniel Grumberg   for (const FrontendInputFile &FIF : Inputs) {
355*f833aab0SDaniel Grumberg     if (Kind.isObjectiveC())
356*f833aab0SDaniel Grumberg       HeaderContents += "#import";
357*f833aab0SDaniel Grumberg     else
358*f833aab0SDaniel Grumberg       HeaderContents += "#include";
359*f833aab0SDaniel Grumberg     HeaderContents += " \"";
360*f833aab0SDaniel Grumberg     HeaderContents += FIF.getFile();
361*f833aab0SDaniel Grumberg     HeaderContents += "\"\n";
362*f833aab0SDaniel Grumberg   }
363*f833aab0SDaniel Grumberg 
364*f833aab0SDaniel Grumberg   Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
365*f833aab0SDaniel Grumberg                                                 getInputBufferName());
366*f833aab0SDaniel Grumberg 
367*f833aab0SDaniel Grumberg   // Set that buffer up as our "real" input in the CompilerInstance.
368*f833aab0SDaniel Grumberg   Inputs.clear();
369*f833aab0SDaniel Grumberg   Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false);
370*f833aab0SDaniel Grumberg 
371*f833aab0SDaniel Grumberg   return true;
372*f833aab0SDaniel Grumberg }
373*f833aab0SDaniel Grumberg 
37489f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream>
37589f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
37689f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS =
37789f6b26fSZixu Wang       CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json",
37889f6b26fSZixu Wang                                  /*RemoveFileOnSignal=*/false);
37989f6b26fSZixu Wang   if (!OS)
38089f6b26fSZixu Wang     return nullptr;
38189f6b26fSZixu Wang   return OS;
38289f6b26fSZixu Wang }
383