189f6b26fSZixu Wang //===- ExtractAPI/ExtractAPIConsumer.cpp ------------------------*- C++ -*-===// 289f6b26fSZixu Wang // 389f6b26fSZixu Wang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 489f6b26fSZixu Wang // See https://llvm.org/LICENSE.txt for license information. 589f6b26fSZixu Wang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 689f6b26fSZixu Wang // 789f6b26fSZixu Wang //===----------------------------------------------------------------------===// 889f6b26fSZixu Wang /// 989f6b26fSZixu Wang /// \file 1089f6b26fSZixu Wang /// This file implements the ExtractAPIAction, and ASTVisitor/Consumer to 1189f6b26fSZixu Wang /// collect API information. 1289f6b26fSZixu Wang /// 1389f6b26fSZixu Wang //===----------------------------------------------------------------------===// 1489f6b26fSZixu Wang 1589f6b26fSZixu Wang #include "clang/AST/ASTConsumer.h" 1689f6b26fSZixu Wang #include "clang/AST/ASTContext.h" 1789f6b26fSZixu Wang #include "clang/AST/Decl.h" 1889f6b26fSZixu Wang #include "clang/AST/DeclCXX.h" 1989f6b26fSZixu Wang #include "clang/AST/ParentMapContext.h" 2089f6b26fSZixu Wang #include "clang/AST/RawCommentList.h" 2189f6b26fSZixu Wang #include "clang/AST/RecursiveASTVisitor.h" 2289f6b26fSZixu Wang #include "clang/Basic/TargetInfo.h" 2389f6b26fSZixu Wang #include "clang/ExtractAPI/API.h" 2489f6b26fSZixu Wang #include "clang/ExtractAPI/AvailabilityInfo.h" 2589f6b26fSZixu Wang #include "clang/ExtractAPI/DeclarationFragments.h" 2689f6b26fSZixu Wang #include "clang/ExtractAPI/FrontendActions.h" 2789f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" 2889f6b26fSZixu Wang #include "clang/Frontend/ASTConsumers.h" 2989f6b26fSZixu Wang #include "clang/Frontend/CompilerInstance.h" 30f833aab0SDaniel Grumberg #include "clang/Frontend/FrontendOptions.h" 31529a0570SDaniel Grumberg #include "clang/Lex/MacroInfo.h" 32529a0570SDaniel Grumberg #include "clang/Lex/PPCallbacks.h" 33529a0570SDaniel Grumberg #include "clang/Lex/PreprocessorOptions.h" 34529a0570SDaniel Grumberg #include "llvm/ADT/STLExtras.h" 35f833aab0SDaniel Grumberg #include "llvm/ADT/SmallVector.h" 36f833aab0SDaniel Grumberg #include "llvm/Support/MemoryBuffer.h" 3789f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h" 3889f6b26fSZixu Wang 3989f6b26fSZixu Wang using namespace clang; 4089f6b26fSZixu Wang using namespace extractapi; 4189f6b26fSZixu Wang 4289f6b26fSZixu Wang namespace { 4389f6b26fSZixu Wang 4489f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API 4589f6b26fSZixu Wang /// information. 4689f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> { 4789f6b26fSZixu Wang public: 48a9909d23SDaniel Grumberg ExtractAPIVisitor(ASTContext &Context, APISet &API) 49a9909d23SDaniel Grumberg : Context(Context), API(API) {} 5089f6b26fSZixu Wang 5189f6b26fSZixu Wang const APISet &getAPI() const { return API; } 5289f6b26fSZixu Wang 5389f6b26fSZixu Wang bool VisitVarDecl(const VarDecl *Decl) { 5489f6b26fSZixu Wang // Skip function parameters. 5589f6b26fSZixu Wang if (isa<ParmVarDecl>(Decl)) 5689f6b26fSZixu Wang return true; 5789f6b26fSZixu Wang 5889f6b26fSZixu Wang // Skip non-global variables in records (struct/union/class). 5989f6b26fSZixu Wang if (Decl->getDeclContext()->isRecord()) 6089f6b26fSZixu Wang return true; 6189f6b26fSZixu Wang 6289f6b26fSZixu Wang // Skip local variables inside function or method. 6389f6b26fSZixu Wang if (!Decl->isDefinedOutsideFunctionOrMethod()) 6489f6b26fSZixu Wang return true; 6589f6b26fSZixu Wang 6689f6b26fSZixu Wang // If this is a template but not specialization or instantiation, skip. 6789f6b26fSZixu Wang if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && 6889f6b26fSZixu Wang Decl->getTemplateSpecializationKind() == TSK_Undeclared) 6989f6b26fSZixu Wang return true; 7089f6b26fSZixu Wang 7189f6b26fSZixu Wang // Collect symbol information. 7289f6b26fSZixu Wang StringRef Name = Decl->getName(); 7389f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 7489f6b26fSZixu Wang PresumedLoc Loc = 7589f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 7689f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 7789f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 7889f6b26fSZixu Wang DocComment Comment; 7989f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 8089f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 8189f6b26fSZixu Wang Context.getDiagnostics()); 8289f6b26fSZixu Wang 8389f6b26fSZixu Wang // Build declaration fragments and sub-heading for the variable. 8489f6b26fSZixu Wang DeclarationFragments Declaration = 8589f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForVar(Decl); 8689f6b26fSZixu Wang DeclarationFragments SubHeading = 8789f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 8889f6b26fSZixu Wang 8989f6b26fSZixu Wang // Add the global variable record to the API set. 9089f6b26fSZixu Wang API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment, 9189f6b26fSZixu Wang Declaration, SubHeading); 9289f6b26fSZixu Wang return true; 9389f6b26fSZixu Wang } 9489f6b26fSZixu Wang 9589f6b26fSZixu Wang bool VisitFunctionDecl(const FunctionDecl *Decl) { 9689f6b26fSZixu Wang if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) { 9789f6b26fSZixu Wang // Skip member function in class templates. 9889f6b26fSZixu Wang if (Method->getParent()->getDescribedClassTemplate() != nullptr) 9989f6b26fSZixu Wang return true; 10089f6b26fSZixu Wang 10189f6b26fSZixu Wang // Skip methods in records. 10289f6b26fSZixu Wang for (auto P : Context.getParents(*Method)) { 10389f6b26fSZixu Wang if (P.get<CXXRecordDecl>()) 10489f6b26fSZixu Wang return true; 10589f6b26fSZixu Wang } 10689f6b26fSZixu Wang 10789f6b26fSZixu Wang // Skip ConstructorDecl and DestructorDecl. 10889f6b26fSZixu Wang if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) 10989f6b26fSZixu Wang return true; 11089f6b26fSZixu Wang } 11189f6b26fSZixu Wang 11289f6b26fSZixu Wang // Skip templated functions. 11389f6b26fSZixu Wang switch (Decl->getTemplatedKind()) { 11489f6b26fSZixu Wang case FunctionDecl::TK_NonTemplate: 11589f6b26fSZixu Wang break; 11689f6b26fSZixu Wang case FunctionDecl::TK_MemberSpecialization: 11789f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplateSpecialization: 11889f6b26fSZixu Wang if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) { 11989f6b26fSZixu Wang if (!TemplateInfo->isExplicitInstantiationOrSpecialization()) 12089f6b26fSZixu Wang return true; 12189f6b26fSZixu Wang } 12289f6b26fSZixu Wang break; 12389f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplate: 12489f6b26fSZixu Wang case FunctionDecl::TK_DependentFunctionTemplateSpecialization: 12589f6b26fSZixu Wang return true; 12689f6b26fSZixu Wang } 12789f6b26fSZixu Wang 12889f6b26fSZixu Wang // Collect symbol information. 12989f6b26fSZixu Wang StringRef Name = Decl->getName(); 13089f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 13189f6b26fSZixu Wang PresumedLoc Loc = 13289f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 13389f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 13489f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 13589f6b26fSZixu Wang DocComment Comment; 13689f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 13789f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 13889f6b26fSZixu Wang Context.getDiagnostics()); 13989f6b26fSZixu Wang 14089f6b26fSZixu Wang // Build declaration fragments, sub-heading, and signature of the function. 14189f6b26fSZixu Wang DeclarationFragments Declaration = 14289f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); 14389f6b26fSZixu Wang DeclarationFragments SubHeading = 14489f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 14589f6b26fSZixu Wang FunctionSignature Signature = 14689f6b26fSZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Decl); 14789f6b26fSZixu Wang 14889f6b26fSZixu Wang // Add the function record to the API set. 14989f6b26fSZixu Wang API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration, 15089f6b26fSZixu Wang SubHeading, Signature); 15189f6b26fSZixu Wang return true; 15289f6b26fSZixu Wang } 15389f6b26fSZixu Wang 15471b4c226SZixu Wang bool VisitEnumDecl(const EnumDecl *Decl) { 15571b4c226SZixu Wang if (!Decl->isComplete()) 15671b4c226SZixu Wang return true; 15771b4c226SZixu Wang 15871b4c226SZixu Wang // Skip forward declaration. 15971b4c226SZixu Wang if (!Decl->isThisDeclarationADefinition()) 16071b4c226SZixu Wang return true; 16171b4c226SZixu Wang 16271b4c226SZixu Wang // Collect symbol information. 16371b4c226SZixu Wang StringRef Name = Decl->getName(); 16471b4c226SZixu Wang StringRef USR = API.recordUSR(Decl); 16571b4c226SZixu Wang PresumedLoc Loc = 16671b4c226SZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 16771b4c226SZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 16871b4c226SZixu Wang DocComment Comment; 16971b4c226SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 17071b4c226SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 17171b4c226SZixu Wang Context.getDiagnostics()); 17271b4c226SZixu Wang 17371b4c226SZixu Wang // Build declaration fragments and sub-heading for the enum. 17471b4c226SZixu Wang DeclarationFragments Declaration = 17571b4c226SZixu Wang DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); 17671b4c226SZixu Wang DeclarationFragments SubHeading = 17771b4c226SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 17871b4c226SZixu Wang 17971b4c226SZixu Wang EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment, 18071b4c226SZixu Wang Declaration, SubHeading); 18171b4c226SZixu Wang 18271b4c226SZixu Wang // Now collect information about the enumerators in this enum. 18371b4c226SZixu Wang recordEnumConstants(EnumRecord, Decl->enumerators()); 18471b4c226SZixu Wang 18571b4c226SZixu Wang return true; 18671b4c226SZixu Wang } 18771b4c226SZixu Wang 1885bb5704cSZixu Wang bool VisitRecordDecl(const RecordDecl *Decl) { 1895bb5704cSZixu Wang if (!Decl->isCompleteDefinition()) 1905bb5704cSZixu Wang return true; 1915bb5704cSZixu Wang 1925bb5704cSZixu Wang // Skip C++ structs/classes/unions 1935bb5704cSZixu Wang // TODO: support C++ records 1945bb5704cSZixu Wang if (isa<CXXRecordDecl>(Decl)) 1955bb5704cSZixu Wang return true; 1965bb5704cSZixu Wang 1975bb5704cSZixu Wang // Collect symbol information. 1985bb5704cSZixu Wang StringRef Name = Decl->getName(); 1995bb5704cSZixu Wang StringRef USR = API.recordUSR(Decl); 2005bb5704cSZixu Wang PresumedLoc Loc = 2015bb5704cSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 2025bb5704cSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 2035bb5704cSZixu Wang DocComment Comment; 2045bb5704cSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 2055bb5704cSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 2065bb5704cSZixu Wang Context.getDiagnostics()); 2075bb5704cSZixu Wang 2085bb5704cSZixu Wang // Build declaration fragments and sub-heading for the struct. 2095bb5704cSZixu Wang DeclarationFragments Declaration = 2105bb5704cSZixu Wang DeclarationFragmentsBuilder::getFragmentsForStruct(Decl); 2115bb5704cSZixu Wang DeclarationFragments SubHeading = 2125bb5704cSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 2135bb5704cSZixu Wang 2145bb5704cSZixu Wang StructRecord *StructRecord = API.addStruct( 2155bb5704cSZixu Wang Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 2165bb5704cSZixu Wang 2175bb5704cSZixu Wang // Now collect information about the fields in this struct. 2185bb5704cSZixu Wang recordStructFields(StructRecord, Decl->fields()); 2195bb5704cSZixu Wang 2205bb5704cSZixu Wang return true; 2215bb5704cSZixu Wang } 2225bb5704cSZixu Wang 2239b36e126SZixu Wang bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) { 2249b36e126SZixu Wang // Skip forward declaration for classes (@class) 2259b36e126SZixu Wang if (!Decl->isThisDeclarationADefinition()) 2269b36e126SZixu Wang return true; 2279b36e126SZixu Wang 2289b36e126SZixu Wang // Collect symbol information. 2299b36e126SZixu Wang StringRef Name = Decl->getName(); 2309b36e126SZixu Wang StringRef USR = API.recordUSR(Decl); 2319b36e126SZixu Wang PresumedLoc Loc = 2329b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 2339b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 2349b36e126SZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 2359b36e126SZixu Wang DocComment Comment; 2369b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 2379b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 2389b36e126SZixu Wang Context.getDiagnostics()); 2399b36e126SZixu Wang 2409b36e126SZixu Wang // Build declaration fragments and sub-heading for the interface. 2419b36e126SZixu Wang DeclarationFragments Declaration = 2429b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl); 2439b36e126SZixu Wang DeclarationFragments SubHeading = 2449b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 2459b36e126SZixu Wang 2469b36e126SZixu Wang // Collect super class information. 2479b36e126SZixu Wang SymbolReference SuperClass; 2489b36e126SZixu Wang if (const auto *SuperClassDecl = Decl->getSuperClass()) { 2499b36e126SZixu Wang SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); 2509b36e126SZixu Wang SuperClass.USR = API.recordUSR(SuperClassDecl); 2519b36e126SZixu Wang } 2529b36e126SZixu Wang 2539b36e126SZixu Wang ObjCInterfaceRecord *ObjCInterfaceRecord = 2549b36e126SZixu Wang API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment, 2559b36e126SZixu Wang Declaration, SubHeading, SuperClass); 2569b36e126SZixu Wang 2579b36e126SZixu Wang // Record all methods (selectors). This doesn't include automatically 2589b36e126SZixu Wang // synthesized property methods. 2599b36e126SZixu Wang recordObjCMethods(ObjCInterfaceRecord, Decl->methods()); 2609b36e126SZixu Wang recordObjCProperties(ObjCInterfaceRecord, Decl->properties()); 2619b36e126SZixu Wang recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars()); 2629b36e126SZixu Wang recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols()); 2639b36e126SZixu Wang 2649b36e126SZixu Wang return true; 2659b36e126SZixu Wang } 2669b36e126SZixu Wang 267d1d34bafSZixu Wang bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) { 268d1d34bafSZixu Wang // Skip forward declaration for protocols (@protocol). 269d1d34bafSZixu Wang if (!Decl->isThisDeclarationADefinition()) 270d1d34bafSZixu Wang return true; 271d1d34bafSZixu Wang 272d1d34bafSZixu Wang // Collect symbol information. 273d1d34bafSZixu Wang StringRef Name = Decl->getName(); 274d1d34bafSZixu Wang StringRef USR = API.recordUSR(Decl); 275d1d34bafSZixu Wang PresumedLoc Loc = 276d1d34bafSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 277d1d34bafSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 278d1d34bafSZixu Wang DocComment Comment; 279d1d34bafSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 280d1d34bafSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 281d1d34bafSZixu Wang Context.getDiagnostics()); 282d1d34bafSZixu Wang 283d1d34bafSZixu Wang // Build declaration fragments and sub-heading for the protocol. 284d1d34bafSZixu Wang DeclarationFragments Declaration = 285d1d34bafSZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl); 286d1d34bafSZixu Wang DeclarationFragments SubHeading = 287d1d34bafSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 288d1d34bafSZixu Wang 289d1d34bafSZixu Wang ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol( 290d1d34bafSZixu Wang Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 291d1d34bafSZixu Wang 292d1d34bafSZixu Wang recordObjCMethods(ObjCProtocolRecord, Decl->methods()); 293d1d34bafSZixu Wang recordObjCProperties(ObjCProtocolRecord, Decl->properties()); 294d1d34bafSZixu Wang recordObjCProtocols(ObjCProtocolRecord, Decl->protocols()); 295d1d34bafSZixu Wang 296d1d34bafSZixu Wang return true; 297d1d34bafSZixu Wang } 298d1d34bafSZixu Wang 29989f6b26fSZixu Wang private: 30089f6b26fSZixu Wang /// Get availability information of the declaration \p D. 30189f6b26fSZixu Wang AvailabilityInfo getAvailability(const Decl *D) const { 30289f6b26fSZixu Wang StringRef PlatformName = Context.getTargetInfo().getPlatformName(); 30389f6b26fSZixu Wang 30489f6b26fSZixu Wang AvailabilityInfo Availability; 30589f6b26fSZixu Wang // Collect availability attributes from all redeclarations. 30689f6b26fSZixu Wang for (const auto *RD : D->redecls()) { 30789f6b26fSZixu Wang for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) { 30889f6b26fSZixu Wang if (A->getPlatform()->getName() != PlatformName) 30989f6b26fSZixu Wang continue; 31089f6b26fSZixu Wang Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(), 31189f6b26fSZixu Wang A->getObsoleted(), A->getUnavailable(), 31289f6b26fSZixu Wang /* UnconditionallyDeprecated */ false, 31389f6b26fSZixu Wang /* UnconditionallyUnavailable */ false); 31489f6b26fSZixu Wang break; 31589f6b26fSZixu Wang } 31689f6b26fSZixu Wang 31789f6b26fSZixu Wang if (const auto *A = RD->getAttr<UnavailableAttr>()) 31889f6b26fSZixu Wang if (!A->isImplicit()) { 31989f6b26fSZixu Wang Availability.Unavailable = true; 32089f6b26fSZixu Wang Availability.UnconditionallyUnavailable = true; 32189f6b26fSZixu Wang } 32289f6b26fSZixu Wang 32389f6b26fSZixu Wang if (const auto *A = RD->getAttr<DeprecatedAttr>()) 32489f6b26fSZixu Wang if (!A->isImplicit()) 32589f6b26fSZixu Wang Availability.UnconditionallyDeprecated = true; 32689f6b26fSZixu Wang } 32789f6b26fSZixu Wang 32889f6b26fSZixu Wang return Availability; 32989f6b26fSZixu Wang } 33089f6b26fSZixu Wang 33171b4c226SZixu Wang /// Collect API information for the enum constants and associate with the 33271b4c226SZixu Wang /// parent enum. 33371b4c226SZixu Wang void recordEnumConstants(EnumRecord *EnumRecord, 33471b4c226SZixu Wang const EnumDecl::enumerator_range Constants) { 33571b4c226SZixu Wang for (const auto *Constant : Constants) { 33671b4c226SZixu Wang // Collect symbol information. 33771b4c226SZixu Wang StringRef Name = Constant->getName(); 33871b4c226SZixu Wang StringRef USR = API.recordUSR(Constant); 33971b4c226SZixu Wang PresumedLoc Loc = 34071b4c226SZixu Wang Context.getSourceManager().getPresumedLoc(Constant->getLocation()); 34171b4c226SZixu Wang AvailabilityInfo Availability = getAvailability(Constant); 34271b4c226SZixu Wang DocComment Comment; 34371b4c226SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant)) 34471b4c226SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 34571b4c226SZixu Wang Context.getDiagnostics()); 34671b4c226SZixu Wang 34771b4c226SZixu Wang // Build declaration fragments and sub-heading for the enum constant. 34871b4c226SZixu Wang DeclarationFragments Declaration = 34971b4c226SZixu Wang DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant); 35071b4c226SZixu Wang DeclarationFragments SubHeading = 35171b4c226SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Constant); 35271b4c226SZixu Wang 35371b4c226SZixu Wang API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment, 35471b4c226SZixu Wang Declaration, SubHeading); 35571b4c226SZixu Wang } 35671b4c226SZixu Wang } 35771b4c226SZixu Wang 3585bb5704cSZixu Wang /// Collect API information for the struct fields and associate with the 3595bb5704cSZixu Wang /// parent struct. 3605bb5704cSZixu Wang void recordStructFields(StructRecord *StructRecord, 3615bb5704cSZixu Wang const RecordDecl::field_range Fields) { 3625bb5704cSZixu Wang for (const auto *Field : Fields) { 3635bb5704cSZixu Wang // Collect symbol information. 3645bb5704cSZixu Wang StringRef Name = Field->getName(); 3655bb5704cSZixu Wang StringRef USR = API.recordUSR(Field); 3665bb5704cSZixu Wang PresumedLoc Loc = 3675bb5704cSZixu Wang Context.getSourceManager().getPresumedLoc(Field->getLocation()); 3685bb5704cSZixu Wang AvailabilityInfo Availability = getAvailability(Field); 3695bb5704cSZixu Wang DocComment Comment; 3705bb5704cSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field)) 3715bb5704cSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 3725bb5704cSZixu Wang Context.getDiagnostics()); 3735bb5704cSZixu Wang 3745bb5704cSZixu Wang // Build declaration fragments and sub-heading for the struct field. 3755bb5704cSZixu Wang DeclarationFragments Declaration = 3765bb5704cSZixu Wang DeclarationFragmentsBuilder::getFragmentsForField(Field); 3775bb5704cSZixu Wang DeclarationFragments SubHeading = 3785bb5704cSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Field); 3795bb5704cSZixu Wang 3805bb5704cSZixu Wang API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment, 3815bb5704cSZixu Wang Declaration, SubHeading); 3825bb5704cSZixu Wang } 3835bb5704cSZixu Wang } 3845bb5704cSZixu Wang 3859b36e126SZixu Wang /// Collect API information for the Objective-C methods and associate with the 3869b36e126SZixu Wang /// parent container. 3879b36e126SZixu Wang void recordObjCMethods(ObjCContainerRecord *Container, 3889b36e126SZixu Wang const ObjCContainerDecl::method_range Methods) { 3899b36e126SZixu Wang for (const auto *Method : Methods) { 3909b36e126SZixu Wang // Don't record selectors for properties. 3919b36e126SZixu Wang if (Method->isPropertyAccessor()) 3929b36e126SZixu Wang continue; 3939b36e126SZixu Wang 3949b36e126SZixu Wang StringRef Name = API.copyString(Method->getSelector().getAsString()); 3959b36e126SZixu Wang StringRef USR = API.recordUSR(Method); 3969b36e126SZixu Wang PresumedLoc Loc = 3979b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Method->getLocation()); 3989b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Method); 3999b36e126SZixu Wang DocComment Comment; 4009b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method)) 4019b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 4029b36e126SZixu Wang Context.getDiagnostics()); 4039b36e126SZixu Wang 4049b36e126SZixu Wang // Build declaration fragments, sub-heading, and signature for the method. 4059b36e126SZixu Wang DeclarationFragments Declaration = 4069b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method); 4079b36e126SZixu Wang DeclarationFragments SubHeading = 4089b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Method); 4099b36e126SZixu Wang FunctionSignature Signature = 4109b36e126SZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Method); 4119b36e126SZixu Wang 4129b36e126SZixu Wang API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment, 4139b36e126SZixu Wang Declaration, SubHeading, Signature, 4149b36e126SZixu Wang Method->isInstanceMethod()); 4159b36e126SZixu Wang } 4169b36e126SZixu Wang } 4179b36e126SZixu Wang 4189b36e126SZixu Wang void recordObjCProperties(ObjCContainerRecord *Container, 4199b36e126SZixu Wang const ObjCContainerDecl::prop_range Properties) { 4209b36e126SZixu Wang for (const auto *Property : Properties) { 4219b36e126SZixu Wang StringRef Name = Property->getName(); 4229b36e126SZixu Wang StringRef USR = API.recordUSR(Property); 4239b36e126SZixu Wang PresumedLoc Loc = 4249b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Property->getLocation()); 4259b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Property); 4269b36e126SZixu Wang DocComment Comment; 4279b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property)) 4289b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 4299b36e126SZixu Wang Context.getDiagnostics()); 4309b36e126SZixu Wang 4319b36e126SZixu Wang // Build declaration fragments and sub-heading for the property. 4329b36e126SZixu Wang DeclarationFragments Declaration = 4339b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property); 4349b36e126SZixu Wang DeclarationFragments SubHeading = 4359b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Property); 4369b36e126SZixu Wang 4379b36e126SZixu Wang StringRef GetterName = 4389b36e126SZixu Wang API.copyString(Property->getGetterName().getAsString()); 4399b36e126SZixu Wang StringRef SetterName = 4409b36e126SZixu Wang API.copyString(Property->getSetterName().getAsString()); 4419b36e126SZixu Wang 4429b36e126SZixu Wang // Get the attributes for property. 4439b36e126SZixu Wang unsigned Attributes = ObjCPropertyRecord::NoAttr; 4449b36e126SZixu Wang if (Property->getPropertyAttributes() & 4459b36e126SZixu Wang ObjCPropertyAttribute::kind_readonly) 4469b36e126SZixu Wang Attributes |= ObjCPropertyRecord::ReadOnly; 4479b36e126SZixu Wang if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class) 4489b36e126SZixu Wang Attributes |= ObjCPropertyRecord::Class; 4499b36e126SZixu Wang 4509b36e126SZixu Wang API.addObjCProperty( 4519b36e126SZixu Wang Container, Name, USR, Loc, Availability, Comment, Declaration, 4529b36e126SZixu Wang SubHeading, 4539b36e126SZixu Wang static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), 4549b36e126SZixu Wang GetterName, SetterName, Property->isOptional()); 4559b36e126SZixu Wang } 4569b36e126SZixu Wang } 4579b36e126SZixu Wang 4589b36e126SZixu Wang void recordObjCInstanceVariables( 4599b36e126SZixu Wang ObjCContainerRecord *Container, 4609b36e126SZixu Wang const llvm::iterator_range< 4619b36e126SZixu Wang DeclContext::specific_decl_iterator<ObjCIvarDecl>> 4629b36e126SZixu Wang Ivars) { 4639b36e126SZixu Wang for (const auto *Ivar : Ivars) { 4649b36e126SZixu Wang StringRef Name = Ivar->getName(); 4659b36e126SZixu Wang StringRef USR = API.recordUSR(Ivar); 4669b36e126SZixu Wang PresumedLoc Loc = 4679b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); 4689b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Ivar); 4699b36e126SZixu Wang DocComment Comment; 4709b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar)) 4719b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 4729b36e126SZixu Wang Context.getDiagnostics()); 4739b36e126SZixu Wang 4749b36e126SZixu Wang // Build declaration fragments and sub-heading for the instance variable. 4759b36e126SZixu Wang DeclarationFragments Declaration = 4769b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForField(Ivar); 4779b36e126SZixu Wang DeclarationFragments SubHeading = 4789b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Ivar); 4799b36e126SZixu Wang 4809b36e126SZixu Wang ObjCInstanceVariableRecord::AccessControl Access = 4819b36e126SZixu Wang Ivar->getCanonicalAccessControl(); 4829b36e126SZixu Wang 4839b36e126SZixu Wang API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability, 4849b36e126SZixu Wang Comment, Declaration, SubHeading, Access); 4859b36e126SZixu Wang } 4869b36e126SZixu Wang } 4879b36e126SZixu Wang 4889b36e126SZixu Wang void recordObjCProtocols(ObjCContainerRecord *Container, 4899b36e126SZixu Wang ObjCInterfaceDecl::protocol_range Protocols) { 4909b36e126SZixu Wang for (const auto *Protocol : Protocols) 4919b36e126SZixu Wang Container->Protocols.emplace_back(Protocol->getName(), 4929b36e126SZixu Wang API.recordUSR(Protocol)); 4939b36e126SZixu Wang } 4949b36e126SZixu Wang 49589f6b26fSZixu Wang ASTContext &Context; 496a9909d23SDaniel Grumberg APISet &API; 49789f6b26fSZixu Wang }; 49889f6b26fSZixu Wang 49989f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer { 50089f6b26fSZixu Wang public: 501a9909d23SDaniel Grumberg ExtractAPIConsumer(ASTContext &Context, APISet &API) 502a9909d23SDaniel Grumberg : Visitor(Context, API) {} 50389f6b26fSZixu Wang 50489f6b26fSZixu Wang void HandleTranslationUnit(ASTContext &Context) override { 50589f6b26fSZixu Wang // Use ExtractAPIVisitor to traverse symbol declarations in the context. 50689f6b26fSZixu Wang Visitor.TraverseDecl(Context.getTranslationUnitDecl()); 50789f6b26fSZixu Wang } 50889f6b26fSZixu Wang 50989f6b26fSZixu Wang private: 51089f6b26fSZixu Wang ExtractAPIVisitor Visitor; 51189f6b26fSZixu Wang }; 51289f6b26fSZixu Wang 513529a0570SDaniel Grumberg class MacroCallback : public PPCallbacks { 514529a0570SDaniel Grumberg public: 515529a0570SDaniel Grumberg MacroCallback(const SourceManager &SM, APISet &API) : SM(SM), API(API) {} 516529a0570SDaniel Grumberg 517529a0570SDaniel Grumberg void MacroDefined(const Token &MacroNameToken, 518529a0570SDaniel Grumberg const MacroDirective *MD) override { 519529a0570SDaniel Grumberg auto *MacroInfo = MD->getMacroInfo(); 520529a0570SDaniel Grumberg 521529a0570SDaniel Grumberg if (MacroInfo->isBuiltinMacro()) 522529a0570SDaniel Grumberg return; 523529a0570SDaniel Grumberg 524529a0570SDaniel Grumberg auto SourceLoc = MacroNameToken.getLocation(); 525529a0570SDaniel Grumberg if (SM.isWrittenInBuiltinFile(SourceLoc) || 526529a0570SDaniel Grumberg SM.isWrittenInCommandLineFile(SourceLoc)) 527529a0570SDaniel Grumberg return; 528529a0570SDaniel Grumberg 529529a0570SDaniel Grumberg PendingMacros.emplace_back(MacroNameToken, MD); 530529a0570SDaniel Grumberg } 531529a0570SDaniel Grumberg 532529a0570SDaniel Grumberg // If a macro gets undefined at some point during preprocessing of the inputs 533529a0570SDaniel Grumberg // it means that it isn't an exposed API and we should therefore not add a 534529a0570SDaniel Grumberg // macro definition for it. 535529a0570SDaniel Grumberg void MacroUndefined(const Token &MacroNameToken, const MacroDefinition &MD, 536529a0570SDaniel Grumberg const MacroDirective *Undef) override { 537529a0570SDaniel Grumberg llvm::erase_if(PendingMacros, [&MD](const PendingMacro &PM) { 538529a0570SDaniel Grumberg return MD.getMacroInfo()->getDefinitionLoc() == 539529a0570SDaniel Grumberg PM.MD->getMacroInfo()->getDefinitionLoc(); 540529a0570SDaniel Grumberg }); 541529a0570SDaniel Grumberg } 542529a0570SDaniel Grumberg 543529a0570SDaniel Grumberg void EndOfMainFile() override { 544529a0570SDaniel Grumberg for (auto &PM : PendingMacros) { 545529a0570SDaniel Grumberg // `isUsedForHeaderGuard` is only set when the preprocessor leaves the 546529a0570SDaniel Grumberg // file so check for it here. 547529a0570SDaniel Grumberg if (PM.MD->getMacroInfo()->isUsedForHeaderGuard()) 548529a0570SDaniel Grumberg continue; 549529a0570SDaniel Grumberg 550529a0570SDaniel Grumberg StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName(); 551529a0570SDaniel Grumberg PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation()); 552529a0570SDaniel Grumberg StringRef USR = 553529a0570SDaniel Grumberg API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM); 554529a0570SDaniel Grumberg 555529a0570SDaniel Grumberg API.addMacroDefinition( 556529a0570SDaniel Grumberg Name, USR, Loc, 557529a0570SDaniel Grumberg DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD), 558529a0570SDaniel Grumberg DeclarationFragmentsBuilder::getSubHeadingForMacro(Name)); 559529a0570SDaniel Grumberg } 560529a0570SDaniel Grumberg 561529a0570SDaniel Grumberg PendingMacros.clear(); 562529a0570SDaniel Grumberg } 563529a0570SDaniel Grumberg 564529a0570SDaniel Grumberg private: 565529a0570SDaniel Grumberg struct PendingMacro { 566529a0570SDaniel Grumberg Token MacroNameToken; 567529a0570SDaniel Grumberg const MacroDirective *MD; 568529a0570SDaniel Grumberg 569529a0570SDaniel Grumberg PendingMacro(const Token &MacroNameToken, const MacroDirective *MD) 570529a0570SDaniel Grumberg : MacroNameToken(MacroNameToken), MD(MD) {} 571529a0570SDaniel Grumberg }; 572529a0570SDaniel Grumberg 573529a0570SDaniel Grumberg const SourceManager &SM; 574529a0570SDaniel Grumberg APISet &API; 575529a0570SDaniel Grumberg llvm::SmallVector<PendingMacro> PendingMacros; 576529a0570SDaniel Grumberg }; 577529a0570SDaniel Grumberg 57889f6b26fSZixu Wang } // namespace 57989f6b26fSZixu Wang 58089f6b26fSZixu Wang std::unique_ptr<ASTConsumer> 58189f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { 582a9909d23SDaniel Grumberg OS = CreateOutputFile(CI, InFile); 58389f6b26fSZixu Wang if (!OS) 58489f6b26fSZixu Wang return nullptr; 585a9909d23SDaniel Grumberg 586a9909d23SDaniel Grumberg ProductName = CI.getFrontendOpts().ProductName; 587a9909d23SDaniel Grumberg 588a9909d23SDaniel Grumberg // Now that we have enough information about the language options and the 589a9909d23SDaniel Grumberg // target triple, let's create the APISet before anyone uses it. 590a9909d23SDaniel Grumberg API = std::make_unique<APISet>( 591a9909d23SDaniel Grumberg CI.getTarget().getTriple(), 592a9909d23SDaniel Grumberg CI.getFrontendOpts().Inputs.back().getKind().getLanguage()); 593a9909d23SDaniel Grumberg 594529a0570SDaniel Grumberg // Register preprocessor callbacks that will add macro definitions to API. 595529a0570SDaniel Grumberg CI.getPreprocessor().addPPCallbacks( 596529a0570SDaniel Grumberg std::make_unique<MacroCallback>(CI.getSourceManager(), *API)); 597529a0570SDaniel Grumberg 598a9909d23SDaniel Grumberg return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(), *API); 59989f6b26fSZixu Wang } 60089f6b26fSZixu Wang 601f833aab0SDaniel Grumberg bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { 602f833aab0SDaniel Grumberg auto &Inputs = CI.getFrontendOpts().Inputs; 603f833aab0SDaniel Grumberg if (Inputs.empty()) 604f833aab0SDaniel Grumberg return true; 605f833aab0SDaniel Grumberg 606f833aab0SDaniel Grumberg auto Kind = Inputs[0].getKind(); 607f833aab0SDaniel Grumberg 608f833aab0SDaniel Grumberg // Convert the header file inputs into a single input buffer. 609f833aab0SDaniel Grumberg SmallString<256> HeaderContents; 610f833aab0SDaniel Grumberg for (const FrontendInputFile &FIF : Inputs) { 611f833aab0SDaniel Grumberg if (Kind.isObjectiveC()) 612f833aab0SDaniel Grumberg HeaderContents += "#import"; 613f833aab0SDaniel Grumberg else 614f833aab0SDaniel Grumberg HeaderContents += "#include"; 615f833aab0SDaniel Grumberg HeaderContents += " \""; 616f833aab0SDaniel Grumberg HeaderContents += FIF.getFile(); 617f833aab0SDaniel Grumberg HeaderContents += "\"\n"; 618f833aab0SDaniel Grumberg } 619f833aab0SDaniel Grumberg 620*985eaa1aSDaniel Grumberg Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents, 621f833aab0SDaniel Grumberg getInputBufferName()); 622f833aab0SDaniel Grumberg 623f833aab0SDaniel Grumberg // Set that buffer up as our "real" input in the CompilerInstance. 624f833aab0SDaniel Grumberg Inputs.clear(); 625f833aab0SDaniel Grumberg Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false); 626f833aab0SDaniel Grumberg 627f833aab0SDaniel Grumberg return true; 628f833aab0SDaniel Grumberg } 629f833aab0SDaniel Grumberg 630a9909d23SDaniel Grumberg void ExtractAPIAction::EndSourceFileAction() { 631a9909d23SDaniel Grumberg if (!OS) 632a9909d23SDaniel Grumberg return; 633a9909d23SDaniel Grumberg 634a9909d23SDaniel Grumberg // Setup a SymbolGraphSerializer to write out collected API information in 635a9909d23SDaniel Grumberg // the Symbol Graph format. 636a9909d23SDaniel Grumberg // FIXME: Make the kind of APISerializer configurable. 637a9909d23SDaniel Grumberg SymbolGraphSerializer SGSerializer(*API, ProductName); 638a9909d23SDaniel Grumberg SGSerializer.serialize(*OS); 639a9909d23SDaniel Grumberg OS->flush(); 640a9909d23SDaniel Grumberg } 641a9909d23SDaniel Grumberg 64289f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> 64389f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { 64489f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS = 64589f6b26fSZixu Wang CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json", 64689f6b26fSZixu Wang /*RemoveFileOnSignal=*/false); 64789f6b26fSZixu Wang if (!OS) 64889f6b26fSZixu Wang return nullptr; 64989f6b26fSZixu Wang return OS; 65089f6b26fSZixu Wang } 651