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