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