1*89f6b26fSZixu Wang //===- ExtractAPI/ExtractAPIConsumer.cpp ------------------------*- C++ -*-===// 2*89f6b26fSZixu Wang // 3*89f6b26fSZixu Wang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*89f6b26fSZixu Wang // See https://llvm.org/LICENSE.txt for license information. 5*89f6b26fSZixu Wang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*89f6b26fSZixu Wang // 7*89f6b26fSZixu Wang //===----------------------------------------------------------------------===// 8*89f6b26fSZixu Wang /// 9*89f6b26fSZixu Wang /// \file 10*89f6b26fSZixu Wang /// This file implements the ExtractAPIAction, and ASTVisitor/Consumer to 11*89f6b26fSZixu Wang /// collect API information. 12*89f6b26fSZixu Wang /// 13*89f6b26fSZixu Wang //===----------------------------------------------------------------------===// 14*89f6b26fSZixu Wang 15*89f6b26fSZixu Wang #include "clang/AST/ASTConsumer.h" 16*89f6b26fSZixu Wang #include "clang/AST/ASTContext.h" 17*89f6b26fSZixu Wang #include "clang/AST/Decl.h" 18*89f6b26fSZixu Wang #include "clang/AST/DeclCXX.h" 19*89f6b26fSZixu Wang #include "clang/AST/ParentMapContext.h" 20*89f6b26fSZixu Wang #include "clang/AST/RawCommentList.h" 21*89f6b26fSZixu Wang #include "clang/AST/RecursiveASTVisitor.h" 22*89f6b26fSZixu Wang #include "clang/Basic/TargetInfo.h" 23*89f6b26fSZixu Wang #include "clang/ExtractAPI/API.h" 24*89f6b26fSZixu Wang #include "clang/ExtractAPI/AvailabilityInfo.h" 25*89f6b26fSZixu Wang #include "clang/ExtractAPI/DeclarationFragments.h" 26*89f6b26fSZixu Wang #include "clang/ExtractAPI/FrontendActions.h" 27*89f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" 28*89f6b26fSZixu Wang #include "clang/Frontend/ASTConsumers.h" 29*89f6b26fSZixu Wang #include "clang/Frontend/CompilerInstance.h" 30*89f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h" 31*89f6b26fSZixu Wang 32*89f6b26fSZixu Wang using namespace clang; 33*89f6b26fSZixu Wang using namespace extractapi; 34*89f6b26fSZixu Wang 35*89f6b26fSZixu Wang namespace { 36*89f6b26fSZixu Wang 37*89f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API 38*89f6b26fSZixu Wang /// information. 39*89f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> { 40*89f6b26fSZixu Wang public: 41*89f6b26fSZixu Wang explicit ExtractAPIVisitor(ASTContext &Context) 42*89f6b26fSZixu Wang : Context(Context), 43*89f6b26fSZixu Wang API(Context.getTargetInfo().getTriple(), Context.getLangOpts()) {} 44*89f6b26fSZixu Wang 45*89f6b26fSZixu Wang const APISet &getAPI() const { return API; } 46*89f6b26fSZixu Wang 47*89f6b26fSZixu Wang bool VisitVarDecl(const VarDecl *Decl) { 48*89f6b26fSZixu Wang // Skip function parameters. 49*89f6b26fSZixu Wang if (isa<ParmVarDecl>(Decl)) 50*89f6b26fSZixu Wang return true; 51*89f6b26fSZixu Wang 52*89f6b26fSZixu Wang // Skip non-global variables in records (struct/union/class). 53*89f6b26fSZixu Wang if (Decl->getDeclContext()->isRecord()) 54*89f6b26fSZixu Wang return true; 55*89f6b26fSZixu Wang 56*89f6b26fSZixu Wang // Skip local variables inside function or method. 57*89f6b26fSZixu Wang if (!Decl->isDefinedOutsideFunctionOrMethod()) 58*89f6b26fSZixu Wang return true; 59*89f6b26fSZixu Wang 60*89f6b26fSZixu Wang // If this is a template but not specialization or instantiation, skip. 61*89f6b26fSZixu Wang if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && 62*89f6b26fSZixu Wang Decl->getTemplateSpecializationKind() == TSK_Undeclared) 63*89f6b26fSZixu Wang return true; 64*89f6b26fSZixu Wang 65*89f6b26fSZixu Wang // Collect symbol information. 66*89f6b26fSZixu Wang StringRef Name = Decl->getName(); 67*89f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 68*89f6b26fSZixu Wang PresumedLoc Loc = 69*89f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 70*89f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 71*89f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 72*89f6b26fSZixu Wang DocComment Comment; 73*89f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 74*89f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 75*89f6b26fSZixu Wang Context.getDiagnostics()); 76*89f6b26fSZixu Wang 77*89f6b26fSZixu Wang // Build declaration fragments and sub-heading for the variable. 78*89f6b26fSZixu Wang DeclarationFragments Declaration = 79*89f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForVar(Decl); 80*89f6b26fSZixu Wang DeclarationFragments SubHeading = 81*89f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 82*89f6b26fSZixu Wang 83*89f6b26fSZixu Wang // Add the global variable record to the API set. 84*89f6b26fSZixu Wang API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment, 85*89f6b26fSZixu Wang Declaration, SubHeading); 86*89f6b26fSZixu Wang return true; 87*89f6b26fSZixu Wang } 88*89f6b26fSZixu Wang 89*89f6b26fSZixu Wang bool VisitFunctionDecl(const FunctionDecl *Decl) { 90*89f6b26fSZixu Wang if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) { 91*89f6b26fSZixu Wang // Skip member function in class templates. 92*89f6b26fSZixu Wang if (Method->getParent()->getDescribedClassTemplate() != nullptr) 93*89f6b26fSZixu Wang return true; 94*89f6b26fSZixu Wang 95*89f6b26fSZixu Wang // Skip methods in records. 96*89f6b26fSZixu Wang for (auto P : Context.getParents(*Method)) { 97*89f6b26fSZixu Wang if (P.get<CXXRecordDecl>()) 98*89f6b26fSZixu Wang return true; 99*89f6b26fSZixu Wang } 100*89f6b26fSZixu Wang 101*89f6b26fSZixu Wang // Skip ConstructorDecl and DestructorDecl. 102*89f6b26fSZixu Wang if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) 103*89f6b26fSZixu Wang return true; 104*89f6b26fSZixu Wang } 105*89f6b26fSZixu Wang 106*89f6b26fSZixu Wang // Skip templated functions. 107*89f6b26fSZixu Wang switch (Decl->getTemplatedKind()) { 108*89f6b26fSZixu Wang case FunctionDecl::TK_NonTemplate: 109*89f6b26fSZixu Wang break; 110*89f6b26fSZixu Wang case FunctionDecl::TK_MemberSpecialization: 111*89f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplateSpecialization: 112*89f6b26fSZixu Wang if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) { 113*89f6b26fSZixu Wang if (!TemplateInfo->isExplicitInstantiationOrSpecialization()) 114*89f6b26fSZixu Wang return true; 115*89f6b26fSZixu Wang } 116*89f6b26fSZixu Wang break; 117*89f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplate: 118*89f6b26fSZixu Wang case FunctionDecl::TK_DependentFunctionTemplateSpecialization: 119*89f6b26fSZixu Wang return true; 120*89f6b26fSZixu Wang } 121*89f6b26fSZixu Wang 122*89f6b26fSZixu Wang // Collect symbol information. 123*89f6b26fSZixu Wang StringRef Name = Decl->getName(); 124*89f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 125*89f6b26fSZixu Wang PresumedLoc Loc = 126*89f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 127*89f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 128*89f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 129*89f6b26fSZixu Wang DocComment Comment; 130*89f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 131*89f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 132*89f6b26fSZixu Wang Context.getDiagnostics()); 133*89f6b26fSZixu Wang 134*89f6b26fSZixu Wang // Build declaration fragments, sub-heading, and signature of the function. 135*89f6b26fSZixu Wang DeclarationFragments Declaration = 136*89f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); 137*89f6b26fSZixu Wang DeclarationFragments SubHeading = 138*89f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 139*89f6b26fSZixu Wang FunctionSignature Signature = 140*89f6b26fSZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Decl); 141*89f6b26fSZixu Wang 142*89f6b26fSZixu Wang // Add the function record to the API set. 143*89f6b26fSZixu Wang API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration, 144*89f6b26fSZixu Wang SubHeading, Signature); 145*89f6b26fSZixu Wang return true; 146*89f6b26fSZixu Wang } 147*89f6b26fSZixu Wang 148*89f6b26fSZixu Wang private: 149*89f6b26fSZixu Wang /// Get availability information of the declaration \p D. 150*89f6b26fSZixu Wang AvailabilityInfo getAvailability(const Decl *D) const { 151*89f6b26fSZixu Wang StringRef PlatformName = Context.getTargetInfo().getPlatformName(); 152*89f6b26fSZixu Wang 153*89f6b26fSZixu Wang AvailabilityInfo Availability; 154*89f6b26fSZixu Wang // Collect availability attributes from all redeclarations. 155*89f6b26fSZixu Wang for (const auto *RD : D->redecls()) { 156*89f6b26fSZixu Wang for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) { 157*89f6b26fSZixu Wang if (A->getPlatform()->getName() != PlatformName) 158*89f6b26fSZixu Wang continue; 159*89f6b26fSZixu Wang Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(), 160*89f6b26fSZixu Wang A->getObsoleted(), A->getUnavailable(), 161*89f6b26fSZixu Wang /* UnconditionallyDeprecated */ false, 162*89f6b26fSZixu Wang /* UnconditionallyUnavailable */ false); 163*89f6b26fSZixu Wang break; 164*89f6b26fSZixu Wang } 165*89f6b26fSZixu Wang 166*89f6b26fSZixu Wang if (const auto *A = RD->getAttr<UnavailableAttr>()) 167*89f6b26fSZixu Wang if (!A->isImplicit()) { 168*89f6b26fSZixu Wang Availability.Unavailable = true; 169*89f6b26fSZixu Wang Availability.UnconditionallyUnavailable = true; 170*89f6b26fSZixu Wang } 171*89f6b26fSZixu Wang 172*89f6b26fSZixu Wang if (const auto *A = RD->getAttr<DeprecatedAttr>()) 173*89f6b26fSZixu Wang if (!A->isImplicit()) 174*89f6b26fSZixu Wang Availability.UnconditionallyDeprecated = true; 175*89f6b26fSZixu Wang } 176*89f6b26fSZixu Wang 177*89f6b26fSZixu Wang return Availability; 178*89f6b26fSZixu Wang } 179*89f6b26fSZixu Wang 180*89f6b26fSZixu Wang ASTContext &Context; 181*89f6b26fSZixu Wang APISet API; 182*89f6b26fSZixu Wang }; 183*89f6b26fSZixu Wang 184*89f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer { 185*89f6b26fSZixu Wang public: 186*89f6b26fSZixu Wang ExtractAPIConsumer(ASTContext &Context, std::unique_ptr<raw_pwrite_stream> OS) 187*89f6b26fSZixu Wang : Visitor(Context), OS(std::move(OS)) {} 188*89f6b26fSZixu Wang 189*89f6b26fSZixu Wang void HandleTranslationUnit(ASTContext &Context) override { 190*89f6b26fSZixu Wang // Use ExtractAPIVisitor to traverse symbol declarations in the context. 191*89f6b26fSZixu Wang Visitor.TraverseDecl(Context.getTranslationUnitDecl()); 192*89f6b26fSZixu Wang 193*89f6b26fSZixu Wang // Setup a SymbolGraphSerializer to write out collected API information in 194*89f6b26fSZixu Wang // the Symbol Graph format. 195*89f6b26fSZixu Wang // FIXME: Make the kind of APISerializer configurable. 196*89f6b26fSZixu Wang SymbolGraphSerializer SGSerializer(Visitor.getAPI()); 197*89f6b26fSZixu Wang SGSerializer.serialize(*OS); 198*89f6b26fSZixu Wang } 199*89f6b26fSZixu Wang 200*89f6b26fSZixu Wang private: 201*89f6b26fSZixu Wang ExtractAPIVisitor Visitor; 202*89f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS; 203*89f6b26fSZixu Wang }; 204*89f6b26fSZixu Wang 205*89f6b26fSZixu Wang } // namespace 206*89f6b26fSZixu Wang 207*89f6b26fSZixu Wang std::unique_ptr<ASTConsumer> 208*89f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { 209*89f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile); 210*89f6b26fSZixu Wang if (!OS) 211*89f6b26fSZixu Wang return nullptr; 212*89f6b26fSZixu Wang return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(), 213*89f6b26fSZixu Wang std::move(OS)); 214*89f6b26fSZixu Wang } 215*89f6b26fSZixu Wang 216*89f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> 217*89f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { 218*89f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS = 219*89f6b26fSZixu Wang CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json", 220*89f6b26fSZixu Wang /*RemoveFileOnSignal=*/false); 221*89f6b26fSZixu Wang if (!OS) 222*89f6b26fSZixu Wang return nullptr; 223*89f6b26fSZixu Wang return OS; 224*89f6b26fSZixu Wang } 225