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 159fc45ca0SDaniel 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" 23*aebe5fc6SDaniel Grumberg #include "clang/Basic/SourceLocation.h" 24*aebe5fc6SDaniel Grumberg #include "clang/Basic/SourceManager.h" 2589f6b26fSZixu Wang #include "clang/Basic/TargetInfo.h" 2689f6b26fSZixu Wang #include "clang/ExtractAPI/API.h" 2789f6b26fSZixu Wang #include "clang/ExtractAPI/AvailabilityInfo.h" 2889f6b26fSZixu Wang #include "clang/ExtractAPI/DeclarationFragments.h" 2989f6b26fSZixu Wang #include "clang/ExtractAPI/FrontendActions.h" 3089f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" 3189f6b26fSZixu Wang #include "clang/Frontend/ASTConsumers.h" 3289f6b26fSZixu Wang #include "clang/Frontend/CompilerInstance.h" 33f833aab0SDaniel Grumberg #include "clang/Frontend/FrontendOptions.h" 34529a0570SDaniel Grumberg #include "clang/Lex/MacroInfo.h" 35529a0570SDaniel Grumberg #include "clang/Lex/PPCallbacks.h" 36*aebe5fc6SDaniel Grumberg #include "clang/Lex/Preprocessor.h" 37529a0570SDaniel Grumberg #include "clang/Lex/PreprocessorOptions.h" 38*aebe5fc6SDaniel Grumberg #include "llvm/ADT/DenseSet.h" 39529a0570SDaniel Grumberg #include "llvm/ADT/STLExtras.h" 40f833aab0SDaniel Grumberg #include "llvm/ADT/SmallVector.h" 41f833aab0SDaniel Grumberg #include "llvm/Support/MemoryBuffer.h" 4289f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h" 43*aebe5fc6SDaniel Grumberg #include <memory> 44*aebe5fc6SDaniel Grumberg #include <utility> 4589f6b26fSZixu Wang 4689f6b26fSZixu Wang using namespace clang; 4789f6b26fSZixu Wang using namespace extractapi; 4889f6b26fSZixu Wang 4989f6b26fSZixu Wang namespace { 5089f6b26fSZixu Wang 519fc45ca0SDaniel Grumberg StringRef getTypedefName(const TagDecl *Decl) { 529fc45ca0SDaniel Grumberg if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl()) 539fc45ca0SDaniel Grumberg return TypedefDecl->getName(); 549fc45ca0SDaniel Grumberg 559fc45ca0SDaniel Grumberg return {}; 569fc45ca0SDaniel Grumberg } 579fc45ca0SDaniel Grumberg 58*aebe5fc6SDaniel Grumberg struct LocationFileChecker { 59*aebe5fc6SDaniel Grumberg bool isLocationInKnownFile(SourceLocation Loc) { 60*aebe5fc6SDaniel Grumberg // If the loc refers to a macro expansion we need to first get the file 61*aebe5fc6SDaniel Grumberg // location of the expansion. 62*aebe5fc6SDaniel Grumberg auto FileLoc = SM.getFileLoc(Loc); 63*aebe5fc6SDaniel Grumberg FileID FID = SM.getFileID(FileLoc); 64*aebe5fc6SDaniel Grumberg if (FID.isInvalid()) 65*aebe5fc6SDaniel Grumberg return false; 66*aebe5fc6SDaniel Grumberg 67*aebe5fc6SDaniel Grumberg const auto *File = SM.getFileEntryForID(FID); 68*aebe5fc6SDaniel Grumberg if (!File) 69*aebe5fc6SDaniel Grumberg return false; 70*aebe5fc6SDaniel Grumberg 71*aebe5fc6SDaniel Grumberg if (KnownFileEntries.count(File)) 72*aebe5fc6SDaniel Grumberg return true; 73*aebe5fc6SDaniel Grumberg 74*aebe5fc6SDaniel Grumberg return false; 75*aebe5fc6SDaniel Grumberg } 76*aebe5fc6SDaniel Grumberg 77*aebe5fc6SDaniel Grumberg LocationFileChecker(const SourceManager &SM, 78*aebe5fc6SDaniel Grumberg const std::vector<std::string> &KnownFiles) 79*aebe5fc6SDaniel Grumberg : SM(SM) { 80*aebe5fc6SDaniel Grumberg for (const auto &KnownFilePath : KnownFiles) 81*aebe5fc6SDaniel Grumberg if (auto FileEntry = SM.getFileManager().getFile(KnownFilePath)) 82*aebe5fc6SDaniel Grumberg KnownFileEntries.insert(*FileEntry); 83*aebe5fc6SDaniel Grumberg } 84*aebe5fc6SDaniel Grumberg 85*aebe5fc6SDaniel Grumberg private: 86*aebe5fc6SDaniel Grumberg const SourceManager &SM; 87*aebe5fc6SDaniel Grumberg llvm::DenseSet<const FileEntry *> KnownFileEntries; 88*aebe5fc6SDaniel Grumberg }; 89*aebe5fc6SDaniel Grumberg 9089f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API 9189f6b26fSZixu Wang /// information. 9289f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> { 9389f6b26fSZixu Wang public: 94*aebe5fc6SDaniel Grumberg ExtractAPIVisitor(ASTContext &Context, LocationFileChecker &LCF, APISet &API) 95*aebe5fc6SDaniel Grumberg : Context(Context), API(API), LCF(LCF) {} 9689f6b26fSZixu Wang 9789f6b26fSZixu Wang const APISet &getAPI() const { return API; } 9889f6b26fSZixu Wang 9989f6b26fSZixu Wang bool VisitVarDecl(const VarDecl *Decl) { 10089f6b26fSZixu Wang // Skip function parameters. 10189f6b26fSZixu Wang if (isa<ParmVarDecl>(Decl)) 10289f6b26fSZixu Wang return true; 10389f6b26fSZixu Wang 10489f6b26fSZixu Wang // Skip non-global variables in records (struct/union/class). 10589f6b26fSZixu Wang if (Decl->getDeclContext()->isRecord()) 10689f6b26fSZixu Wang return true; 10789f6b26fSZixu Wang 10889f6b26fSZixu Wang // Skip local variables inside function or method. 10989f6b26fSZixu Wang if (!Decl->isDefinedOutsideFunctionOrMethod()) 11089f6b26fSZixu Wang return true; 11189f6b26fSZixu Wang 11289f6b26fSZixu Wang // If this is a template but not specialization or instantiation, skip. 11389f6b26fSZixu Wang if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && 11489f6b26fSZixu Wang Decl->getTemplateSpecializationKind() == TSK_Undeclared) 11589f6b26fSZixu Wang return true; 11689f6b26fSZixu Wang 117*aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 118*aebe5fc6SDaniel Grumberg return true; 119*aebe5fc6SDaniel Grumberg 12089f6b26fSZixu Wang // Collect symbol information. 12189f6b26fSZixu Wang StringRef Name = Decl->getName(); 12289f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 12389f6b26fSZixu Wang PresumedLoc Loc = 12489f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 12589f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 12689f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 12789f6b26fSZixu Wang DocComment Comment; 12889f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 12989f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 13089f6b26fSZixu Wang Context.getDiagnostics()); 13189f6b26fSZixu Wang 13289f6b26fSZixu Wang // Build declaration fragments and sub-heading for the variable. 13389f6b26fSZixu Wang DeclarationFragments Declaration = 13489f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForVar(Decl); 13589f6b26fSZixu Wang DeclarationFragments SubHeading = 13689f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 13789f6b26fSZixu Wang 13889f6b26fSZixu Wang // Add the global variable record to the API set. 13989f6b26fSZixu Wang API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment, 14089f6b26fSZixu Wang Declaration, SubHeading); 14189f6b26fSZixu Wang return true; 14289f6b26fSZixu Wang } 14389f6b26fSZixu Wang 14489f6b26fSZixu Wang bool VisitFunctionDecl(const FunctionDecl *Decl) { 14589f6b26fSZixu Wang if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) { 14689f6b26fSZixu Wang // Skip member function in class templates. 14789f6b26fSZixu Wang if (Method->getParent()->getDescribedClassTemplate() != nullptr) 14889f6b26fSZixu Wang return true; 14989f6b26fSZixu Wang 15089f6b26fSZixu Wang // Skip methods in records. 15189f6b26fSZixu Wang for (auto P : Context.getParents(*Method)) { 15289f6b26fSZixu Wang if (P.get<CXXRecordDecl>()) 15389f6b26fSZixu Wang return true; 15489f6b26fSZixu Wang } 15589f6b26fSZixu Wang 15689f6b26fSZixu Wang // Skip ConstructorDecl and DestructorDecl. 15789f6b26fSZixu Wang if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) 15889f6b26fSZixu Wang return true; 15989f6b26fSZixu Wang } 16089f6b26fSZixu Wang 16189f6b26fSZixu Wang // Skip templated functions. 16289f6b26fSZixu Wang switch (Decl->getTemplatedKind()) { 16389f6b26fSZixu Wang case FunctionDecl::TK_NonTemplate: 16489f6b26fSZixu Wang break; 16589f6b26fSZixu Wang case FunctionDecl::TK_MemberSpecialization: 16689f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplateSpecialization: 16789f6b26fSZixu Wang if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) { 16889f6b26fSZixu Wang if (!TemplateInfo->isExplicitInstantiationOrSpecialization()) 16989f6b26fSZixu Wang return true; 17089f6b26fSZixu Wang } 17189f6b26fSZixu Wang break; 17289f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplate: 17389f6b26fSZixu Wang case FunctionDecl::TK_DependentFunctionTemplateSpecialization: 17489f6b26fSZixu Wang return true; 17589f6b26fSZixu Wang } 17689f6b26fSZixu Wang 177*aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 178*aebe5fc6SDaniel Grumberg return true; 179*aebe5fc6SDaniel Grumberg 18089f6b26fSZixu Wang // Collect symbol information. 18189f6b26fSZixu Wang StringRef Name = Decl->getName(); 18289f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 18389f6b26fSZixu Wang PresumedLoc Loc = 18489f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 18589f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 18689f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 18789f6b26fSZixu Wang DocComment Comment; 18889f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 18989f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 19089f6b26fSZixu Wang Context.getDiagnostics()); 19189f6b26fSZixu Wang 19289f6b26fSZixu Wang // Build declaration fragments, sub-heading, and signature of the function. 19389f6b26fSZixu Wang DeclarationFragments Declaration = 19489f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); 19589f6b26fSZixu Wang DeclarationFragments SubHeading = 19689f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 19789f6b26fSZixu Wang FunctionSignature Signature = 19889f6b26fSZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Decl); 19989f6b26fSZixu Wang 20089f6b26fSZixu Wang // Add the function record to the API set. 20189f6b26fSZixu Wang API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration, 20289f6b26fSZixu Wang SubHeading, Signature); 20389f6b26fSZixu Wang return true; 20489f6b26fSZixu Wang } 20589f6b26fSZixu Wang 20671b4c226SZixu Wang bool VisitEnumDecl(const EnumDecl *Decl) { 20771b4c226SZixu Wang if (!Decl->isComplete()) 20871b4c226SZixu Wang return true; 20971b4c226SZixu Wang 21071b4c226SZixu Wang // Skip forward declaration. 21171b4c226SZixu Wang if (!Decl->isThisDeclarationADefinition()) 21271b4c226SZixu Wang return true; 21371b4c226SZixu Wang 214*aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 215*aebe5fc6SDaniel Grumberg return true; 216*aebe5fc6SDaniel Grumberg 21771b4c226SZixu Wang // Collect symbol information. 21871b4c226SZixu Wang StringRef Name = Decl->getName(); 2199fc45ca0SDaniel Grumberg if (Name.empty()) 2209fc45ca0SDaniel Grumberg Name = getTypedefName(Decl); 22171b4c226SZixu Wang StringRef USR = API.recordUSR(Decl); 22271b4c226SZixu Wang PresumedLoc Loc = 22371b4c226SZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 22471b4c226SZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 22571b4c226SZixu Wang DocComment Comment; 22671b4c226SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 22771b4c226SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 22871b4c226SZixu Wang Context.getDiagnostics()); 22971b4c226SZixu Wang 23071b4c226SZixu Wang // Build declaration fragments and sub-heading for the enum. 23171b4c226SZixu Wang DeclarationFragments Declaration = 23271b4c226SZixu Wang DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); 23371b4c226SZixu Wang DeclarationFragments SubHeading = 23471b4c226SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 23571b4c226SZixu Wang 23671b4c226SZixu Wang EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment, 23771b4c226SZixu Wang Declaration, SubHeading); 23871b4c226SZixu Wang 23971b4c226SZixu Wang // Now collect information about the enumerators in this enum. 24071b4c226SZixu Wang recordEnumConstants(EnumRecord, Decl->enumerators()); 24171b4c226SZixu Wang 24271b4c226SZixu Wang return true; 24371b4c226SZixu Wang } 24471b4c226SZixu Wang 2455bb5704cSZixu Wang bool VisitRecordDecl(const RecordDecl *Decl) { 2465bb5704cSZixu Wang if (!Decl->isCompleteDefinition()) 2475bb5704cSZixu Wang return true; 2485bb5704cSZixu Wang 2495bb5704cSZixu Wang // Skip C++ structs/classes/unions 2505bb5704cSZixu Wang // TODO: support C++ records 2515bb5704cSZixu Wang if (isa<CXXRecordDecl>(Decl)) 2525bb5704cSZixu Wang return true; 2535bb5704cSZixu Wang 254*aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 255*aebe5fc6SDaniel Grumberg return true; 256*aebe5fc6SDaniel Grumberg 2575bb5704cSZixu Wang // Collect symbol information. 2585bb5704cSZixu Wang StringRef Name = Decl->getName(); 2599fc45ca0SDaniel Grumberg if (Name.empty()) 2609fc45ca0SDaniel Grumberg Name = getTypedefName(Decl); 2615bb5704cSZixu Wang StringRef USR = API.recordUSR(Decl); 2625bb5704cSZixu Wang PresumedLoc Loc = 2635bb5704cSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 2645bb5704cSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 2655bb5704cSZixu Wang DocComment Comment; 2665bb5704cSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 2675bb5704cSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 2685bb5704cSZixu Wang Context.getDiagnostics()); 2695bb5704cSZixu Wang 2705bb5704cSZixu Wang // Build declaration fragments and sub-heading for the struct. 2715bb5704cSZixu Wang DeclarationFragments Declaration = 2725bb5704cSZixu Wang DeclarationFragmentsBuilder::getFragmentsForStruct(Decl); 2735bb5704cSZixu Wang DeclarationFragments SubHeading = 2745bb5704cSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 2755bb5704cSZixu Wang 2765bb5704cSZixu Wang StructRecord *StructRecord = API.addStruct( 2775bb5704cSZixu Wang Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 2785bb5704cSZixu Wang 2795bb5704cSZixu Wang // Now collect information about the fields in this struct. 2805bb5704cSZixu Wang recordStructFields(StructRecord, Decl->fields()); 2815bb5704cSZixu Wang 2825bb5704cSZixu Wang return true; 2835bb5704cSZixu Wang } 2845bb5704cSZixu Wang 2859b36e126SZixu Wang bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) { 2869b36e126SZixu Wang // Skip forward declaration for classes (@class) 2879b36e126SZixu Wang if (!Decl->isThisDeclarationADefinition()) 2889b36e126SZixu Wang return true; 2899b36e126SZixu Wang 290*aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 291*aebe5fc6SDaniel Grumberg return true; 292*aebe5fc6SDaniel Grumberg 2939b36e126SZixu Wang // Collect symbol information. 2949b36e126SZixu Wang StringRef Name = Decl->getName(); 2959b36e126SZixu Wang StringRef USR = API.recordUSR(Decl); 2969b36e126SZixu Wang PresumedLoc Loc = 2979b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 2989b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 2999b36e126SZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 3009b36e126SZixu Wang DocComment Comment; 3019b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 3029b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 3039b36e126SZixu Wang Context.getDiagnostics()); 3049b36e126SZixu Wang 3059b36e126SZixu Wang // Build declaration fragments and sub-heading for the interface. 3069b36e126SZixu Wang DeclarationFragments Declaration = 3079b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl); 3089b36e126SZixu Wang DeclarationFragments SubHeading = 3099b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 3109b36e126SZixu Wang 3119b36e126SZixu Wang // Collect super class information. 3129b36e126SZixu Wang SymbolReference SuperClass; 3139b36e126SZixu Wang if (const auto *SuperClassDecl = Decl->getSuperClass()) { 3149b36e126SZixu Wang SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); 3159b36e126SZixu Wang SuperClass.USR = API.recordUSR(SuperClassDecl); 3169b36e126SZixu Wang } 3179b36e126SZixu Wang 3189b36e126SZixu Wang ObjCInterfaceRecord *ObjCInterfaceRecord = 3199b36e126SZixu Wang API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment, 3209b36e126SZixu Wang Declaration, SubHeading, SuperClass); 3219b36e126SZixu Wang 3229b36e126SZixu Wang // Record all methods (selectors). This doesn't include automatically 3239b36e126SZixu Wang // synthesized property methods. 3249b36e126SZixu Wang recordObjCMethods(ObjCInterfaceRecord, Decl->methods()); 3259b36e126SZixu Wang recordObjCProperties(ObjCInterfaceRecord, Decl->properties()); 3269b36e126SZixu Wang recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars()); 3279b36e126SZixu Wang recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols()); 3289b36e126SZixu Wang 3299b36e126SZixu Wang return true; 3309b36e126SZixu Wang } 3319b36e126SZixu Wang 332d1d34bafSZixu Wang bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) { 333d1d34bafSZixu Wang // Skip forward declaration for protocols (@protocol). 334d1d34bafSZixu Wang if (!Decl->isThisDeclarationADefinition()) 335d1d34bafSZixu Wang return true; 336d1d34bafSZixu Wang 337*aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 338*aebe5fc6SDaniel Grumberg return true; 339*aebe5fc6SDaniel Grumberg 340d1d34bafSZixu Wang // Collect symbol information. 341d1d34bafSZixu Wang StringRef Name = Decl->getName(); 342d1d34bafSZixu Wang StringRef USR = API.recordUSR(Decl); 343d1d34bafSZixu Wang PresumedLoc Loc = 344d1d34bafSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 345d1d34bafSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 346d1d34bafSZixu Wang DocComment Comment; 347d1d34bafSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 348d1d34bafSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 349d1d34bafSZixu Wang Context.getDiagnostics()); 350d1d34bafSZixu Wang 351d1d34bafSZixu Wang // Build declaration fragments and sub-heading for the protocol. 352d1d34bafSZixu Wang DeclarationFragments Declaration = 353d1d34bafSZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl); 354d1d34bafSZixu Wang DeclarationFragments SubHeading = 355d1d34bafSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 356d1d34bafSZixu Wang 357d1d34bafSZixu Wang ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol( 358d1d34bafSZixu Wang Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 359d1d34bafSZixu Wang 360d1d34bafSZixu Wang recordObjCMethods(ObjCProtocolRecord, Decl->methods()); 361d1d34bafSZixu Wang recordObjCProperties(ObjCProtocolRecord, Decl->properties()); 362d1d34bafSZixu Wang recordObjCProtocols(ObjCProtocolRecord, Decl->protocols()); 363d1d34bafSZixu Wang 364d1d34bafSZixu Wang return true; 365d1d34bafSZixu Wang } 366d1d34bafSZixu Wang 3679fc45ca0SDaniel Grumberg bool VisitTypedefNameDecl(const TypedefNameDecl *Decl) { 3689fc45ca0SDaniel Grumberg // Skip ObjC Type Parameter for now. 3699fc45ca0SDaniel Grumberg if (isa<ObjCTypeParamDecl>(Decl)) 3709fc45ca0SDaniel Grumberg return true; 3719fc45ca0SDaniel Grumberg 3729fc45ca0SDaniel Grumberg if (!Decl->isDefinedOutsideFunctionOrMethod()) 3739fc45ca0SDaniel Grumberg return true; 3749fc45ca0SDaniel Grumberg 375*aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(Decl->getLocation())) 376*aebe5fc6SDaniel Grumberg return true; 377*aebe5fc6SDaniel Grumberg 3789fc45ca0SDaniel Grumberg PresumedLoc Loc = 3799fc45ca0SDaniel Grumberg Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 3809fc45ca0SDaniel Grumberg StringRef Name = Decl->getName(); 3819fc45ca0SDaniel Grumberg AvailabilityInfo Availability = getAvailability(Decl); 3829fc45ca0SDaniel Grumberg StringRef USR = API.recordUSR(Decl); 3839fc45ca0SDaniel Grumberg DocComment Comment; 3849fc45ca0SDaniel Grumberg if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 3859fc45ca0SDaniel Grumberg Comment = RawComment->getFormattedLines(Context.getSourceManager(), 3869fc45ca0SDaniel Grumberg Context.getDiagnostics()); 3879fc45ca0SDaniel Grumberg 3889fc45ca0SDaniel Grumberg QualType Type = Decl->getUnderlyingType(); 3899fc45ca0SDaniel Grumberg SymbolReference SymRef = 3909fc45ca0SDaniel Grumberg TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type, 3919fc45ca0SDaniel Grumberg API); 3929fc45ca0SDaniel Grumberg 3939fc45ca0SDaniel Grumberg API.addTypedef(Name, USR, Loc, Availability, Comment, 3949fc45ca0SDaniel Grumberg DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), 3959fc45ca0SDaniel Grumberg DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef); 3969fc45ca0SDaniel Grumberg 3979fc45ca0SDaniel Grumberg return true; 3989fc45ca0SDaniel Grumberg } 3999fc45ca0SDaniel Grumberg 400178aad9bSZixu Wang bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) { 401178aad9bSZixu Wang // Collect symbol information. 402178aad9bSZixu Wang StringRef Name = Decl->getName(); 403178aad9bSZixu Wang StringRef USR = API.recordUSR(Decl); 404178aad9bSZixu Wang PresumedLoc Loc = 405178aad9bSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 406178aad9bSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 407178aad9bSZixu Wang DocComment Comment; 408178aad9bSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 409178aad9bSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 410178aad9bSZixu Wang Context.getDiagnostics()); 411178aad9bSZixu Wang // Build declaration fragments and sub-heading for the category. 412178aad9bSZixu Wang DeclarationFragments Declaration = 413178aad9bSZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl); 414178aad9bSZixu Wang DeclarationFragments SubHeading = 415178aad9bSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 416178aad9bSZixu Wang 417178aad9bSZixu Wang const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface(); 418178aad9bSZixu Wang SymbolReference Interface(InterfaceDecl->getName(), 419178aad9bSZixu Wang API.recordUSR(InterfaceDecl)); 420178aad9bSZixu Wang 421178aad9bSZixu Wang ObjCCategoryRecord *ObjCCategoryRecord = 422178aad9bSZixu Wang API.addObjCCategory(Name, USR, Loc, Availability, Comment, Declaration, 423178aad9bSZixu Wang SubHeading, Interface); 424178aad9bSZixu Wang 425178aad9bSZixu Wang recordObjCMethods(ObjCCategoryRecord, Decl->methods()); 426178aad9bSZixu Wang recordObjCProperties(ObjCCategoryRecord, Decl->properties()); 427178aad9bSZixu Wang recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars()); 428178aad9bSZixu Wang recordObjCProtocols(ObjCCategoryRecord, Decl->protocols()); 429178aad9bSZixu Wang 430178aad9bSZixu Wang return true; 431178aad9bSZixu Wang } 432178aad9bSZixu Wang 43389f6b26fSZixu Wang private: 43489f6b26fSZixu Wang /// Get availability information of the declaration \p D. 43589f6b26fSZixu Wang AvailabilityInfo getAvailability(const Decl *D) const { 43689f6b26fSZixu Wang StringRef PlatformName = Context.getTargetInfo().getPlatformName(); 43789f6b26fSZixu Wang 43889f6b26fSZixu Wang AvailabilityInfo Availability; 43989f6b26fSZixu Wang // Collect availability attributes from all redeclarations. 44089f6b26fSZixu Wang for (const auto *RD : D->redecls()) { 44189f6b26fSZixu Wang for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) { 44289f6b26fSZixu Wang if (A->getPlatform()->getName() != PlatformName) 44389f6b26fSZixu Wang continue; 44489f6b26fSZixu Wang Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(), 44589f6b26fSZixu Wang A->getObsoleted(), A->getUnavailable(), 44689f6b26fSZixu Wang /* UnconditionallyDeprecated */ false, 44789f6b26fSZixu Wang /* UnconditionallyUnavailable */ false); 44889f6b26fSZixu Wang break; 44989f6b26fSZixu Wang } 45089f6b26fSZixu Wang 45189f6b26fSZixu Wang if (const auto *A = RD->getAttr<UnavailableAttr>()) 45289f6b26fSZixu Wang if (!A->isImplicit()) { 45389f6b26fSZixu Wang Availability.Unavailable = true; 45489f6b26fSZixu Wang Availability.UnconditionallyUnavailable = true; 45589f6b26fSZixu Wang } 45689f6b26fSZixu Wang 45789f6b26fSZixu Wang if (const auto *A = RD->getAttr<DeprecatedAttr>()) 45889f6b26fSZixu Wang if (!A->isImplicit()) 45989f6b26fSZixu Wang Availability.UnconditionallyDeprecated = true; 46089f6b26fSZixu Wang } 46189f6b26fSZixu Wang 46289f6b26fSZixu Wang return Availability; 46389f6b26fSZixu Wang } 46489f6b26fSZixu Wang 46571b4c226SZixu Wang /// Collect API information for the enum constants and associate with the 46671b4c226SZixu Wang /// parent enum. 46771b4c226SZixu Wang void recordEnumConstants(EnumRecord *EnumRecord, 46871b4c226SZixu Wang const EnumDecl::enumerator_range Constants) { 46971b4c226SZixu Wang for (const auto *Constant : Constants) { 47071b4c226SZixu Wang // Collect symbol information. 47171b4c226SZixu Wang StringRef Name = Constant->getName(); 47271b4c226SZixu Wang StringRef USR = API.recordUSR(Constant); 47371b4c226SZixu Wang PresumedLoc Loc = 47471b4c226SZixu Wang Context.getSourceManager().getPresumedLoc(Constant->getLocation()); 47571b4c226SZixu Wang AvailabilityInfo Availability = getAvailability(Constant); 47671b4c226SZixu Wang DocComment Comment; 47771b4c226SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant)) 47871b4c226SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 47971b4c226SZixu Wang Context.getDiagnostics()); 48071b4c226SZixu Wang 48171b4c226SZixu Wang // Build declaration fragments and sub-heading for the enum constant. 48271b4c226SZixu Wang DeclarationFragments Declaration = 48371b4c226SZixu Wang DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant); 48471b4c226SZixu Wang DeclarationFragments SubHeading = 48571b4c226SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Constant); 48671b4c226SZixu Wang 48771b4c226SZixu Wang API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment, 48871b4c226SZixu Wang Declaration, SubHeading); 48971b4c226SZixu Wang } 49071b4c226SZixu Wang } 49171b4c226SZixu Wang 4925bb5704cSZixu Wang /// Collect API information for the struct fields and associate with the 4935bb5704cSZixu Wang /// parent struct. 4945bb5704cSZixu Wang void recordStructFields(StructRecord *StructRecord, 4955bb5704cSZixu Wang const RecordDecl::field_range Fields) { 4965bb5704cSZixu Wang for (const auto *Field : Fields) { 4975bb5704cSZixu Wang // Collect symbol information. 4985bb5704cSZixu Wang StringRef Name = Field->getName(); 4995bb5704cSZixu Wang StringRef USR = API.recordUSR(Field); 5005bb5704cSZixu Wang PresumedLoc Loc = 5015bb5704cSZixu Wang Context.getSourceManager().getPresumedLoc(Field->getLocation()); 5025bb5704cSZixu Wang AvailabilityInfo Availability = getAvailability(Field); 5035bb5704cSZixu Wang DocComment Comment; 5045bb5704cSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field)) 5055bb5704cSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 5065bb5704cSZixu Wang Context.getDiagnostics()); 5075bb5704cSZixu Wang 5085bb5704cSZixu Wang // Build declaration fragments and sub-heading for the struct field. 5095bb5704cSZixu Wang DeclarationFragments Declaration = 5105bb5704cSZixu Wang DeclarationFragmentsBuilder::getFragmentsForField(Field); 5115bb5704cSZixu Wang DeclarationFragments SubHeading = 5125bb5704cSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Field); 5135bb5704cSZixu Wang 5145bb5704cSZixu Wang API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment, 5155bb5704cSZixu Wang Declaration, SubHeading); 5165bb5704cSZixu Wang } 5175bb5704cSZixu Wang } 5185bb5704cSZixu Wang 5199b36e126SZixu Wang /// Collect API information for the Objective-C methods and associate with the 5209b36e126SZixu Wang /// parent container. 5219b36e126SZixu Wang void recordObjCMethods(ObjCContainerRecord *Container, 5229b36e126SZixu Wang const ObjCContainerDecl::method_range Methods) { 5239b36e126SZixu Wang for (const auto *Method : Methods) { 5249b36e126SZixu Wang // Don't record selectors for properties. 5259b36e126SZixu Wang if (Method->isPropertyAccessor()) 5269b36e126SZixu Wang continue; 5279b36e126SZixu Wang 5289b36e126SZixu Wang StringRef Name = API.copyString(Method->getSelector().getAsString()); 5299b36e126SZixu Wang StringRef USR = API.recordUSR(Method); 5309b36e126SZixu Wang PresumedLoc Loc = 5319b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Method->getLocation()); 5329b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Method); 5339b36e126SZixu Wang DocComment Comment; 5349b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method)) 5359b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 5369b36e126SZixu Wang Context.getDiagnostics()); 5379b36e126SZixu Wang 5389b36e126SZixu Wang // Build declaration fragments, sub-heading, and signature for the method. 5399b36e126SZixu Wang DeclarationFragments Declaration = 5409b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method); 5419b36e126SZixu Wang DeclarationFragments SubHeading = 5429b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Method); 5439b36e126SZixu Wang FunctionSignature Signature = 5449b36e126SZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Method); 5459b36e126SZixu Wang 5469b36e126SZixu Wang API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment, 5479b36e126SZixu Wang Declaration, SubHeading, Signature, 5489b36e126SZixu Wang Method->isInstanceMethod()); 5499b36e126SZixu Wang } 5509b36e126SZixu Wang } 5519b36e126SZixu Wang 5529b36e126SZixu Wang void recordObjCProperties(ObjCContainerRecord *Container, 5539b36e126SZixu Wang const ObjCContainerDecl::prop_range Properties) { 5549b36e126SZixu Wang for (const auto *Property : Properties) { 5559b36e126SZixu Wang StringRef Name = Property->getName(); 5569b36e126SZixu Wang StringRef USR = API.recordUSR(Property); 5579b36e126SZixu Wang PresumedLoc Loc = 5589b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Property->getLocation()); 5599b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Property); 5609b36e126SZixu Wang DocComment Comment; 5619b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property)) 5629b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 5639b36e126SZixu Wang Context.getDiagnostics()); 5649b36e126SZixu Wang 5659b36e126SZixu Wang // Build declaration fragments and sub-heading for the property. 5669b36e126SZixu Wang DeclarationFragments Declaration = 5679b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property); 5689b36e126SZixu Wang DeclarationFragments SubHeading = 5699b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Property); 5709b36e126SZixu Wang 5719b36e126SZixu Wang StringRef GetterName = 5729b36e126SZixu Wang API.copyString(Property->getGetterName().getAsString()); 5739b36e126SZixu Wang StringRef SetterName = 5749b36e126SZixu Wang API.copyString(Property->getSetterName().getAsString()); 5759b36e126SZixu Wang 5769b36e126SZixu Wang // Get the attributes for property. 5779b36e126SZixu Wang unsigned Attributes = ObjCPropertyRecord::NoAttr; 5789b36e126SZixu Wang if (Property->getPropertyAttributes() & 5799b36e126SZixu Wang ObjCPropertyAttribute::kind_readonly) 5809b36e126SZixu Wang Attributes |= ObjCPropertyRecord::ReadOnly; 5819b36e126SZixu Wang if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class) 5829b36e126SZixu Wang Attributes |= ObjCPropertyRecord::Class; 5839b36e126SZixu Wang 5849b36e126SZixu Wang API.addObjCProperty( 5859b36e126SZixu Wang Container, Name, USR, Loc, Availability, Comment, Declaration, 5869b36e126SZixu Wang SubHeading, 5879b36e126SZixu Wang static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), 5889b36e126SZixu Wang GetterName, SetterName, Property->isOptional()); 5899b36e126SZixu Wang } 5909b36e126SZixu Wang } 5919b36e126SZixu Wang 5929b36e126SZixu Wang void recordObjCInstanceVariables( 5939b36e126SZixu Wang ObjCContainerRecord *Container, 5949b36e126SZixu Wang const llvm::iterator_range< 5959b36e126SZixu Wang DeclContext::specific_decl_iterator<ObjCIvarDecl>> 5969b36e126SZixu Wang Ivars) { 5979b36e126SZixu Wang for (const auto *Ivar : Ivars) { 5989b36e126SZixu Wang StringRef Name = Ivar->getName(); 5999b36e126SZixu Wang StringRef USR = API.recordUSR(Ivar); 6009b36e126SZixu Wang PresumedLoc Loc = 6019b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); 6029b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Ivar); 6039b36e126SZixu Wang DocComment Comment; 6049b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar)) 6059b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 6069b36e126SZixu Wang Context.getDiagnostics()); 6079b36e126SZixu Wang 6089b36e126SZixu Wang // Build declaration fragments and sub-heading for the instance variable. 6099b36e126SZixu Wang DeclarationFragments Declaration = 6109b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForField(Ivar); 6119b36e126SZixu Wang DeclarationFragments SubHeading = 6129b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Ivar); 6139b36e126SZixu Wang 6149b36e126SZixu Wang ObjCInstanceVariableRecord::AccessControl Access = 6159b36e126SZixu Wang Ivar->getCanonicalAccessControl(); 6169b36e126SZixu Wang 6179b36e126SZixu Wang API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability, 6189b36e126SZixu Wang Comment, Declaration, SubHeading, Access); 6199b36e126SZixu Wang } 6209b36e126SZixu Wang } 6219b36e126SZixu Wang 6229b36e126SZixu Wang void recordObjCProtocols(ObjCContainerRecord *Container, 6239b36e126SZixu Wang ObjCInterfaceDecl::protocol_range Protocols) { 6249b36e126SZixu Wang for (const auto *Protocol : Protocols) 6259b36e126SZixu Wang Container->Protocols.emplace_back(Protocol->getName(), 6269b36e126SZixu Wang API.recordUSR(Protocol)); 6279b36e126SZixu Wang } 6289b36e126SZixu Wang 62989f6b26fSZixu Wang ASTContext &Context; 630a9909d23SDaniel Grumberg APISet &API; 631*aebe5fc6SDaniel Grumberg LocationFileChecker &LCF; 63289f6b26fSZixu Wang }; 63389f6b26fSZixu Wang 63489f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer { 63589f6b26fSZixu Wang public: 636*aebe5fc6SDaniel Grumberg ExtractAPIConsumer(ASTContext &Context, 637*aebe5fc6SDaniel Grumberg std::unique_ptr<LocationFileChecker> LCF, APISet &API) 638*aebe5fc6SDaniel Grumberg : Visitor(Context, *LCF, API), LCF(std::move(LCF)) {} 63989f6b26fSZixu Wang 64089f6b26fSZixu Wang void HandleTranslationUnit(ASTContext &Context) override { 64189f6b26fSZixu Wang // Use ExtractAPIVisitor to traverse symbol declarations in the context. 64289f6b26fSZixu Wang Visitor.TraverseDecl(Context.getTranslationUnitDecl()); 64389f6b26fSZixu Wang } 64489f6b26fSZixu Wang 64589f6b26fSZixu Wang private: 64689f6b26fSZixu Wang ExtractAPIVisitor Visitor; 647*aebe5fc6SDaniel Grumberg std::unique_ptr<LocationFileChecker> LCF; 64889f6b26fSZixu Wang }; 64989f6b26fSZixu Wang 650529a0570SDaniel Grumberg class MacroCallback : public PPCallbacks { 651529a0570SDaniel Grumberg public: 652*aebe5fc6SDaniel Grumberg MacroCallback(const SourceManager &SM, LocationFileChecker &LCF, APISet &API) 653*aebe5fc6SDaniel Grumberg : SM(SM), LCF(LCF), API(API) {} 654529a0570SDaniel Grumberg 655529a0570SDaniel Grumberg void MacroDefined(const Token &MacroNameToken, 656529a0570SDaniel Grumberg const MacroDirective *MD) override { 657529a0570SDaniel Grumberg auto *MacroInfo = MD->getMacroInfo(); 658529a0570SDaniel Grumberg 659529a0570SDaniel Grumberg if (MacroInfo->isBuiltinMacro()) 660529a0570SDaniel Grumberg return; 661529a0570SDaniel Grumberg 662529a0570SDaniel Grumberg auto SourceLoc = MacroNameToken.getLocation(); 663529a0570SDaniel Grumberg if (SM.isWrittenInBuiltinFile(SourceLoc) || 664529a0570SDaniel Grumberg SM.isWrittenInCommandLineFile(SourceLoc)) 665529a0570SDaniel Grumberg return; 666529a0570SDaniel Grumberg 667529a0570SDaniel Grumberg PendingMacros.emplace_back(MacroNameToken, MD); 668529a0570SDaniel Grumberg } 669529a0570SDaniel Grumberg 670529a0570SDaniel Grumberg // If a macro gets undefined at some point during preprocessing of the inputs 671529a0570SDaniel Grumberg // it means that it isn't an exposed API and we should therefore not add a 672529a0570SDaniel Grumberg // macro definition for it. 673529a0570SDaniel Grumberg void MacroUndefined(const Token &MacroNameToken, const MacroDefinition &MD, 674529a0570SDaniel Grumberg const MacroDirective *Undef) override { 6758b63622bSDaniel Grumberg // If this macro wasn't previously defined we don't need to do anything 6768b63622bSDaniel Grumberg // here. 6778b63622bSDaniel Grumberg if (!Undef) 6788b63622bSDaniel Grumberg return; 6798b63622bSDaniel Grumberg 680529a0570SDaniel Grumberg llvm::erase_if(PendingMacros, [&MD](const PendingMacro &PM) { 681529a0570SDaniel Grumberg return MD.getMacroInfo()->getDefinitionLoc() == 682529a0570SDaniel Grumberg PM.MD->getMacroInfo()->getDefinitionLoc(); 683529a0570SDaniel Grumberg }); 684529a0570SDaniel Grumberg } 685529a0570SDaniel Grumberg 686529a0570SDaniel Grumberg void EndOfMainFile() override { 687529a0570SDaniel Grumberg for (auto &PM : PendingMacros) { 688529a0570SDaniel Grumberg // `isUsedForHeaderGuard` is only set when the preprocessor leaves the 689529a0570SDaniel Grumberg // file so check for it here. 690529a0570SDaniel Grumberg if (PM.MD->getMacroInfo()->isUsedForHeaderGuard()) 691529a0570SDaniel Grumberg continue; 692529a0570SDaniel Grumberg 693*aebe5fc6SDaniel Grumberg if (!LCF.isLocationInKnownFile(PM.MacroNameToken.getLocation())) 694*aebe5fc6SDaniel Grumberg continue; 695*aebe5fc6SDaniel Grumberg 696529a0570SDaniel Grumberg StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName(); 697529a0570SDaniel Grumberg PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation()); 698529a0570SDaniel Grumberg StringRef USR = 699529a0570SDaniel Grumberg API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM); 700529a0570SDaniel Grumberg 701529a0570SDaniel Grumberg API.addMacroDefinition( 702529a0570SDaniel Grumberg Name, USR, Loc, 703529a0570SDaniel Grumberg DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD), 704529a0570SDaniel Grumberg DeclarationFragmentsBuilder::getSubHeadingForMacro(Name)); 705529a0570SDaniel Grumberg } 706529a0570SDaniel Grumberg 707529a0570SDaniel Grumberg PendingMacros.clear(); 708529a0570SDaniel Grumberg } 709529a0570SDaniel Grumberg 710529a0570SDaniel Grumberg private: 711529a0570SDaniel Grumberg struct PendingMacro { 712529a0570SDaniel Grumberg Token MacroNameToken; 713529a0570SDaniel Grumberg const MacroDirective *MD; 714529a0570SDaniel Grumberg 715529a0570SDaniel Grumberg PendingMacro(const Token &MacroNameToken, const MacroDirective *MD) 716529a0570SDaniel Grumberg : MacroNameToken(MacroNameToken), MD(MD) {} 717529a0570SDaniel Grumberg }; 718529a0570SDaniel Grumberg 719529a0570SDaniel Grumberg const SourceManager &SM; 720*aebe5fc6SDaniel Grumberg LocationFileChecker &LCF; 721529a0570SDaniel Grumberg APISet &API; 722529a0570SDaniel Grumberg llvm::SmallVector<PendingMacro> PendingMacros; 723529a0570SDaniel Grumberg }; 724529a0570SDaniel Grumberg 72589f6b26fSZixu Wang } // namespace 72689f6b26fSZixu Wang 72789f6b26fSZixu Wang std::unique_ptr<ASTConsumer> 72889f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { 729a9909d23SDaniel Grumberg OS = CreateOutputFile(CI, InFile); 73089f6b26fSZixu Wang if (!OS) 73189f6b26fSZixu Wang return nullptr; 732a9909d23SDaniel Grumberg 733a9909d23SDaniel Grumberg ProductName = CI.getFrontendOpts().ProductName; 734a9909d23SDaniel Grumberg 735a9909d23SDaniel Grumberg // Now that we have enough information about the language options and the 736a9909d23SDaniel Grumberg // target triple, let's create the APISet before anyone uses it. 737a9909d23SDaniel Grumberg API = std::make_unique<APISet>( 738a9909d23SDaniel Grumberg CI.getTarget().getTriple(), 739a9909d23SDaniel Grumberg CI.getFrontendOpts().Inputs.back().getKind().getLanguage()); 740a9909d23SDaniel Grumberg 741*aebe5fc6SDaniel Grumberg auto LCF = std::make_unique<LocationFileChecker>(CI.getSourceManager(), 742*aebe5fc6SDaniel Grumberg KnownInputFiles); 743*aebe5fc6SDaniel Grumberg 744529a0570SDaniel Grumberg // Register preprocessor callbacks that will add macro definitions to API. 745529a0570SDaniel Grumberg CI.getPreprocessor().addPPCallbacks( 746*aebe5fc6SDaniel Grumberg std::make_unique<MacroCallback>(CI.getSourceManager(), *LCF, *API)); 747529a0570SDaniel Grumberg 748*aebe5fc6SDaniel Grumberg return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(), 749*aebe5fc6SDaniel Grumberg std::move(LCF), *API); 75089f6b26fSZixu Wang } 75189f6b26fSZixu Wang 752f833aab0SDaniel Grumberg bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { 753f833aab0SDaniel Grumberg auto &Inputs = CI.getFrontendOpts().Inputs; 754f833aab0SDaniel Grumberg if (Inputs.empty()) 755f833aab0SDaniel Grumberg return true; 756f833aab0SDaniel Grumberg 757f833aab0SDaniel Grumberg auto Kind = Inputs[0].getKind(); 758f833aab0SDaniel Grumberg 759f833aab0SDaniel Grumberg // Convert the header file inputs into a single input buffer. 760f833aab0SDaniel Grumberg SmallString<256> HeaderContents; 761f833aab0SDaniel Grumberg for (const FrontendInputFile &FIF : Inputs) { 762f833aab0SDaniel Grumberg if (Kind.isObjectiveC()) 763f833aab0SDaniel Grumberg HeaderContents += "#import"; 764f833aab0SDaniel Grumberg else 765f833aab0SDaniel Grumberg HeaderContents += "#include"; 766f833aab0SDaniel Grumberg HeaderContents += " \""; 767f833aab0SDaniel Grumberg HeaderContents += FIF.getFile(); 768f833aab0SDaniel Grumberg HeaderContents += "\"\n"; 769*aebe5fc6SDaniel Grumberg 770*aebe5fc6SDaniel Grumberg KnownInputFiles.emplace_back(FIF.getFile()); 771f833aab0SDaniel Grumberg } 772f833aab0SDaniel Grumberg 773985eaa1aSDaniel Grumberg Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents, 774f833aab0SDaniel Grumberg getInputBufferName()); 775f833aab0SDaniel Grumberg 776f833aab0SDaniel Grumberg // Set that buffer up as our "real" input in the CompilerInstance. 777f833aab0SDaniel Grumberg Inputs.clear(); 778f833aab0SDaniel Grumberg Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false); 779f833aab0SDaniel Grumberg 780f833aab0SDaniel Grumberg return true; 781f833aab0SDaniel Grumberg } 782f833aab0SDaniel Grumberg 783a9909d23SDaniel Grumberg void ExtractAPIAction::EndSourceFileAction() { 784a9909d23SDaniel Grumberg if (!OS) 785a9909d23SDaniel Grumberg return; 786a9909d23SDaniel Grumberg 787a9909d23SDaniel Grumberg // Setup a SymbolGraphSerializer to write out collected API information in 788a9909d23SDaniel Grumberg // the Symbol Graph format. 789a9909d23SDaniel Grumberg // FIXME: Make the kind of APISerializer configurable. 790a9909d23SDaniel Grumberg SymbolGraphSerializer SGSerializer(*API, ProductName); 791a9909d23SDaniel Grumberg SGSerializer.serialize(*OS); 792a9909d23SDaniel Grumberg OS->flush(); 793a9909d23SDaniel Grumberg } 794a9909d23SDaniel Grumberg 79589f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> 79689f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { 79789f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS = 79889f6b26fSZixu Wang CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json", 79989f6b26fSZixu Wang /*RemoveFileOnSignal=*/false); 80089f6b26fSZixu Wang if (!OS) 80189f6b26fSZixu Wang return nullptr; 80289f6b26fSZixu Wang return OS; 80389f6b26fSZixu Wang } 804