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"
3089f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h"
3189f6b26fSZixu Wang 
3289f6b26fSZixu Wang using namespace clang;
3389f6b26fSZixu Wang using namespace extractapi;
3489f6b26fSZixu Wang 
3589f6b26fSZixu Wang namespace {
3689f6b26fSZixu Wang 
3789f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API
3889f6b26fSZixu Wang /// information.
3989f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
4089f6b26fSZixu Wang public:
4189f6b26fSZixu Wang   explicit ExtractAPIVisitor(ASTContext &Context)
4289f6b26fSZixu Wang       : Context(Context),
4389f6b26fSZixu Wang         API(Context.getTargetInfo().getTriple(), Context.getLangOpts()) {}
4489f6b26fSZixu Wang 
4589f6b26fSZixu Wang   const APISet &getAPI() const { return API; }
4689f6b26fSZixu Wang 
4789f6b26fSZixu Wang   bool VisitVarDecl(const VarDecl *Decl) {
4889f6b26fSZixu Wang     // Skip function parameters.
4989f6b26fSZixu Wang     if (isa<ParmVarDecl>(Decl))
5089f6b26fSZixu Wang       return true;
5189f6b26fSZixu Wang 
5289f6b26fSZixu Wang     // Skip non-global variables in records (struct/union/class).
5389f6b26fSZixu Wang     if (Decl->getDeclContext()->isRecord())
5489f6b26fSZixu Wang       return true;
5589f6b26fSZixu Wang 
5689f6b26fSZixu Wang     // Skip local variables inside function or method.
5789f6b26fSZixu Wang     if (!Decl->isDefinedOutsideFunctionOrMethod())
5889f6b26fSZixu Wang       return true;
5989f6b26fSZixu Wang 
6089f6b26fSZixu Wang     // If this is a template but not specialization or instantiation, skip.
6189f6b26fSZixu Wang     if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
6289f6b26fSZixu Wang         Decl->getTemplateSpecializationKind() == TSK_Undeclared)
6389f6b26fSZixu Wang       return true;
6489f6b26fSZixu Wang 
6589f6b26fSZixu Wang     // Collect symbol information.
6689f6b26fSZixu Wang     StringRef Name = Decl->getName();
6789f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
6889f6b26fSZixu Wang     PresumedLoc Loc =
6989f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
7089f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
7189f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
7289f6b26fSZixu Wang     DocComment Comment;
7389f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
7489f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
7589f6b26fSZixu Wang                                               Context.getDiagnostics());
7689f6b26fSZixu Wang 
7789f6b26fSZixu Wang     // Build declaration fragments and sub-heading for the variable.
7889f6b26fSZixu Wang     DeclarationFragments Declaration =
7989f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
8089f6b26fSZixu Wang     DeclarationFragments SubHeading =
8189f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
8289f6b26fSZixu Wang 
8389f6b26fSZixu Wang     // Add the global variable record to the API set.
8489f6b26fSZixu Wang     API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment,
8589f6b26fSZixu Wang                      Declaration, SubHeading);
8689f6b26fSZixu Wang     return true;
8789f6b26fSZixu Wang   }
8889f6b26fSZixu Wang 
8989f6b26fSZixu Wang   bool VisitFunctionDecl(const FunctionDecl *Decl) {
9089f6b26fSZixu Wang     if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
9189f6b26fSZixu Wang       // Skip member function in class templates.
9289f6b26fSZixu Wang       if (Method->getParent()->getDescribedClassTemplate() != nullptr)
9389f6b26fSZixu Wang         return true;
9489f6b26fSZixu Wang 
9589f6b26fSZixu Wang       // Skip methods in records.
9689f6b26fSZixu Wang       for (auto P : Context.getParents(*Method)) {
9789f6b26fSZixu Wang         if (P.get<CXXRecordDecl>())
9889f6b26fSZixu Wang           return true;
9989f6b26fSZixu Wang       }
10089f6b26fSZixu Wang 
10189f6b26fSZixu Wang       // Skip ConstructorDecl and DestructorDecl.
10289f6b26fSZixu Wang       if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
10389f6b26fSZixu Wang         return true;
10489f6b26fSZixu Wang     }
10589f6b26fSZixu Wang 
10689f6b26fSZixu Wang     // Skip templated functions.
10789f6b26fSZixu Wang     switch (Decl->getTemplatedKind()) {
10889f6b26fSZixu Wang     case FunctionDecl::TK_NonTemplate:
10989f6b26fSZixu Wang       break;
11089f6b26fSZixu Wang     case FunctionDecl::TK_MemberSpecialization:
11189f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplateSpecialization:
11289f6b26fSZixu Wang       if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
11389f6b26fSZixu Wang         if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
11489f6b26fSZixu Wang           return true;
11589f6b26fSZixu Wang       }
11689f6b26fSZixu Wang       break;
11789f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplate:
11889f6b26fSZixu Wang     case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
11989f6b26fSZixu Wang       return true;
12089f6b26fSZixu Wang     }
12189f6b26fSZixu Wang 
12289f6b26fSZixu Wang     // Collect symbol information.
12389f6b26fSZixu Wang     StringRef Name = Decl->getName();
12489f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
12589f6b26fSZixu Wang     PresumedLoc Loc =
12689f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
12789f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
12889f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
12989f6b26fSZixu Wang     DocComment Comment;
13089f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
13189f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
13289f6b26fSZixu Wang                                               Context.getDiagnostics());
13389f6b26fSZixu Wang 
13489f6b26fSZixu Wang     // Build declaration fragments, sub-heading, and signature of the function.
13589f6b26fSZixu Wang     DeclarationFragments Declaration =
13689f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
13789f6b26fSZixu Wang     DeclarationFragments SubHeading =
13889f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
13989f6b26fSZixu Wang     FunctionSignature Signature =
14089f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFunctionSignature(Decl);
14189f6b26fSZixu Wang 
14289f6b26fSZixu Wang     // Add the function record to the API set.
14389f6b26fSZixu Wang     API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration,
14489f6b26fSZixu Wang                     SubHeading, Signature);
14589f6b26fSZixu Wang     return true;
14689f6b26fSZixu Wang   }
14789f6b26fSZixu Wang 
14871b4c226SZixu Wang   bool VisitEnumDecl(const EnumDecl *Decl) {
14971b4c226SZixu Wang     if (!Decl->isComplete())
15071b4c226SZixu Wang       return true;
15171b4c226SZixu Wang 
15271b4c226SZixu Wang     // Skip forward declaration.
15371b4c226SZixu Wang     if (!Decl->isThisDeclarationADefinition())
15471b4c226SZixu Wang       return true;
15571b4c226SZixu Wang 
15671b4c226SZixu Wang     // Collect symbol information.
15771b4c226SZixu Wang     StringRef Name = Decl->getName();
15871b4c226SZixu Wang     StringRef USR = API.recordUSR(Decl);
15971b4c226SZixu Wang     PresumedLoc Loc =
16071b4c226SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
16171b4c226SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
16271b4c226SZixu Wang     DocComment Comment;
16371b4c226SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
16471b4c226SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
16571b4c226SZixu Wang                                               Context.getDiagnostics());
16671b4c226SZixu Wang 
16771b4c226SZixu Wang     // Build declaration fragments and sub-heading for the enum.
16871b4c226SZixu Wang     DeclarationFragments Declaration =
16971b4c226SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
17071b4c226SZixu Wang     DeclarationFragments SubHeading =
17171b4c226SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
17271b4c226SZixu Wang 
17371b4c226SZixu Wang     EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment,
17471b4c226SZixu Wang                                          Declaration, SubHeading);
17571b4c226SZixu Wang 
17671b4c226SZixu Wang     // Now collect information about the enumerators in this enum.
17771b4c226SZixu Wang     recordEnumConstants(EnumRecord, Decl->enumerators());
17871b4c226SZixu Wang 
17971b4c226SZixu Wang     return true;
18071b4c226SZixu Wang   }
18171b4c226SZixu Wang 
182*5bb5704cSZixu Wang   bool VisitRecordDecl(const RecordDecl *Decl) {
183*5bb5704cSZixu Wang     if (!Decl->isCompleteDefinition())
184*5bb5704cSZixu Wang       return true;
185*5bb5704cSZixu Wang 
186*5bb5704cSZixu Wang     // Skip C++ structs/classes/unions
187*5bb5704cSZixu Wang     // TODO: support C++ records
188*5bb5704cSZixu Wang     if (isa<CXXRecordDecl>(Decl))
189*5bb5704cSZixu Wang       return true;
190*5bb5704cSZixu Wang 
191*5bb5704cSZixu Wang     // Collect symbol information.
192*5bb5704cSZixu Wang     StringRef Name = Decl->getName();
193*5bb5704cSZixu Wang     StringRef USR = API.recordUSR(Decl);
194*5bb5704cSZixu Wang     PresumedLoc Loc =
195*5bb5704cSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
196*5bb5704cSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
197*5bb5704cSZixu Wang     DocComment Comment;
198*5bb5704cSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
199*5bb5704cSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
200*5bb5704cSZixu Wang                                               Context.getDiagnostics());
201*5bb5704cSZixu Wang 
202*5bb5704cSZixu Wang     // Build declaration fragments and sub-heading for the struct.
203*5bb5704cSZixu Wang     DeclarationFragments Declaration =
204*5bb5704cSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
205*5bb5704cSZixu Wang     DeclarationFragments SubHeading =
206*5bb5704cSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
207*5bb5704cSZixu Wang 
208*5bb5704cSZixu Wang     StructRecord *StructRecord = API.addStruct(
209*5bb5704cSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
210*5bb5704cSZixu Wang 
211*5bb5704cSZixu Wang     // Now collect information about the fields in this struct.
212*5bb5704cSZixu Wang     recordStructFields(StructRecord, Decl->fields());
213*5bb5704cSZixu Wang 
214*5bb5704cSZixu Wang     return true;
215*5bb5704cSZixu Wang   }
216*5bb5704cSZixu Wang 
21789f6b26fSZixu Wang private:
21889f6b26fSZixu Wang   /// Get availability information of the declaration \p D.
21989f6b26fSZixu Wang   AvailabilityInfo getAvailability(const Decl *D) const {
22089f6b26fSZixu Wang     StringRef PlatformName = Context.getTargetInfo().getPlatformName();
22189f6b26fSZixu Wang 
22289f6b26fSZixu Wang     AvailabilityInfo Availability;
22389f6b26fSZixu Wang     // Collect availability attributes from all redeclarations.
22489f6b26fSZixu Wang     for (const auto *RD : D->redecls()) {
22589f6b26fSZixu Wang       for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
22689f6b26fSZixu Wang         if (A->getPlatform()->getName() != PlatformName)
22789f6b26fSZixu Wang           continue;
22889f6b26fSZixu Wang         Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(),
22989f6b26fSZixu Wang                                         A->getObsoleted(), A->getUnavailable(),
23089f6b26fSZixu Wang                                         /* UnconditionallyDeprecated */ false,
23189f6b26fSZixu Wang                                         /* UnconditionallyUnavailable */ false);
23289f6b26fSZixu Wang         break;
23389f6b26fSZixu Wang       }
23489f6b26fSZixu Wang 
23589f6b26fSZixu Wang       if (const auto *A = RD->getAttr<UnavailableAttr>())
23689f6b26fSZixu Wang         if (!A->isImplicit()) {
23789f6b26fSZixu Wang           Availability.Unavailable = true;
23889f6b26fSZixu Wang           Availability.UnconditionallyUnavailable = true;
23989f6b26fSZixu Wang         }
24089f6b26fSZixu Wang 
24189f6b26fSZixu Wang       if (const auto *A = RD->getAttr<DeprecatedAttr>())
24289f6b26fSZixu Wang         if (!A->isImplicit())
24389f6b26fSZixu Wang           Availability.UnconditionallyDeprecated = true;
24489f6b26fSZixu Wang     }
24589f6b26fSZixu Wang 
24689f6b26fSZixu Wang     return Availability;
24789f6b26fSZixu Wang   }
24889f6b26fSZixu Wang 
24971b4c226SZixu Wang   /// Collect API information for the enum constants and associate with the
25071b4c226SZixu Wang   /// parent enum.
25171b4c226SZixu Wang   void recordEnumConstants(EnumRecord *EnumRecord,
25271b4c226SZixu Wang                            const EnumDecl::enumerator_range Constants) {
25371b4c226SZixu Wang     for (const auto *Constant : Constants) {
25471b4c226SZixu Wang       // Collect symbol information.
25571b4c226SZixu Wang       StringRef Name = Constant->getName();
25671b4c226SZixu Wang       StringRef USR = API.recordUSR(Constant);
25771b4c226SZixu Wang       PresumedLoc Loc =
25871b4c226SZixu Wang           Context.getSourceManager().getPresumedLoc(Constant->getLocation());
25971b4c226SZixu Wang       AvailabilityInfo Availability = getAvailability(Constant);
26071b4c226SZixu Wang       DocComment Comment;
26171b4c226SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
26271b4c226SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
26371b4c226SZixu Wang                                                 Context.getDiagnostics());
26471b4c226SZixu Wang 
26571b4c226SZixu Wang       // Build declaration fragments and sub-heading for the enum constant.
26671b4c226SZixu Wang       DeclarationFragments Declaration =
26771b4c226SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
26871b4c226SZixu Wang       DeclarationFragments SubHeading =
26971b4c226SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Constant);
27071b4c226SZixu Wang 
27171b4c226SZixu Wang       API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
27271b4c226SZixu Wang                           Declaration, SubHeading);
27371b4c226SZixu Wang     }
27471b4c226SZixu Wang   }
27571b4c226SZixu Wang 
276*5bb5704cSZixu Wang   /// Collect API information for the struct fields and associate with the
277*5bb5704cSZixu Wang   /// parent struct.
278*5bb5704cSZixu Wang   void recordStructFields(StructRecord *StructRecord,
279*5bb5704cSZixu Wang                           const RecordDecl::field_range Fields) {
280*5bb5704cSZixu Wang     for (const auto *Field : Fields) {
281*5bb5704cSZixu Wang       // Collect symbol information.
282*5bb5704cSZixu Wang       StringRef Name = Field->getName();
283*5bb5704cSZixu Wang       StringRef USR = API.recordUSR(Field);
284*5bb5704cSZixu Wang       PresumedLoc Loc =
285*5bb5704cSZixu Wang           Context.getSourceManager().getPresumedLoc(Field->getLocation());
286*5bb5704cSZixu Wang       AvailabilityInfo Availability = getAvailability(Field);
287*5bb5704cSZixu Wang       DocComment Comment;
288*5bb5704cSZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
289*5bb5704cSZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
290*5bb5704cSZixu Wang                                                 Context.getDiagnostics());
291*5bb5704cSZixu Wang 
292*5bb5704cSZixu Wang       // Build declaration fragments and sub-heading for the struct field.
293*5bb5704cSZixu Wang       DeclarationFragments Declaration =
294*5bb5704cSZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Field);
295*5bb5704cSZixu Wang       DeclarationFragments SubHeading =
296*5bb5704cSZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Field);
297*5bb5704cSZixu Wang 
298*5bb5704cSZixu Wang       API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
299*5bb5704cSZixu Wang                          Declaration, SubHeading);
300*5bb5704cSZixu Wang     }
301*5bb5704cSZixu Wang   }
302*5bb5704cSZixu Wang 
30389f6b26fSZixu Wang   ASTContext &Context;
30489f6b26fSZixu Wang   APISet API;
30589f6b26fSZixu Wang };
30689f6b26fSZixu Wang 
30789f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer {
30889f6b26fSZixu Wang public:
3095ef2ec7eSDaniel Grumberg   ExtractAPIConsumer(ASTContext &Context, StringRef ProductName,
3105ef2ec7eSDaniel Grumberg                      std::unique_ptr<raw_pwrite_stream> OS)
3115ef2ec7eSDaniel Grumberg       : Visitor(Context), ProductName(ProductName), OS(std::move(OS)) {}
31289f6b26fSZixu Wang 
31389f6b26fSZixu Wang   void HandleTranslationUnit(ASTContext &Context) override {
31489f6b26fSZixu Wang     // Use ExtractAPIVisitor to traverse symbol declarations in the context.
31589f6b26fSZixu Wang     Visitor.TraverseDecl(Context.getTranslationUnitDecl());
31689f6b26fSZixu Wang 
31789f6b26fSZixu Wang     // Setup a SymbolGraphSerializer to write out collected API information in
31889f6b26fSZixu Wang     // the Symbol Graph format.
31989f6b26fSZixu Wang     // FIXME: Make the kind of APISerializer configurable.
3205ef2ec7eSDaniel Grumberg     SymbolGraphSerializer SGSerializer(Visitor.getAPI(), ProductName);
32189f6b26fSZixu Wang     SGSerializer.serialize(*OS);
32289f6b26fSZixu Wang   }
32389f6b26fSZixu Wang 
32489f6b26fSZixu Wang private:
32589f6b26fSZixu Wang   ExtractAPIVisitor Visitor;
3265ef2ec7eSDaniel Grumberg   std::string ProductName;
32789f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS;
32889f6b26fSZixu Wang };
32989f6b26fSZixu Wang 
33089f6b26fSZixu Wang } // namespace
33189f6b26fSZixu Wang 
33289f6b26fSZixu Wang std::unique_ptr<ASTConsumer>
33389f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
33489f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile);
33589f6b26fSZixu Wang   if (!OS)
33689f6b26fSZixu Wang     return nullptr;
3375ef2ec7eSDaniel Grumberg   return std::make_unique<ExtractAPIConsumer>(
3385ef2ec7eSDaniel Grumberg       CI.getASTContext(), CI.getInvocation().getFrontendOpts().ProductName,
33989f6b26fSZixu Wang       std::move(OS));
34089f6b26fSZixu Wang }
34189f6b26fSZixu Wang 
34289f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream>
34389f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
34489f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS =
34589f6b26fSZixu Wang       CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json",
34689f6b26fSZixu Wang                                  /*RemoveFileOnSignal=*/false);
34789f6b26fSZixu Wang   if (!OS)
34889f6b26fSZixu Wang     return nullptr;
34989f6b26fSZixu Wang   return OS;
35089f6b26fSZixu Wang }
351