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 15*9fc45ca0SDaniel Grumberg #include "TypedefUnderlyingTypeResolver.h" 1689f6b26fSZixu Wang #include "clang/AST/ASTConsumer.h" 1789f6b26fSZixu Wang #include "clang/AST/ASTContext.h" 1889f6b26fSZixu Wang #include "clang/AST/Decl.h" 1989f6b26fSZixu Wang #include "clang/AST/DeclCXX.h" 2089f6b26fSZixu Wang #include "clang/AST/ParentMapContext.h" 2189f6b26fSZixu Wang #include "clang/AST/RawCommentList.h" 2289f6b26fSZixu Wang #include "clang/AST/RecursiveASTVisitor.h" 2389f6b26fSZixu Wang #include "clang/Basic/TargetInfo.h" 2489f6b26fSZixu Wang #include "clang/ExtractAPI/API.h" 2589f6b26fSZixu Wang #include "clang/ExtractAPI/AvailabilityInfo.h" 2689f6b26fSZixu Wang #include "clang/ExtractAPI/DeclarationFragments.h" 2789f6b26fSZixu Wang #include "clang/ExtractAPI/FrontendActions.h" 2889f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" 2989f6b26fSZixu Wang #include "clang/Frontend/ASTConsumers.h" 3089f6b26fSZixu Wang #include "clang/Frontend/CompilerInstance.h" 31f833aab0SDaniel Grumberg #include "clang/Frontend/FrontendOptions.h" 32529a0570SDaniel Grumberg #include "clang/Lex/MacroInfo.h" 33529a0570SDaniel Grumberg #include "clang/Lex/PPCallbacks.h" 34529a0570SDaniel Grumberg #include "clang/Lex/PreprocessorOptions.h" 35529a0570SDaniel Grumberg #include "llvm/ADT/STLExtras.h" 36f833aab0SDaniel Grumberg #include "llvm/ADT/SmallVector.h" 37f833aab0SDaniel Grumberg #include "llvm/Support/MemoryBuffer.h" 3889f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h" 3989f6b26fSZixu Wang 4089f6b26fSZixu Wang using namespace clang; 4189f6b26fSZixu Wang using namespace extractapi; 4289f6b26fSZixu Wang 4389f6b26fSZixu Wang namespace { 4489f6b26fSZixu Wang 45*9fc45ca0SDaniel Grumberg StringRef getTypedefName(const TagDecl *Decl) { 46*9fc45ca0SDaniel Grumberg if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl()) 47*9fc45ca0SDaniel Grumberg return TypedefDecl->getName(); 48*9fc45ca0SDaniel Grumberg 49*9fc45ca0SDaniel Grumberg return {}; 50*9fc45ca0SDaniel Grumberg } 51*9fc45ca0SDaniel Grumberg 5289f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API 5389f6b26fSZixu Wang /// information. 5489f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> { 5589f6b26fSZixu Wang public: 56a9909d23SDaniel Grumberg ExtractAPIVisitor(ASTContext &Context, APISet &API) 57a9909d23SDaniel Grumberg : Context(Context), API(API) {} 5889f6b26fSZixu Wang 5989f6b26fSZixu Wang const APISet &getAPI() const { return API; } 6089f6b26fSZixu Wang 6189f6b26fSZixu Wang bool VisitVarDecl(const VarDecl *Decl) { 6289f6b26fSZixu Wang // Skip function parameters. 6389f6b26fSZixu Wang if (isa<ParmVarDecl>(Decl)) 6489f6b26fSZixu Wang return true; 6589f6b26fSZixu Wang 6689f6b26fSZixu Wang // Skip non-global variables in records (struct/union/class). 6789f6b26fSZixu Wang if (Decl->getDeclContext()->isRecord()) 6889f6b26fSZixu Wang return true; 6989f6b26fSZixu Wang 7089f6b26fSZixu Wang // Skip local variables inside function or method. 7189f6b26fSZixu Wang if (!Decl->isDefinedOutsideFunctionOrMethod()) 7289f6b26fSZixu Wang return true; 7389f6b26fSZixu Wang 7489f6b26fSZixu Wang // If this is a template but not specialization or instantiation, skip. 7589f6b26fSZixu Wang if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && 7689f6b26fSZixu Wang Decl->getTemplateSpecializationKind() == TSK_Undeclared) 7789f6b26fSZixu Wang return true; 7889f6b26fSZixu Wang 7989f6b26fSZixu Wang // Collect symbol information. 8089f6b26fSZixu Wang StringRef Name = Decl->getName(); 8189f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 8289f6b26fSZixu Wang PresumedLoc Loc = 8389f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 8489f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 8589f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 8689f6b26fSZixu Wang DocComment Comment; 8789f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 8889f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 8989f6b26fSZixu Wang Context.getDiagnostics()); 9089f6b26fSZixu Wang 9189f6b26fSZixu Wang // Build declaration fragments and sub-heading for the variable. 9289f6b26fSZixu Wang DeclarationFragments Declaration = 9389f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForVar(Decl); 9489f6b26fSZixu Wang DeclarationFragments SubHeading = 9589f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 9689f6b26fSZixu Wang 9789f6b26fSZixu Wang // Add the global variable record to the API set. 9889f6b26fSZixu Wang API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment, 9989f6b26fSZixu Wang Declaration, SubHeading); 10089f6b26fSZixu Wang return true; 10189f6b26fSZixu Wang } 10289f6b26fSZixu Wang 10389f6b26fSZixu Wang bool VisitFunctionDecl(const FunctionDecl *Decl) { 10489f6b26fSZixu Wang if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) { 10589f6b26fSZixu Wang // Skip member function in class templates. 10689f6b26fSZixu Wang if (Method->getParent()->getDescribedClassTemplate() != nullptr) 10789f6b26fSZixu Wang return true; 10889f6b26fSZixu Wang 10989f6b26fSZixu Wang // Skip methods in records. 11089f6b26fSZixu Wang for (auto P : Context.getParents(*Method)) { 11189f6b26fSZixu Wang if (P.get<CXXRecordDecl>()) 11289f6b26fSZixu Wang return true; 11389f6b26fSZixu Wang } 11489f6b26fSZixu Wang 11589f6b26fSZixu Wang // Skip ConstructorDecl and DestructorDecl. 11689f6b26fSZixu Wang if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) 11789f6b26fSZixu Wang return true; 11889f6b26fSZixu Wang } 11989f6b26fSZixu Wang 12089f6b26fSZixu Wang // Skip templated functions. 12189f6b26fSZixu Wang switch (Decl->getTemplatedKind()) { 12289f6b26fSZixu Wang case FunctionDecl::TK_NonTemplate: 12389f6b26fSZixu Wang break; 12489f6b26fSZixu Wang case FunctionDecl::TK_MemberSpecialization: 12589f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplateSpecialization: 12689f6b26fSZixu Wang if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) { 12789f6b26fSZixu Wang if (!TemplateInfo->isExplicitInstantiationOrSpecialization()) 12889f6b26fSZixu Wang return true; 12989f6b26fSZixu Wang } 13089f6b26fSZixu Wang break; 13189f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplate: 13289f6b26fSZixu Wang case FunctionDecl::TK_DependentFunctionTemplateSpecialization: 13389f6b26fSZixu Wang return true; 13489f6b26fSZixu Wang } 13589f6b26fSZixu Wang 13689f6b26fSZixu Wang // Collect symbol information. 13789f6b26fSZixu Wang StringRef Name = Decl->getName(); 13889f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 13989f6b26fSZixu Wang PresumedLoc Loc = 14089f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 14189f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 14289f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 14389f6b26fSZixu Wang DocComment Comment; 14489f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 14589f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 14689f6b26fSZixu Wang Context.getDiagnostics()); 14789f6b26fSZixu Wang 14889f6b26fSZixu Wang // Build declaration fragments, sub-heading, and signature of the function. 14989f6b26fSZixu Wang DeclarationFragments Declaration = 15089f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); 15189f6b26fSZixu Wang DeclarationFragments SubHeading = 15289f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 15389f6b26fSZixu Wang FunctionSignature Signature = 15489f6b26fSZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Decl); 15589f6b26fSZixu Wang 15689f6b26fSZixu Wang // Add the function record to the API set. 15789f6b26fSZixu Wang API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration, 15889f6b26fSZixu Wang SubHeading, Signature); 15989f6b26fSZixu Wang return true; 16089f6b26fSZixu Wang } 16189f6b26fSZixu Wang 16271b4c226SZixu Wang bool VisitEnumDecl(const EnumDecl *Decl) { 16371b4c226SZixu Wang if (!Decl->isComplete()) 16471b4c226SZixu Wang return true; 16571b4c226SZixu Wang 16671b4c226SZixu Wang // Skip forward declaration. 16771b4c226SZixu Wang if (!Decl->isThisDeclarationADefinition()) 16871b4c226SZixu Wang return true; 16971b4c226SZixu Wang 17071b4c226SZixu Wang // Collect symbol information. 17171b4c226SZixu Wang StringRef Name = Decl->getName(); 172*9fc45ca0SDaniel Grumberg if (Name.empty()) 173*9fc45ca0SDaniel Grumberg Name = getTypedefName(Decl); 17471b4c226SZixu Wang StringRef USR = API.recordUSR(Decl); 17571b4c226SZixu Wang PresumedLoc Loc = 17671b4c226SZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 17771b4c226SZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 17871b4c226SZixu Wang DocComment Comment; 17971b4c226SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 18071b4c226SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 18171b4c226SZixu Wang Context.getDiagnostics()); 18271b4c226SZixu Wang 18371b4c226SZixu Wang // Build declaration fragments and sub-heading for the enum. 18471b4c226SZixu Wang DeclarationFragments Declaration = 18571b4c226SZixu Wang DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); 18671b4c226SZixu Wang DeclarationFragments SubHeading = 18771b4c226SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 18871b4c226SZixu Wang 18971b4c226SZixu Wang EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment, 19071b4c226SZixu Wang Declaration, SubHeading); 19171b4c226SZixu Wang 19271b4c226SZixu Wang // Now collect information about the enumerators in this enum. 19371b4c226SZixu Wang recordEnumConstants(EnumRecord, Decl->enumerators()); 19471b4c226SZixu Wang 19571b4c226SZixu Wang return true; 19671b4c226SZixu Wang } 19771b4c226SZixu Wang 1985bb5704cSZixu Wang bool VisitRecordDecl(const RecordDecl *Decl) { 1995bb5704cSZixu Wang if (!Decl->isCompleteDefinition()) 2005bb5704cSZixu Wang return true; 2015bb5704cSZixu Wang 2025bb5704cSZixu Wang // Skip C++ structs/classes/unions 2035bb5704cSZixu Wang // TODO: support C++ records 2045bb5704cSZixu Wang if (isa<CXXRecordDecl>(Decl)) 2055bb5704cSZixu Wang return true; 2065bb5704cSZixu Wang 2075bb5704cSZixu Wang // Collect symbol information. 2085bb5704cSZixu Wang StringRef Name = Decl->getName(); 209*9fc45ca0SDaniel Grumberg if (Name.empty()) 210*9fc45ca0SDaniel Grumberg Name = getTypedefName(Decl); 2115bb5704cSZixu Wang StringRef USR = API.recordUSR(Decl); 2125bb5704cSZixu Wang PresumedLoc Loc = 2135bb5704cSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 2145bb5704cSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 2155bb5704cSZixu Wang DocComment Comment; 2165bb5704cSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 2175bb5704cSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 2185bb5704cSZixu Wang Context.getDiagnostics()); 2195bb5704cSZixu Wang 2205bb5704cSZixu Wang // Build declaration fragments and sub-heading for the struct. 2215bb5704cSZixu Wang DeclarationFragments Declaration = 2225bb5704cSZixu Wang DeclarationFragmentsBuilder::getFragmentsForStruct(Decl); 2235bb5704cSZixu Wang DeclarationFragments SubHeading = 2245bb5704cSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 2255bb5704cSZixu Wang 2265bb5704cSZixu Wang StructRecord *StructRecord = API.addStruct( 2275bb5704cSZixu Wang Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 2285bb5704cSZixu Wang 2295bb5704cSZixu Wang // Now collect information about the fields in this struct. 2305bb5704cSZixu Wang recordStructFields(StructRecord, Decl->fields()); 2315bb5704cSZixu Wang 2325bb5704cSZixu Wang return true; 2335bb5704cSZixu Wang } 2345bb5704cSZixu Wang 2359b36e126SZixu Wang bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) { 2369b36e126SZixu Wang // Skip forward declaration for classes (@class) 2379b36e126SZixu Wang if (!Decl->isThisDeclarationADefinition()) 2389b36e126SZixu Wang return true; 2399b36e126SZixu Wang 2409b36e126SZixu Wang // Collect symbol information. 2419b36e126SZixu Wang StringRef Name = Decl->getName(); 2429b36e126SZixu Wang StringRef USR = API.recordUSR(Decl); 2439b36e126SZixu Wang PresumedLoc Loc = 2449b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 2459b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 2469b36e126SZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 2479b36e126SZixu Wang DocComment Comment; 2489b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 2499b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 2509b36e126SZixu Wang Context.getDiagnostics()); 2519b36e126SZixu Wang 2529b36e126SZixu Wang // Build declaration fragments and sub-heading for the interface. 2539b36e126SZixu Wang DeclarationFragments Declaration = 2549b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl); 2559b36e126SZixu Wang DeclarationFragments SubHeading = 2569b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 2579b36e126SZixu Wang 2589b36e126SZixu Wang // Collect super class information. 2599b36e126SZixu Wang SymbolReference SuperClass; 2609b36e126SZixu Wang if (const auto *SuperClassDecl = Decl->getSuperClass()) { 2619b36e126SZixu Wang SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); 2629b36e126SZixu Wang SuperClass.USR = API.recordUSR(SuperClassDecl); 2639b36e126SZixu Wang } 2649b36e126SZixu Wang 2659b36e126SZixu Wang ObjCInterfaceRecord *ObjCInterfaceRecord = 2669b36e126SZixu Wang API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment, 2679b36e126SZixu Wang Declaration, SubHeading, SuperClass); 2689b36e126SZixu Wang 2699b36e126SZixu Wang // Record all methods (selectors). This doesn't include automatically 2709b36e126SZixu Wang // synthesized property methods. 2719b36e126SZixu Wang recordObjCMethods(ObjCInterfaceRecord, Decl->methods()); 2729b36e126SZixu Wang recordObjCProperties(ObjCInterfaceRecord, Decl->properties()); 2739b36e126SZixu Wang recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars()); 2749b36e126SZixu Wang recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols()); 2759b36e126SZixu Wang 2769b36e126SZixu Wang return true; 2779b36e126SZixu Wang } 2789b36e126SZixu Wang 279d1d34bafSZixu Wang bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) { 280d1d34bafSZixu Wang // Skip forward declaration for protocols (@protocol). 281d1d34bafSZixu Wang if (!Decl->isThisDeclarationADefinition()) 282d1d34bafSZixu Wang return true; 283d1d34bafSZixu Wang 284d1d34bafSZixu Wang // Collect symbol information. 285d1d34bafSZixu Wang StringRef Name = Decl->getName(); 286d1d34bafSZixu Wang StringRef USR = API.recordUSR(Decl); 287d1d34bafSZixu Wang PresumedLoc Loc = 288d1d34bafSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 289d1d34bafSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 290d1d34bafSZixu Wang DocComment Comment; 291d1d34bafSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 292d1d34bafSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 293d1d34bafSZixu Wang Context.getDiagnostics()); 294d1d34bafSZixu Wang 295d1d34bafSZixu Wang // Build declaration fragments and sub-heading for the protocol. 296d1d34bafSZixu Wang DeclarationFragments Declaration = 297d1d34bafSZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl); 298d1d34bafSZixu Wang DeclarationFragments SubHeading = 299d1d34bafSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 300d1d34bafSZixu Wang 301d1d34bafSZixu Wang ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol( 302d1d34bafSZixu Wang Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 303d1d34bafSZixu Wang 304d1d34bafSZixu Wang recordObjCMethods(ObjCProtocolRecord, Decl->methods()); 305d1d34bafSZixu Wang recordObjCProperties(ObjCProtocolRecord, Decl->properties()); 306d1d34bafSZixu Wang recordObjCProtocols(ObjCProtocolRecord, Decl->protocols()); 307d1d34bafSZixu Wang 308d1d34bafSZixu Wang return true; 309d1d34bafSZixu Wang } 310d1d34bafSZixu Wang 311*9fc45ca0SDaniel Grumberg bool VisitTypedefNameDecl(const TypedefNameDecl *Decl) { 312*9fc45ca0SDaniel Grumberg // Skip ObjC Type Parameter for now. 313*9fc45ca0SDaniel Grumberg if (isa<ObjCTypeParamDecl>(Decl)) 314*9fc45ca0SDaniel Grumberg return true; 315*9fc45ca0SDaniel Grumberg 316*9fc45ca0SDaniel Grumberg if (!Decl->isDefinedOutsideFunctionOrMethod()) 317*9fc45ca0SDaniel Grumberg return true; 318*9fc45ca0SDaniel Grumberg 319*9fc45ca0SDaniel Grumberg PresumedLoc Loc = 320*9fc45ca0SDaniel Grumberg Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 321*9fc45ca0SDaniel Grumberg StringRef Name = Decl->getName(); 322*9fc45ca0SDaniel Grumberg AvailabilityInfo Availability = getAvailability(Decl); 323*9fc45ca0SDaniel Grumberg StringRef USR = API.recordUSR(Decl); 324*9fc45ca0SDaniel Grumberg DocComment Comment; 325*9fc45ca0SDaniel Grumberg if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 326*9fc45ca0SDaniel Grumberg Comment = RawComment->getFormattedLines(Context.getSourceManager(), 327*9fc45ca0SDaniel Grumberg Context.getDiagnostics()); 328*9fc45ca0SDaniel Grumberg 329*9fc45ca0SDaniel Grumberg QualType Type = Decl->getUnderlyingType(); 330*9fc45ca0SDaniel Grumberg SymbolReference SymRef = 331*9fc45ca0SDaniel Grumberg TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type, 332*9fc45ca0SDaniel Grumberg API); 333*9fc45ca0SDaniel Grumberg 334*9fc45ca0SDaniel Grumberg API.addTypedef(Name, USR, Loc, Availability, Comment, 335*9fc45ca0SDaniel Grumberg DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), 336*9fc45ca0SDaniel Grumberg DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef); 337*9fc45ca0SDaniel Grumberg 338*9fc45ca0SDaniel Grumberg return true; 339*9fc45ca0SDaniel Grumberg } 340*9fc45ca0SDaniel Grumberg 34189f6b26fSZixu Wang private: 34289f6b26fSZixu Wang /// Get availability information of the declaration \p D. 34389f6b26fSZixu Wang AvailabilityInfo getAvailability(const Decl *D) const { 34489f6b26fSZixu Wang StringRef PlatformName = Context.getTargetInfo().getPlatformName(); 34589f6b26fSZixu Wang 34689f6b26fSZixu Wang AvailabilityInfo Availability; 34789f6b26fSZixu Wang // Collect availability attributes from all redeclarations. 34889f6b26fSZixu Wang for (const auto *RD : D->redecls()) { 34989f6b26fSZixu Wang for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) { 35089f6b26fSZixu Wang if (A->getPlatform()->getName() != PlatformName) 35189f6b26fSZixu Wang continue; 35289f6b26fSZixu Wang Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(), 35389f6b26fSZixu Wang A->getObsoleted(), A->getUnavailable(), 35489f6b26fSZixu Wang /* UnconditionallyDeprecated */ false, 35589f6b26fSZixu Wang /* UnconditionallyUnavailable */ false); 35689f6b26fSZixu Wang break; 35789f6b26fSZixu Wang } 35889f6b26fSZixu Wang 35989f6b26fSZixu Wang if (const auto *A = RD->getAttr<UnavailableAttr>()) 36089f6b26fSZixu Wang if (!A->isImplicit()) { 36189f6b26fSZixu Wang Availability.Unavailable = true; 36289f6b26fSZixu Wang Availability.UnconditionallyUnavailable = true; 36389f6b26fSZixu Wang } 36489f6b26fSZixu Wang 36589f6b26fSZixu Wang if (const auto *A = RD->getAttr<DeprecatedAttr>()) 36689f6b26fSZixu Wang if (!A->isImplicit()) 36789f6b26fSZixu Wang Availability.UnconditionallyDeprecated = true; 36889f6b26fSZixu Wang } 36989f6b26fSZixu Wang 37089f6b26fSZixu Wang return Availability; 37189f6b26fSZixu Wang } 37289f6b26fSZixu Wang 37371b4c226SZixu Wang /// Collect API information for the enum constants and associate with the 37471b4c226SZixu Wang /// parent enum. 37571b4c226SZixu Wang void recordEnumConstants(EnumRecord *EnumRecord, 37671b4c226SZixu Wang const EnumDecl::enumerator_range Constants) { 37771b4c226SZixu Wang for (const auto *Constant : Constants) { 37871b4c226SZixu Wang // Collect symbol information. 37971b4c226SZixu Wang StringRef Name = Constant->getName(); 38071b4c226SZixu Wang StringRef USR = API.recordUSR(Constant); 38171b4c226SZixu Wang PresumedLoc Loc = 38271b4c226SZixu Wang Context.getSourceManager().getPresumedLoc(Constant->getLocation()); 38371b4c226SZixu Wang AvailabilityInfo Availability = getAvailability(Constant); 38471b4c226SZixu Wang DocComment Comment; 38571b4c226SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant)) 38671b4c226SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 38771b4c226SZixu Wang Context.getDiagnostics()); 38871b4c226SZixu Wang 38971b4c226SZixu Wang // Build declaration fragments and sub-heading for the enum constant. 39071b4c226SZixu Wang DeclarationFragments Declaration = 39171b4c226SZixu Wang DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant); 39271b4c226SZixu Wang DeclarationFragments SubHeading = 39371b4c226SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Constant); 39471b4c226SZixu Wang 39571b4c226SZixu Wang API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment, 39671b4c226SZixu Wang Declaration, SubHeading); 39771b4c226SZixu Wang } 39871b4c226SZixu Wang } 39971b4c226SZixu Wang 4005bb5704cSZixu Wang /// Collect API information for the struct fields and associate with the 4015bb5704cSZixu Wang /// parent struct. 4025bb5704cSZixu Wang void recordStructFields(StructRecord *StructRecord, 4035bb5704cSZixu Wang const RecordDecl::field_range Fields) { 4045bb5704cSZixu Wang for (const auto *Field : Fields) { 4055bb5704cSZixu Wang // Collect symbol information. 4065bb5704cSZixu Wang StringRef Name = Field->getName(); 4075bb5704cSZixu Wang StringRef USR = API.recordUSR(Field); 4085bb5704cSZixu Wang PresumedLoc Loc = 4095bb5704cSZixu Wang Context.getSourceManager().getPresumedLoc(Field->getLocation()); 4105bb5704cSZixu Wang AvailabilityInfo Availability = getAvailability(Field); 4115bb5704cSZixu Wang DocComment Comment; 4125bb5704cSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field)) 4135bb5704cSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 4145bb5704cSZixu Wang Context.getDiagnostics()); 4155bb5704cSZixu Wang 4165bb5704cSZixu Wang // Build declaration fragments and sub-heading for the struct field. 4175bb5704cSZixu Wang DeclarationFragments Declaration = 4185bb5704cSZixu Wang DeclarationFragmentsBuilder::getFragmentsForField(Field); 4195bb5704cSZixu Wang DeclarationFragments SubHeading = 4205bb5704cSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Field); 4215bb5704cSZixu Wang 4225bb5704cSZixu Wang API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment, 4235bb5704cSZixu Wang Declaration, SubHeading); 4245bb5704cSZixu Wang } 4255bb5704cSZixu Wang } 4265bb5704cSZixu Wang 4279b36e126SZixu Wang /// Collect API information for the Objective-C methods and associate with the 4289b36e126SZixu Wang /// parent container. 4299b36e126SZixu Wang void recordObjCMethods(ObjCContainerRecord *Container, 4309b36e126SZixu Wang const ObjCContainerDecl::method_range Methods) { 4319b36e126SZixu Wang for (const auto *Method : Methods) { 4329b36e126SZixu Wang // Don't record selectors for properties. 4339b36e126SZixu Wang if (Method->isPropertyAccessor()) 4349b36e126SZixu Wang continue; 4359b36e126SZixu Wang 4369b36e126SZixu Wang StringRef Name = API.copyString(Method->getSelector().getAsString()); 4379b36e126SZixu Wang StringRef USR = API.recordUSR(Method); 4389b36e126SZixu Wang PresumedLoc Loc = 4399b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Method->getLocation()); 4409b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Method); 4419b36e126SZixu Wang DocComment Comment; 4429b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method)) 4439b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 4449b36e126SZixu Wang Context.getDiagnostics()); 4459b36e126SZixu Wang 4469b36e126SZixu Wang // Build declaration fragments, sub-heading, and signature for the method. 4479b36e126SZixu Wang DeclarationFragments Declaration = 4489b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method); 4499b36e126SZixu Wang DeclarationFragments SubHeading = 4509b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Method); 4519b36e126SZixu Wang FunctionSignature Signature = 4529b36e126SZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Method); 4539b36e126SZixu Wang 4549b36e126SZixu Wang API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment, 4559b36e126SZixu Wang Declaration, SubHeading, Signature, 4569b36e126SZixu Wang Method->isInstanceMethod()); 4579b36e126SZixu Wang } 4589b36e126SZixu Wang } 4599b36e126SZixu Wang 4609b36e126SZixu Wang void recordObjCProperties(ObjCContainerRecord *Container, 4619b36e126SZixu Wang const ObjCContainerDecl::prop_range Properties) { 4629b36e126SZixu Wang for (const auto *Property : Properties) { 4639b36e126SZixu Wang StringRef Name = Property->getName(); 4649b36e126SZixu Wang StringRef USR = API.recordUSR(Property); 4659b36e126SZixu Wang PresumedLoc Loc = 4669b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Property->getLocation()); 4679b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Property); 4689b36e126SZixu Wang DocComment Comment; 4699b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property)) 4709b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 4719b36e126SZixu Wang Context.getDiagnostics()); 4729b36e126SZixu Wang 4739b36e126SZixu Wang // Build declaration fragments and sub-heading for the property. 4749b36e126SZixu Wang DeclarationFragments Declaration = 4759b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property); 4769b36e126SZixu Wang DeclarationFragments SubHeading = 4779b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Property); 4789b36e126SZixu Wang 4799b36e126SZixu Wang StringRef GetterName = 4809b36e126SZixu Wang API.copyString(Property->getGetterName().getAsString()); 4819b36e126SZixu Wang StringRef SetterName = 4829b36e126SZixu Wang API.copyString(Property->getSetterName().getAsString()); 4839b36e126SZixu Wang 4849b36e126SZixu Wang // Get the attributes for property. 4859b36e126SZixu Wang unsigned Attributes = ObjCPropertyRecord::NoAttr; 4869b36e126SZixu Wang if (Property->getPropertyAttributes() & 4879b36e126SZixu Wang ObjCPropertyAttribute::kind_readonly) 4889b36e126SZixu Wang Attributes |= ObjCPropertyRecord::ReadOnly; 4899b36e126SZixu Wang if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class) 4909b36e126SZixu Wang Attributes |= ObjCPropertyRecord::Class; 4919b36e126SZixu Wang 4929b36e126SZixu Wang API.addObjCProperty( 4939b36e126SZixu Wang Container, Name, USR, Loc, Availability, Comment, Declaration, 4949b36e126SZixu Wang SubHeading, 4959b36e126SZixu Wang static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), 4969b36e126SZixu Wang GetterName, SetterName, Property->isOptional()); 4979b36e126SZixu Wang } 4989b36e126SZixu Wang } 4999b36e126SZixu Wang 5009b36e126SZixu Wang void recordObjCInstanceVariables( 5019b36e126SZixu Wang ObjCContainerRecord *Container, 5029b36e126SZixu Wang const llvm::iterator_range< 5039b36e126SZixu Wang DeclContext::specific_decl_iterator<ObjCIvarDecl>> 5049b36e126SZixu Wang Ivars) { 5059b36e126SZixu Wang for (const auto *Ivar : Ivars) { 5069b36e126SZixu Wang StringRef Name = Ivar->getName(); 5079b36e126SZixu Wang StringRef USR = API.recordUSR(Ivar); 5089b36e126SZixu Wang PresumedLoc Loc = 5099b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); 5109b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Ivar); 5119b36e126SZixu Wang DocComment Comment; 5129b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar)) 5139b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 5149b36e126SZixu Wang Context.getDiagnostics()); 5159b36e126SZixu Wang 5169b36e126SZixu Wang // Build declaration fragments and sub-heading for the instance variable. 5179b36e126SZixu Wang DeclarationFragments Declaration = 5189b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForField(Ivar); 5199b36e126SZixu Wang DeclarationFragments SubHeading = 5209b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Ivar); 5219b36e126SZixu Wang 5229b36e126SZixu Wang ObjCInstanceVariableRecord::AccessControl Access = 5239b36e126SZixu Wang Ivar->getCanonicalAccessControl(); 5249b36e126SZixu Wang 5259b36e126SZixu Wang API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability, 5269b36e126SZixu Wang Comment, Declaration, SubHeading, Access); 5279b36e126SZixu Wang } 5289b36e126SZixu Wang } 5299b36e126SZixu Wang 5309b36e126SZixu Wang void recordObjCProtocols(ObjCContainerRecord *Container, 5319b36e126SZixu Wang ObjCInterfaceDecl::protocol_range Protocols) { 5329b36e126SZixu Wang for (const auto *Protocol : Protocols) 5339b36e126SZixu Wang Container->Protocols.emplace_back(Protocol->getName(), 5349b36e126SZixu Wang API.recordUSR(Protocol)); 5359b36e126SZixu Wang } 5369b36e126SZixu Wang 53789f6b26fSZixu Wang ASTContext &Context; 538a9909d23SDaniel Grumberg APISet &API; 53989f6b26fSZixu Wang }; 54089f6b26fSZixu Wang 54189f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer { 54289f6b26fSZixu Wang public: 543a9909d23SDaniel Grumberg ExtractAPIConsumer(ASTContext &Context, APISet &API) 544a9909d23SDaniel Grumberg : Visitor(Context, API) {} 54589f6b26fSZixu Wang 54689f6b26fSZixu Wang void HandleTranslationUnit(ASTContext &Context) override { 54789f6b26fSZixu Wang // Use ExtractAPIVisitor to traverse symbol declarations in the context. 54889f6b26fSZixu Wang Visitor.TraverseDecl(Context.getTranslationUnitDecl()); 54989f6b26fSZixu Wang } 55089f6b26fSZixu Wang 55189f6b26fSZixu Wang private: 55289f6b26fSZixu Wang ExtractAPIVisitor Visitor; 55389f6b26fSZixu Wang }; 55489f6b26fSZixu Wang 555529a0570SDaniel Grumberg class MacroCallback : public PPCallbacks { 556529a0570SDaniel Grumberg public: 557529a0570SDaniel Grumberg MacroCallback(const SourceManager &SM, APISet &API) : SM(SM), API(API) {} 558529a0570SDaniel Grumberg 559529a0570SDaniel Grumberg void MacroDefined(const Token &MacroNameToken, 560529a0570SDaniel Grumberg const MacroDirective *MD) override { 561529a0570SDaniel Grumberg auto *MacroInfo = MD->getMacroInfo(); 562529a0570SDaniel Grumberg 563529a0570SDaniel Grumberg if (MacroInfo->isBuiltinMacro()) 564529a0570SDaniel Grumberg return; 565529a0570SDaniel Grumberg 566529a0570SDaniel Grumberg auto SourceLoc = MacroNameToken.getLocation(); 567529a0570SDaniel Grumberg if (SM.isWrittenInBuiltinFile(SourceLoc) || 568529a0570SDaniel Grumberg SM.isWrittenInCommandLineFile(SourceLoc)) 569529a0570SDaniel Grumberg return; 570529a0570SDaniel Grumberg 571529a0570SDaniel Grumberg PendingMacros.emplace_back(MacroNameToken, MD); 572529a0570SDaniel Grumberg } 573529a0570SDaniel Grumberg 574529a0570SDaniel Grumberg // If a macro gets undefined at some point during preprocessing of the inputs 575529a0570SDaniel Grumberg // it means that it isn't an exposed API and we should therefore not add a 576529a0570SDaniel Grumberg // macro definition for it. 577529a0570SDaniel Grumberg void MacroUndefined(const Token &MacroNameToken, const MacroDefinition &MD, 578529a0570SDaniel Grumberg const MacroDirective *Undef) override { 5798b63622bSDaniel Grumberg // If this macro wasn't previously defined we don't need to do anything 5808b63622bSDaniel Grumberg // here. 5818b63622bSDaniel Grumberg if (!Undef) 5828b63622bSDaniel Grumberg return; 5838b63622bSDaniel Grumberg 584529a0570SDaniel Grumberg llvm::erase_if(PendingMacros, [&MD](const PendingMacro &PM) { 585529a0570SDaniel Grumberg return MD.getMacroInfo()->getDefinitionLoc() == 586529a0570SDaniel Grumberg PM.MD->getMacroInfo()->getDefinitionLoc(); 587529a0570SDaniel Grumberg }); 588529a0570SDaniel Grumberg } 589529a0570SDaniel Grumberg 590529a0570SDaniel Grumberg void EndOfMainFile() override { 591529a0570SDaniel Grumberg for (auto &PM : PendingMacros) { 592529a0570SDaniel Grumberg // `isUsedForHeaderGuard` is only set when the preprocessor leaves the 593529a0570SDaniel Grumberg // file so check for it here. 594529a0570SDaniel Grumberg if (PM.MD->getMacroInfo()->isUsedForHeaderGuard()) 595529a0570SDaniel Grumberg continue; 596529a0570SDaniel Grumberg 597529a0570SDaniel Grumberg StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName(); 598529a0570SDaniel Grumberg PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation()); 599529a0570SDaniel Grumberg StringRef USR = 600529a0570SDaniel Grumberg API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM); 601529a0570SDaniel Grumberg 602529a0570SDaniel Grumberg API.addMacroDefinition( 603529a0570SDaniel Grumberg Name, USR, Loc, 604529a0570SDaniel Grumberg DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD), 605529a0570SDaniel Grumberg DeclarationFragmentsBuilder::getSubHeadingForMacro(Name)); 606529a0570SDaniel Grumberg } 607529a0570SDaniel Grumberg 608529a0570SDaniel Grumberg PendingMacros.clear(); 609529a0570SDaniel Grumberg } 610529a0570SDaniel Grumberg 611529a0570SDaniel Grumberg private: 612529a0570SDaniel Grumberg struct PendingMacro { 613529a0570SDaniel Grumberg Token MacroNameToken; 614529a0570SDaniel Grumberg const MacroDirective *MD; 615529a0570SDaniel Grumberg 616529a0570SDaniel Grumberg PendingMacro(const Token &MacroNameToken, const MacroDirective *MD) 617529a0570SDaniel Grumberg : MacroNameToken(MacroNameToken), MD(MD) {} 618529a0570SDaniel Grumberg }; 619529a0570SDaniel Grumberg 620529a0570SDaniel Grumberg const SourceManager &SM; 621529a0570SDaniel Grumberg APISet &API; 622529a0570SDaniel Grumberg llvm::SmallVector<PendingMacro> PendingMacros; 623529a0570SDaniel Grumberg }; 624529a0570SDaniel Grumberg 62589f6b26fSZixu Wang } // namespace 62689f6b26fSZixu Wang 62789f6b26fSZixu Wang std::unique_ptr<ASTConsumer> 62889f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { 629a9909d23SDaniel Grumberg OS = CreateOutputFile(CI, InFile); 63089f6b26fSZixu Wang if (!OS) 63189f6b26fSZixu Wang return nullptr; 632a9909d23SDaniel Grumberg 633a9909d23SDaniel Grumberg ProductName = CI.getFrontendOpts().ProductName; 634a9909d23SDaniel Grumberg 635a9909d23SDaniel Grumberg // Now that we have enough information about the language options and the 636a9909d23SDaniel Grumberg // target triple, let's create the APISet before anyone uses it. 637a9909d23SDaniel Grumberg API = std::make_unique<APISet>( 638a9909d23SDaniel Grumberg CI.getTarget().getTriple(), 639a9909d23SDaniel Grumberg CI.getFrontendOpts().Inputs.back().getKind().getLanguage()); 640a9909d23SDaniel Grumberg 641529a0570SDaniel Grumberg // Register preprocessor callbacks that will add macro definitions to API. 642529a0570SDaniel Grumberg CI.getPreprocessor().addPPCallbacks( 643529a0570SDaniel Grumberg std::make_unique<MacroCallback>(CI.getSourceManager(), *API)); 644529a0570SDaniel Grumberg 645a9909d23SDaniel Grumberg return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(), *API); 64689f6b26fSZixu Wang } 64789f6b26fSZixu Wang 648f833aab0SDaniel Grumberg bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { 649f833aab0SDaniel Grumberg auto &Inputs = CI.getFrontendOpts().Inputs; 650f833aab0SDaniel Grumberg if (Inputs.empty()) 651f833aab0SDaniel Grumberg return true; 652f833aab0SDaniel Grumberg 653f833aab0SDaniel Grumberg auto Kind = Inputs[0].getKind(); 654f833aab0SDaniel Grumberg 655f833aab0SDaniel Grumberg // Convert the header file inputs into a single input buffer. 656f833aab0SDaniel Grumberg SmallString<256> HeaderContents; 657f833aab0SDaniel Grumberg for (const FrontendInputFile &FIF : Inputs) { 658f833aab0SDaniel Grumberg if (Kind.isObjectiveC()) 659f833aab0SDaniel Grumberg HeaderContents += "#import"; 660f833aab0SDaniel Grumberg else 661f833aab0SDaniel Grumberg HeaderContents += "#include"; 662f833aab0SDaniel Grumberg HeaderContents += " \""; 663f833aab0SDaniel Grumberg HeaderContents += FIF.getFile(); 664f833aab0SDaniel Grumberg HeaderContents += "\"\n"; 665f833aab0SDaniel Grumberg } 666f833aab0SDaniel Grumberg 667985eaa1aSDaniel Grumberg Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents, 668f833aab0SDaniel Grumberg getInputBufferName()); 669f833aab0SDaniel Grumberg 670f833aab0SDaniel Grumberg // Set that buffer up as our "real" input in the CompilerInstance. 671f833aab0SDaniel Grumberg Inputs.clear(); 672f833aab0SDaniel Grumberg Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false); 673f833aab0SDaniel Grumberg 674f833aab0SDaniel Grumberg return true; 675f833aab0SDaniel Grumberg } 676f833aab0SDaniel Grumberg 677a9909d23SDaniel Grumberg void ExtractAPIAction::EndSourceFileAction() { 678a9909d23SDaniel Grumberg if (!OS) 679a9909d23SDaniel Grumberg return; 680a9909d23SDaniel Grumberg 681a9909d23SDaniel Grumberg // Setup a SymbolGraphSerializer to write out collected API information in 682a9909d23SDaniel Grumberg // the Symbol Graph format. 683a9909d23SDaniel Grumberg // FIXME: Make the kind of APISerializer configurable. 684a9909d23SDaniel Grumberg SymbolGraphSerializer SGSerializer(*API, ProductName); 685a9909d23SDaniel Grumberg SGSerializer.serialize(*OS); 686a9909d23SDaniel Grumberg OS->flush(); 687a9909d23SDaniel Grumberg } 688a9909d23SDaniel Grumberg 68989f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> 69089f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { 69189f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS = 69289f6b26fSZixu Wang CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json", 69389f6b26fSZixu Wang /*RemoveFileOnSignal=*/false); 69489f6b26fSZixu Wang if (!OS) 69589f6b26fSZixu Wang return nullptr; 69689f6b26fSZixu Wang return OS; 69789f6b26fSZixu Wang } 698