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" 31f833aab0SDaniel Grumberg #include "llvm/ADT/SmallVector.h" 32f833aab0SDaniel Grumberg #include "llvm/Support/MemoryBuffer.h" 3389f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h" 3489f6b26fSZixu Wang 3589f6b26fSZixu Wang using namespace clang; 3689f6b26fSZixu Wang using namespace extractapi; 3789f6b26fSZixu Wang 3889f6b26fSZixu Wang namespace { 3989f6b26fSZixu Wang 4089f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API 4189f6b26fSZixu Wang /// information. 4289f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> { 4389f6b26fSZixu Wang public: 4415bf0e56SZixu Wang ExtractAPIVisitor(ASTContext &Context, Language Lang) 4515bf0e56SZixu Wang : Context(Context), API(Context.getTargetInfo().getTriple(), Lang) {} 4689f6b26fSZixu Wang 4789f6b26fSZixu Wang const APISet &getAPI() const { return API; } 4889f6b26fSZixu Wang 4989f6b26fSZixu Wang bool VisitVarDecl(const VarDecl *Decl) { 5089f6b26fSZixu Wang // Skip function parameters. 5189f6b26fSZixu Wang if (isa<ParmVarDecl>(Decl)) 5289f6b26fSZixu Wang return true; 5389f6b26fSZixu Wang 5489f6b26fSZixu Wang // Skip non-global variables in records (struct/union/class). 5589f6b26fSZixu Wang if (Decl->getDeclContext()->isRecord()) 5689f6b26fSZixu Wang return true; 5789f6b26fSZixu Wang 5889f6b26fSZixu Wang // Skip local variables inside function or method. 5989f6b26fSZixu Wang if (!Decl->isDefinedOutsideFunctionOrMethod()) 6089f6b26fSZixu Wang return true; 6189f6b26fSZixu Wang 6289f6b26fSZixu Wang // If this is a template but not specialization or instantiation, skip. 6389f6b26fSZixu Wang if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && 6489f6b26fSZixu Wang Decl->getTemplateSpecializationKind() == TSK_Undeclared) 6589f6b26fSZixu Wang return true; 6689f6b26fSZixu Wang 6789f6b26fSZixu Wang // Collect symbol information. 6889f6b26fSZixu Wang StringRef Name = Decl->getName(); 6989f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 7089f6b26fSZixu Wang PresumedLoc Loc = 7189f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 7289f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 7389f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 7489f6b26fSZixu Wang DocComment Comment; 7589f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 7689f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 7789f6b26fSZixu Wang Context.getDiagnostics()); 7889f6b26fSZixu Wang 7989f6b26fSZixu Wang // Build declaration fragments and sub-heading for the variable. 8089f6b26fSZixu Wang DeclarationFragments Declaration = 8189f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForVar(Decl); 8289f6b26fSZixu Wang DeclarationFragments SubHeading = 8389f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 8489f6b26fSZixu Wang 8589f6b26fSZixu Wang // Add the global variable record to the API set. 8689f6b26fSZixu Wang API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment, 8789f6b26fSZixu Wang Declaration, SubHeading); 8889f6b26fSZixu Wang return true; 8989f6b26fSZixu Wang } 9089f6b26fSZixu Wang 9189f6b26fSZixu Wang bool VisitFunctionDecl(const FunctionDecl *Decl) { 9289f6b26fSZixu Wang if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) { 9389f6b26fSZixu Wang // Skip member function in class templates. 9489f6b26fSZixu Wang if (Method->getParent()->getDescribedClassTemplate() != nullptr) 9589f6b26fSZixu Wang return true; 9689f6b26fSZixu Wang 9789f6b26fSZixu Wang // Skip methods in records. 9889f6b26fSZixu Wang for (auto P : Context.getParents(*Method)) { 9989f6b26fSZixu Wang if (P.get<CXXRecordDecl>()) 10089f6b26fSZixu Wang return true; 10189f6b26fSZixu Wang } 10289f6b26fSZixu Wang 10389f6b26fSZixu Wang // Skip ConstructorDecl and DestructorDecl. 10489f6b26fSZixu Wang if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) 10589f6b26fSZixu Wang return true; 10689f6b26fSZixu Wang } 10789f6b26fSZixu Wang 10889f6b26fSZixu Wang // Skip templated functions. 10989f6b26fSZixu Wang switch (Decl->getTemplatedKind()) { 11089f6b26fSZixu Wang case FunctionDecl::TK_NonTemplate: 11189f6b26fSZixu Wang break; 11289f6b26fSZixu Wang case FunctionDecl::TK_MemberSpecialization: 11389f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplateSpecialization: 11489f6b26fSZixu Wang if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) { 11589f6b26fSZixu Wang if (!TemplateInfo->isExplicitInstantiationOrSpecialization()) 11689f6b26fSZixu Wang return true; 11789f6b26fSZixu Wang } 11889f6b26fSZixu Wang break; 11989f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplate: 12089f6b26fSZixu Wang case FunctionDecl::TK_DependentFunctionTemplateSpecialization: 12189f6b26fSZixu Wang return true; 12289f6b26fSZixu Wang } 12389f6b26fSZixu Wang 12489f6b26fSZixu Wang // Collect symbol information. 12589f6b26fSZixu Wang StringRef Name = Decl->getName(); 12689f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 12789f6b26fSZixu Wang PresumedLoc Loc = 12889f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 12989f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 13089f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 13189f6b26fSZixu Wang DocComment Comment; 13289f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 13389f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 13489f6b26fSZixu Wang Context.getDiagnostics()); 13589f6b26fSZixu Wang 13689f6b26fSZixu Wang // Build declaration fragments, sub-heading, and signature of the function. 13789f6b26fSZixu Wang DeclarationFragments Declaration = 13889f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); 13989f6b26fSZixu Wang DeclarationFragments SubHeading = 14089f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 14189f6b26fSZixu Wang FunctionSignature Signature = 14289f6b26fSZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Decl); 14389f6b26fSZixu Wang 14489f6b26fSZixu Wang // Add the function record to the API set. 14589f6b26fSZixu Wang API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration, 14689f6b26fSZixu Wang SubHeading, Signature); 14789f6b26fSZixu Wang return true; 14889f6b26fSZixu Wang } 14989f6b26fSZixu Wang 15071b4c226SZixu Wang bool VisitEnumDecl(const EnumDecl *Decl) { 15171b4c226SZixu Wang if (!Decl->isComplete()) 15271b4c226SZixu Wang return true; 15371b4c226SZixu Wang 15471b4c226SZixu Wang // Skip forward declaration. 15571b4c226SZixu Wang if (!Decl->isThisDeclarationADefinition()) 15671b4c226SZixu Wang return true; 15771b4c226SZixu Wang 15871b4c226SZixu Wang // Collect symbol information. 15971b4c226SZixu Wang StringRef Name = Decl->getName(); 16071b4c226SZixu Wang StringRef USR = API.recordUSR(Decl); 16171b4c226SZixu Wang PresumedLoc Loc = 16271b4c226SZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 16371b4c226SZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 16471b4c226SZixu Wang DocComment Comment; 16571b4c226SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 16671b4c226SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 16771b4c226SZixu Wang Context.getDiagnostics()); 16871b4c226SZixu Wang 16971b4c226SZixu Wang // Build declaration fragments and sub-heading for the enum. 17071b4c226SZixu Wang DeclarationFragments Declaration = 17171b4c226SZixu Wang DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); 17271b4c226SZixu Wang DeclarationFragments SubHeading = 17371b4c226SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 17471b4c226SZixu Wang 17571b4c226SZixu Wang EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment, 17671b4c226SZixu Wang Declaration, SubHeading); 17771b4c226SZixu Wang 17871b4c226SZixu Wang // Now collect information about the enumerators in this enum. 17971b4c226SZixu Wang recordEnumConstants(EnumRecord, Decl->enumerators()); 18071b4c226SZixu Wang 18171b4c226SZixu Wang return true; 18271b4c226SZixu Wang } 18371b4c226SZixu Wang 1845bb5704cSZixu Wang bool VisitRecordDecl(const RecordDecl *Decl) { 1855bb5704cSZixu Wang if (!Decl->isCompleteDefinition()) 1865bb5704cSZixu Wang return true; 1875bb5704cSZixu Wang 1885bb5704cSZixu Wang // Skip C++ structs/classes/unions 1895bb5704cSZixu Wang // TODO: support C++ records 1905bb5704cSZixu Wang if (isa<CXXRecordDecl>(Decl)) 1915bb5704cSZixu Wang return true; 1925bb5704cSZixu Wang 1935bb5704cSZixu Wang // Collect symbol information. 1945bb5704cSZixu Wang StringRef Name = Decl->getName(); 1955bb5704cSZixu Wang StringRef USR = API.recordUSR(Decl); 1965bb5704cSZixu Wang PresumedLoc Loc = 1975bb5704cSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 1985bb5704cSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 1995bb5704cSZixu Wang DocComment Comment; 2005bb5704cSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 2015bb5704cSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 2025bb5704cSZixu Wang Context.getDiagnostics()); 2035bb5704cSZixu Wang 2045bb5704cSZixu Wang // Build declaration fragments and sub-heading for the struct. 2055bb5704cSZixu Wang DeclarationFragments Declaration = 2065bb5704cSZixu Wang DeclarationFragmentsBuilder::getFragmentsForStruct(Decl); 2075bb5704cSZixu Wang DeclarationFragments SubHeading = 2085bb5704cSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 2095bb5704cSZixu Wang 2105bb5704cSZixu Wang StructRecord *StructRecord = API.addStruct( 2115bb5704cSZixu Wang Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 2125bb5704cSZixu Wang 2135bb5704cSZixu Wang // Now collect information about the fields in this struct. 2145bb5704cSZixu Wang recordStructFields(StructRecord, Decl->fields()); 2155bb5704cSZixu Wang 2165bb5704cSZixu Wang return true; 2175bb5704cSZixu Wang } 2185bb5704cSZixu Wang 2199b36e126SZixu Wang bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) { 2209b36e126SZixu Wang // Skip forward declaration for classes (@class) 2219b36e126SZixu Wang if (!Decl->isThisDeclarationADefinition()) 2229b36e126SZixu Wang return true; 2239b36e126SZixu Wang 2249b36e126SZixu Wang // Collect symbol information. 2259b36e126SZixu Wang StringRef Name = Decl->getName(); 2269b36e126SZixu Wang StringRef USR = API.recordUSR(Decl); 2279b36e126SZixu Wang PresumedLoc Loc = 2289b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 2299b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 2309b36e126SZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 2319b36e126SZixu Wang DocComment Comment; 2329b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 2339b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 2349b36e126SZixu Wang Context.getDiagnostics()); 2359b36e126SZixu Wang 2369b36e126SZixu Wang // Build declaration fragments and sub-heading for the interface. 2379b36e126SZixu Wang DeclarationFragments Declaration = 2389b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl); 2399b36e126SZixu Wang DeclarationFragments SubHeading = 2409b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 2419b36e126SZixu Wang 2429b36e126SZixu Wang // Collect super class information. 2439b36e126SZixu Wang SymbolReference SuperClass; 2449b36e126SZixu Wang if (const auto *SuperClassDecl = Decl->getSuperClass()) { 2459b36e126SZixu Wang SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); 2469b36e126SZixu Wang SuperClass.USR = API.recordUSR(SuperClassDecl); 2479b36e126SZixu Wang } 2489b36e126SZixu Wang 2499b36e126SZixu Wang ObjCInterfaceRecord *ObjCInterfaceRecord = 2509b36e126SZixu Wang API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment, 2519b36e126SZixu Wang Declaration, SubHeading, SuperClass); 2529b36e126SZixu Wang 2539b36e126SZixu Wang // Record all methods (selectors). This doesn't include automatically 2549b36e126SZixu Wang // synthesized property methods. 2559b36e126SZixu Wang recordObjCMethods(ObjCInterfaceRecord, Decl->methods()); 2569b36e126SZixu Wang recordObjCProperties(ObjCInterfaceRecord, Decl->properties()); 2579b36e126SZixu Wang recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars()); 2589b36e126SZixu Wang recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols()); 2599b36e126SZixu Wang 2609b36e126SZixu Wang return true; 2619b36e126SZixu Wang } 2629b36e126SZixu Wang 263*d1d34bafSZixu Wang bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) { 264*d1d34bafSZixu Wang // Skip forward declaration for protocols (@protocol). 265*d1d34bafSZixu Wang if (!Decl->isThisDeclarationADefinition()) 266*d1d34bafSZixu Wang return true; 267*d1d34bafSZixu Wang 268*d1d34bafSZixu Wang // Collect symbol information. 269*d1d34bafSZixu Wang StringRef Name = Decl->getName(); 270*d1d34bafSZixu Wang StringRef USR = API.recordUSR(Decl); 271*d1d34bafSZixu Wang PresumedLoc Loc = 272*d1d34bafSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 273*d1d34bafSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 274*d1d34bafSZixu Wang DocComment Comment; 275*d1d34bafSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 276*d1d34bafSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 277*d1d34bafSZixu Wang Context.getDiagnostics()); 278*d1d34bafSZixu Wang 279*d1d34bafSZixu Wang // Build declaration fragments and sub-heading for the protocol. 280*d1d34bafSZixu Wang DeclarationFragments Declaration = 281*d1d34bafSZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl); 282*d1d34bafSZixu Wang DeclarationFragments SubHeading = 283*d1d34bafSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 284*d1d34bafSZixu Wang 285*d1d34bafSZixu Wang ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol( 286*d1d34bafSZixu Wang Name, USR, Loc, Availability, Comment, Declaration, SubHeading); 287*d1d34bafSZixu Wang 288*d1d34bafSZixu Wang recordObjCMethods(ObjCProtocolRecord, Decl->methods()); 289*d1d34bafSZixu Wang recordObjCProperties(ObjCProtocolRecord, Decl->properties()); 290*d1d34bafSZixu Wang recordObjCProtocols(ObjCProtocolRecord, Decl->protocols()); 291*d1d34bafSZixu Wang 292*d1d34bafSZixu Wang return true; 293*d1d34bafSZixu Wang } 294*d1d34bafSZixu Wang 29589f6b26fSZixu Wang private: 29689f6b26fSZixu Wang /// Get availability information of the declaration \p D. 29789f6b26fSZixu Wang AvailabilityInfo getAvailability(const Decl *D) const { 29889f6b26fSZixu Wang StringRef PlatformName = Context.getTargetInfo().getPlatformName(); 29989f6b26fSZixu Wang 30089f6b26fSZixu Wang AvailabilityInfo Availability; 30189f6b26fSZixu Wang // Collect availability attributes from all redeclarations. 30289f6b26fSZixu Wang for (const auto *RD : D->redecls()) { 30389f6b26fSZixu Wang for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) { 30489f6b26fSZixu Wang if (A->getPlatform()->getName() != PlatformName) 30589f6b26fSZixu Wang continue; 30689f6b26fSZixu Wang Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(), 30789f6b26fSZixu Wang A->getObsoleted(), A->getUnavailable(), 30889f6b26fSZixu Wang /* UnconditionallyDeprecated */ false, 30989f6b26fSZixu Wang /* UnconditionallyUnavailable */ false); 31089f6b26fSZixu Wang break; 31189f6b26fSZixu Wang } 31289f6b26fSZixu Wang 31389f6b26fSZixu Wang if (const auto *A = RD->getAttr<UnavailableAttr>()) 31489f6b26fSZixu Wang if (!A->isImplicit()) { 31589f6b26fSZixu Wang Availability.Unavailable = true; 31689f6b26fSZixu Wang Availability.UnconditionallyUnavailable = true; 31789f6b26fSZixu Wang } 31889f6b26fSZixu Wang 31989f6b26fSZixu Wang if (const auto *A = RD->getAttr<DeprecatedAttr>()) 32089f6b26fSZixu Wang if (!A->isImplicit()) 32189f6b26fSZixu Wang Availability.UnconditionallyDeprecated = true; 32289f6b26fSZixu Wang } 32389f6b26fSZixu Wang 32489f6b26fSZixu Wang return Availability; 32589f6b26fSZixu Wang } 32689f6b26fSZixu Wang 32771b4c226SZixu Wang /// Collect API information for the enum constants and associate with the 32871b4c226SZixu Wang /// parent enum. 32971b4c226SZixu Wang void recordEnumConstants(EnumRecord *EnumRecord, 33071b4c226SZixu Wang const EnumDecl::enumerator_range Constants) { 33171b4c226SZixu Wang for (const auto *Constant : Constants) { 33271b4c226SZixu Wang // Collect symbol information. 33371b4c226SZixu Wang StringRef Name = Constant->getName(); 33471b4c226SZixu Wang StringRef USR = API.recordUSR(Constant); 33571b4c226SZixu Wang PresumedLoc Loc = 33671b4c226SZixu Wang Context.getSourceManager().getPresumedLoc(Constant->getLocation()); 33771b4c226SZixu Wang AvailabilityInfo Availability = getAvailability(Constant); 33871b4c226SZixu Wang DocComment Comment; 33971b4c226SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant)) 34071b4c226SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 34171b4c226SZixu Wang Context.getDiagnostics()); 34271b4c226SZixu Wang 34371b4c226SZixu Wang // Build declaration fragments and sub-heading for the enum constant. 34471b4c226SZixu Wang DeclarationFragments Declaration = 34571b4c226SZixu Wang DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant); 34671b4c226SZixu Wang DeclarationFragments SubHeading = 34771b4c226SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Constant); 34871b4c226SZixu Wang 34971b4c226SZixu Wang API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment, 35071b4c226SZixu Wang Declaration, SubHeading); 35171b4c226SZixu Wang } 35271b4c226SZixu Wang } 35371b4c226SZixu Wang 3545bb5704cSZixu Wang /// Collect API information for the struct fields and associate with the 3555bb5704cSZixu Wang /// parent struct. 3565bb5704cSZixu Wang void recordStructFields(StructRecord *StructRecord, 3575bb5704cSZixu Wang const RecordDecl::field_range Fields) { 3585bb5704cSZixu Wang for (const auto *Field : Fields) { 3595bb5704cSZixu Wang // Collect symbol information. 3605bb5704cSZixu Wang StringRef Name = Field->getName(); 3615bb5704cSZixu Wang StringRef USR = API.recordUSR(Field); 3625bb5704cSZixu Wang PresumedLoc Loc = 3635bb5704cSZixu Wang Context.getSourceManager().getPresumedLoc(Field->getLocation()); 3645bb5704cSZixu Wang AvailabilityInfo Availability = getAvailability(Field); 3655bb5704cSZixu Wang DocComment Comment; 3665bb5704cSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field)) 3675bb5704cSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 3685bb5704cSZixu Wang Context.getDiagnostics()); 3695bb5704cSZixu Wang 3705bb5704cSZixu Wang // Build declaration fragments and sub-heading for the struct field. 3715bb5704cSZixu Wang DeclarationFragments Declaration = 3725bb5704cSZixu Wang DeclarationFragmentsBuilder::getFragmentsForField(Field); 3735bb5704cSZixu Wang DeclarationFragments SubHeading = 3745bb5704cSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Field); 3755bb5704cSZixu Wang 3765bb5704cSZixu Wang API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment, 3775bb5704cSZixu Wang Declaration, SubHeading); 3785bb5704cSZixu Wang } 3795bb5704cSZixu Wang } 3805bb5704cSZixu Wang 3819b36e126SZixu Wang /// Collect API information for the Objective-C methods and associate with the 3829b36e126SZixu Wang /// parent container. 3839b36e126SZixu Wang void recordObjCMethods(ObjCContainerRecord *Container, 3849b36e126SZixu Wang const ObjCContainerDecl::method_range Methods) { 3859b36e126SZixu Wang for (const auto *Method : Methods) { 3869b36e126SZixu Wang // Don't record selectors for properties. 3879b36e126SZixu Wang if (Method->isPropertyAccessor()) 3889b36e126SZixu Wang continue; 3899b36e126SZixu Wang 3909b36e126SZixu Wang StringRef Name = API.copyString(Method->getSelector().getAsString()); 3919b36e126SZixu Wang StringRef USR = API.recordUSR(Method); 3929b36e126SZixu Wang PresumedLoc Loc = 3939b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Method->getLocation()); 3949b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Method); 3959b36e126SZixu Wang DocComment Comment; 3969b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method)) 3979b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 3989b36e126SZixu Wang Context.getDiagnostics()); 3999b36e126SZixu Wang 4009b36e126SZixu Wang // Build declaration fragments, sub-heading, and signature for the method. 4019b36e126SZixu Wang DeclarationFragments Declaration = 4029b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method); 4039b36e126SZixu Wang DeclarationFragments SubHeading = 4049b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Method); 4059b36e126SZixu Wang FunctionSignature Signature = 4069b36e126SZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Method); 4079b36e126SZixu Wang 4089b36e126SZixu Wang API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment, 4099b36e126SZixu Wang Declaration, SubHeading, Signature, 4109b36e126SZixu Wang Method->isInstanceMethod()); 4119b36e126SZixu Wang } 4129b36e126SZixu Wang } 4139b36e126SZixu Wang 4149b36e126SZixu Wang void recordObjCProperties(ObjCContainerRecord *Container, 4159b36e126SZixu Wang const ObjCContainerDecl::prop_range Properties) { 4169b36e126SZixu Wang for (const auto *Property : Properties) { 4179b36e126SZixu Wang StringRef Name = Property->getName(); 4189b36e126SZixu Wang StringRef USR = API.recordUSR(Property); 4199b36e126SZixu Wang PresumedLoc Loc = 4209b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Property->getLocation()); 4219b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Property); 4229b36e126SZixu Wang DocComment Comment; 4239b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property)) 4249b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 4259b36e126SZixu Wang Context.getDiagnostics()); 4269b36e126SZixu Wang 4279b36e126SZixu Wang // Build declaration fragments and sub-heading for the property. 4289b36e126SZixu Wang DeclarationFragments Declaration = 4299b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property); 4309b36e126SZixu Wang DeclarationFragments SubHeading = 4319b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Property); 4329b36e126SZixu Wang 4339b36e126SZixu Wang StringRef GetterName = 4349b36e126SZixu Wang API.copyString(Property->getGetterName().getAsString()); 4359b36e126SZixu Wang StringRef SetterName = 4369b36e126SZixu Wang API.copyString(Property->getSetterName().getAsString()); 4379b36e126SZixu Wang 4389b36e126SZixu Wang // Get the attributes for property. 4399b36e126SZixu Wang unsigned Attributes = ObjCPropertyRecord::NoAttr; 4409b36e126SZixu Wang if (Property->getPropertyAttributes() & 4419b36e126SZixu Wang ObjCPropertyAttribute::kind_readonly) 4429b36e126SZixu Wang Attributes |= ObjCPropertyRecord::ReadOnly; 4439b36e126SZixu Wang if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class) 4449b36e126SZixu Wang Attributes |= ObjCPropertyRecord::Class; 4459b36e126SZixu Wang 4469b36e126SZixu Wang API.addObjCProperty( 4479b36e126SZixu Wang Container, Name, USR, Loc, Availability, Comment, Declaration, 4489b36e126SZixu Wang SubHeading, 4499b36e126SZixu Wang static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), 4509b36e126SZixu Wang GetterName, SetterName, Property->isOptional()); 4519b36e126SZixu Wang } 4529b36e126SZixu Wang } 4539b36e126SZixu Wang 4549b36e126SZixu Wang void recordObjCInstanceVariables( 4559b36e126SZixu Wang ObjCContainerRecord *Container, 4569b36e126SZixu Wang const llvm::iterator_range< 4579b36e126SZixu Wang DeclContext::specific_decl_iterator<ObjCIvarDecl>> 4589b36e126SZixu Wang Ivars) { 4599b36e126SZixu Wang for (const auto *Ivar : Ivars) { 4609b36e126SZixu Wang StringRef Name = Ivar->getName(); 4619b36e126SZixu Wang StringRef USR = API.recordUSR(Ivar); 4629b36e126SZixu Wang PresumedLoc Loc = 4639b36e126SZixu Wang Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); 4649b36e126SZixu Wang AvailabilityInfo Availability = getAvailability(Ivar); 4659b36e126SZixu Wang DocComment Comment; 4669b36e126SZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar)) 4679b36e126SZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 4689b36e126SZixu Wang Context.getDiagnostics()); 4699b36e126SZixu Wang 4709b36e126SZixu Wang // Build declaration fragments and sub-heading for the instance variable. 4719b36e126SZixu Wang DeclarationFragments Declaration = 4729b36e126SZixu Wang DeclarationFragmentsBuilder::getFragmentsForField(Ivar); 4739b36e126SZixu Wang DeclarationFragments SubHeading = 4749b36e126SZixu Wang DeclarationFragmentsBuilder::getSubHeading(Ivar); 4759b36e126SZixu Wang 4769b36e126SZixu Wang ObjCInstanceVariableRecord::AccessControl Access = 4779b36e126SZixu Wang Ivar->getCanonicalAccessControl(); 4789b36e126SZixu Wang 4799b36e126SZixu Wang API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability, 4809b36e126SZixu Wang Comment, Declaration, SubHeading, Access); 4819b36e126SZixu Wang } 4829b36e126SZixu Wang } 4839b36e126SZixu Wang 4849b36e126SZixu Wang void recordObjCProtocols(ObjCContainerRecord *Container, 4859b36e126SZixu Wang ObjCInterfaceDecl::protocol_range Protocols) { 4869b36e126SZixu Wang for (const auto *Protocol : Protocols) 4879b36e126SZixu Wang Container->Protocols.emplace_back(Protocol->getName(), 4889b36e126SZixu Wang API.recordUSR(Protocol)); 4899b36e126SZixu Wang } 4909b36e126SZixu Wang 49189f6b26fSZixu Wang ASTContext &Context; 49289f6b26fSZixu Wang APISet API; 49389f6b26fSZixu Wang }; 49489f6b26fSZixu Wang 49589f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer { 49689f6b26fSZixu Wang public: 49715bf0e56SZixu Wang ExtractAPIConsumer(ASTContext &Context, StringRef ProductName, Language Lang, 4985ef2ec7eSDaniel Grumberg std::unique_ptr<raw_pwrite_stream> OS) 49915bf0e56SZixu Wang : Visitor(Context, Lang), ProductName(ProductName), OS(std::move(OS)) {} 50089f6b26fSZixu Wang 50189f6b26fSZixu Wang void HandleTranslationUnit(ASTContext &Context) override { 50289f6b26fSZixu Wang // Use ExtractAPIVisitor to traverse symbol declarations in the context. 50389f6b26fSZixu Wang Visitor.TraverseDecl(Context.getTranslationUnitDecl()); 50489f6b26fSZixu Wang 50589f6b26fSZixu Wang // Setup a SymbolGraphSerializer to write out collected API information in 50689f6b26fSZixu Wang // the Symbol Graph format. 50789f6b26fSZixu Wang // FIXME: Make the kind of APISerializer configurable. 5085ef2ec7eSDaniel Grumberg SymbolGraphSerializer SGSerializer(Visitor.getAPI(), ProductName); 50989f6b26fSZixu Wang SGSerializer.serialize(*OS); 51089f6b26fSZixu Wang } 51189f6b26fSZixu Wang 51289f6b26fSZixu Wang private: 51389f6b26fSZixu Wang ExtractAPIVisitor Visitor; 5145ef2ec7eSDaniel Grumberg std::string ProductName; 51589f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS; 51689f6b26fSZixu Wang }; 51789f6b26fSZixu Wang 51889f6b26fSZixu Wang } // namespace 51989f6b26fSZixu Wang 52089f6b26fSZixu Wang std::unique_ptr<ASTConsumer> 52189f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { 52289f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile); 52389f6b26fSZixu Wang if (!OS) 52489f6b26fSZixu Wang return nullptr; 5255ef2ec7eSDaniel Grumberg return std::make_unique<ExtractAPIConsumer>( 5265ef2ec7eSDaniel Grumberg CI.getASTContext(), CI.getInvocation().getFrontendOpts().ProductName, 52715bf0e56SZixu Wang CI.getFrontendOpts().Inputs.back().getKind().getLanguage(), 52889f6b26fSZixu Wang std::move(OS)); 52989f6b26fSZixu Wang } 53089f6b26fSZixu Wang 531f833aab0SDaniel Grumberg bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { 532f833aab0SDaniel Grumberg auto &Inputs = CI.getFrontendOpts().Inputs; 533f833aab0SDaniel Grumberg if (Inputs.empty()) 534f833aab0SDaniel Grumberg return true; 535f833aab0SDaniel Grumberg 536f833aab0SDaniel Grumberg auto Kind = Inputs[0].getKind(); 537f833aab0SDaniel Grumberg 538f833aab0SDaniel Grumberg // Convert the header file inputs into a single input buffer. 539f833aab0SDaniel Grumberg SmallString<256> HeaderContents; 540f833aab0SDaniel Grumberg for (const FrontendInputFile &FIF : Inputs) { 541f833aab0SDaniel Grumberg if (Kind.isObjectiveC()) 542f833aab0SDaniel Grumberg HeaderContents += "#import"; 543f833aab0SDaniel Grumberg else 544f833aab0SDaniel Grumberg HeaderContents += "#include"; 545f833aab0SDaniel Grumberg HeaderContents += " \""; 546f833aab0SDaniel Grumberg HeaderContents += FIF.getFile(); 547f833aab0SDaniel Grumberg HeaderContents += "\"\n"; 548f833aab0SDaniel Grumberg } 549f833aab0SDaniel Grumberg 550f833aab0SDaniel Grumberg Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents, 551f833aab0SDaniel Grumberg getInputBufferName()); 552f833aab0SDaniel Grumberg 553f833aab0SDaniel Grumberg // Set that buffer up as our "real" input in the CompilerInstance. 554f833aab0SDaniel Grumberg Inputs.clear(); 555f833aab0SDaniel Grumberg Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false); 556f833aab0SDaniel Grumberg 557f833aab0SDaniel Grumberg return true; 558f833aab0SDaniel Grumberg } 559f833aab0SDaniel Grumberg 56089f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> 56189f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { 56289f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS = 56389f6b26fSZixu Wang CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json", 56489f6b26fSZixu Wang /*RemoveFileOnSignal=*/false); 56589f6b26fSZixu Wang if (!OS) 56689f6b26fSZixu Wang return nullptr; 56789f6b26fSZixu Wang return OS; 56889f6b26fSZixu Wang } 569