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" 3089f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h" 3189f6b26fSZixu Wang 3289f6b26fSZixu Wang using namespace clang; 3389f6b26fSZixu Wang using namespace extractapi; 3489f6b26fSZixu Wang 3589f6b26fSZixu Wang namespace { 3689f6b26fSZixu Wang 3789f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API 3889f6b26fSZixu Wang /// information. 3989f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> { 4089f6b26fSZixu Wang public: 4189f6b26fSZixu Wang explicit ExtractAPIVisitor(ASTContext &Context) 4289f6b26fSZixu Wang : Context(Context), 4389f6b26fSZixu Wang API(Context.getTargetInfo().getTriple(), Context.getLangOpts()) {} 4489f6b26fSZixu Wang 4589f6b26fSZixu Wang const APISet &getAPI() const { return API; } 4689f6b26fSZixu Wang 4789f6b26fSZixu Wang bool VisitVarDecl(const VarDecl *Decl) { 4889f6b26fSZixu Wang // Skip function parameters. 4989f6b26fSZixu Wang if (isa<ParmVarDecl>(Decl)) 5089f6b26fSZixu Wang return true; 5189f6b26fSZixu Wang 5289f6b26fSZixu Wang // Skip non-global variables in records (struct/union/class). 5389f6b26fSZixu Wang if (Decl->getDeclContext()->isRecord()) 5489f6b26fSZixu Wang return true; 5589f6b26fSZixu Wang 5689f6b26fSZixu Wang // Skip local variables inside function or method. 5789f6b26fSZixu Wang if (!Decl->isDefinedOutsideFunctionOrMethod()) 5889f6b26fSZixu Wang return true; 5989f6b26fSZixu Wang 6089f6b26fSZixu Wang // If this is a template but not specialization or instantiation, skip. 6189f6b26fSZixu Wang if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) && 6289f6b26fSZixu Wang Decl->getTemplateSpecializationKind() == TSK_Undeclared) 6389f6b26fSZixu Wang return true; 6489f6b26fSZixu Wang 6589f6b26fSZixu Wang // Collect symbol information. 6689f6b26fSZixu Wang StringRef Name = Decl->getName(); 6789f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 6889f6b26fSZixu Wang PresumedLoc Loc = 6989f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 7089f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 7189f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 7289f6b26fSZixu Wang DocComment Comment; 7389f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 7489f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 7589f6b26fSZixu Wang Context.getDiagnostics()); 7689f6b26fSZixu Wang 7789f6b26fSZixu Wang // Build declaration fragments and sub-heading for the variable. 7889f6b26fSZixu Wang DeclarationFragments Declaration = 7989f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForVar(Decl); 8089f6b26fSZixu Wang DeclarationFragments SubHeading = 8189f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 8289f6b26fSZixu Wang 8389f6b26fSZixu Wang // Add the global variable record to the API set. 8489f6b26fSZixu Wang API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment, 8589f6b26fSZixu Wang Declaration, SubHeading); 8689f6b26fSZixu Wang return true; 8789f6b26fSZixu Wang } 8889f6b26fSZixu Wang 8989f6b26fSZixu Wang bool VisitFunctionDecl(const FunctionDecl *Decl) { 9089f6b26fSZixu Wang if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) { 9189f6b26fSZixu Wang // Skip member function in class templates. 9289f6b26fSZixu Wang if (Method->getParent()->getDescribedClassTemplate() != nullptr) 9389f6b26fSZixu Wang return true; 9489f6b26fSZixu Wang 9589f6b26fSZixu Wang // Skip methods in records. 9689f6b26fSZixu Wang for (auto P : Context.getParents(*Method)) { 9789f6b26fSZixu Wang if (P.get<CXXRecordDecl>()) 9889f6b26fSZixu Wang return true; 9989f6b26fSZixu Wang } 10089f6b26fSZixu Wang 10189f6b26fSZixu Wang // Skip ConstructorDecl and DestructorDecl. 10289f6b26fSZixu Wang if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) 10389f6b26fSZixu Wang return true; 10489f6b26fSZixu Wang } 10589f6b26fSZixu Wang 10689f6b26fSZixu Wang // Skip templated functions. 10789f6b26fSZixu Wang switch (Decl->getTemplatedKind()) { 10889f6b26fSZixu Wang case FunctionDecl::TK_NonTemplate: 10989f6b26fSZixu Wang break; 11089f6b26fSZixu Wang case FunctionDecl::TK_MemberSpecialization: 11189f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplateSpecialization: 11289f6b26fSZixu Wang if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) { 11389f6b26fSZixu Wang if (!TemplateInfo->isExplicitInstantiationOrSpecialization()) 11489f6b26fSZixu Wang return true; 11589f6b26fSZixu Wang } 11689f6b26fSZixu Wang break; 11789f6b26fSZixu Wang case FunctionDecl::TK_FunctionTemplate: 11889f6b26fSZixu Wang case FunctionDecl::TK_DependentFunctionTemplateSpecialization: 11989f6b26fSZixu Wang return true; 12089f6b26fSZixu Wang } 12189f6b26fSZixu Wang 12289f6b26fSZixu Wang // Collect symbol information. 12389f6b26fSZixu Wang StringRef Name = Decl->getName(); 12489f6b26fSZixu Wang StringRef USR = API.recordUSR(Decl); 12589f6b26fSZixu Wang PresumedLoc Loc = 12689f6b26fSZixu Wang Context.getSourceManager().getPresumedLoc(Decl->getLocation()); 12789f6b26fSZixu Wang AvailabilityInfo Availability = getAvailability(Decl); 12889f6b26fSZixu Wang LinkageInfo Linkage = Decl->getLinkageAndVisibility(); 12989f6b26fSZixu Wang DocComment Comment; 13089f6b26fSZixu Wang if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl)) 13189f6b26fSZixu Wang Comment = RawComment->getFormattedLines(Context.getSourceManager(), 13289f6b26fSZixu Wang Context.getDiagnostics()); 13389f6b26fSZixu Wang 13489f6b26fSZixu Wang // Build declaration fragments, sub-heading, and signature of the function. 13589f6b26fSZixu Wang DeclarationFragments Declaration = 13689f6b26fSZixu Wang DeclarationFragmentsBuilder::getFragmentsForFunction(Decl); 13789f6b26fSZixu Wang DeclarationFragments SubHeading = 13889f6b26fSZixu Wang DeclarationFragmentsBuilder::getSubHeading(Decl); 13989f6b26fSZixu Wang FunctionSignature Signature = 14089f6b26fSZixu Wang DeclarationFragmentsBuilder::getFunctionSignature(Decl); 14189f6b26fSZixu Wang 14289f6b26fSZixu Wang // Add the function record to the API set. 14389f6b26fSZixu Wang API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration, 14489f6b26fSZixu Wang SubHeading, Signature); 14589f6b26fSZixu Wang return true; 14689f6b26fSZixu Wang } 14789f6b26fSZixu Wang 14889f6b26fSZixu Wang private: 14989f6b26fSZixu Wang /// Get availability information of the declaration \p D. 15089f6b26fSZixu Wang AvailabilityInfo getAvailability(const Decl *D) const { 15189f6b26fSZixu Wang StringRef PlatformName = Context.getTargetInfo().getPlatformName(); 15289f6b26fSZixu Wang 15389f6b26fSZixu Wang AvailabilityInfo Availability; 15489f6b26fSZixu Wang // Collect availability attributes from all redeclarations. 15589f6b26fSZixu Wang for (const auto *RD : D->redecls()) { 15689f6b26fSZixu Wang for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) { 15789f6b26fSZixu Wang if (A->getPlatform()->getName() != PlatformName) 15889f6b26fSZixu Wang continue; 15989f6b26fSZixu Wang Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(), 16089f6b26fSZixu Wang A->getObsoleted(), A->getUnavailable(), 16189f6b26fSZixu Wang /* UnconditionallyDeprecated */ false, 16289f6b26fSZixu Wang /* UnconditionallyUnavailable */ false); 16389f6b26fSZixu Wang break; 16489f6b26fSZixu Wang } 16589f6b26fSZixu Wang 16689f6b26fSZixu Wang if (const auto *A = RD->getAttr<UnavailableAttr>()) 16789f6b26fSZixu Wang if (!A->isImplicit()) { 16889f6b26fSZixu Wang Availability.Unavailable = true; 16989f6b26fSZixu Wang Availability.UnconditionallyUnavailable = true; 17089f6b26fSZixu Wang } 17189f6b26fSZixu Wang 17289f6b26fSZixu Wang if (const auto *A = RD->getAttr<DeprecatedAttr>()) 17389f6b26fSZixu Wang if (!A->isImplicit()) 17489f6b26fSZixu Wang Availability.UnconditionallyDeprecated = true; 17589f6b26fSZixu Wang } 17689f6b26fSZixu Wang 17789f6b26fSZixu Wang return Availability; 17889f6b26fSZixu Wang } 17989f6b26fSZixu Wang 18089f6b26fSZixu Wang ASTContext &Context; 18189f6b26fSZixu Wang APISet API; 18289f6b26fSZixu Wang }; 18389f6b26fSZixu Wang 18489f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer { 18589f6b26fSZixu Wang public: 186*5ef2ec7eSDaniel Grumberg ExtractAPIConsumer(ASTContext &Context, StringRef ProductName, 187*5ef2ec7eSDaniel Grumberg std::unique_ptr<raw_pwrite_stream> OS) 188*5ef2ec7eSDaniel Grumberg : Visitor(Context), ProductName(ProductName), OS(std::move(OS)) {} 18989f6b26fSZixu Wang 19089f6b26fSZixu Wang void HandleTranslationUnit(ASTContext &Context) override { 19189f6b26fSZixu Wang // Use ExtractAPIVisitor to traverse symbol declarations in the context. 19289f6b26fSZixu Wang Visitor.TraverseDecl(Context.getTranslationUnitDecl()); 19389f6b26fSZixu Wang 19489f6b26fSZixu Wang // Setup a SymbolGraphSerializer to write out collected API information in 19589f6b26fSZixu Wang // the Symbol Graph format. 19689f6b26fSZixu Wang // FIXME: Make the kind of APISerializer configurable. 197*5ef2ec7eSDaniel Grumberg SymbolGraphSerializer SGSerializer(Visitor.getAPI(), ProductName); 19889f6b26fSZixu Wang SGSerializer.serialize(*OS); 19989f6b26fSZixu Wang } 20089f6b26fSZixu Wang 20189f6b26fSZixu Wang private: 20289f6b26fSZixu Wang ExtractAPIVisitor Visitor; 203*5ef2ec7eSDaniel Grumberg std::string ProductName; 20489f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS; 20589f6b26fSZixu Wang }; 20689f6b26fSZixu Wang 20789f6b26fSZixu Wang } // namespace 20889f6b26fSZixu Wang 20989f6b26fSZixu Wang std::unique_ptr<ASTConsumer> 21089f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { 21189f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile); 21289f6b26fSZixu Wang if (!OS) 21389f6b26fSZixu Wang return nullptr; 214*5ef2ec7eSDaniel Grumberg return std::make_unique<ExtractAPIConsumer>( 215*5ef2ec7eSDaniel Grumberg CI.getASTContext(), CI.getInvocation().getFrontendOpts().ProductName, 21689f6b26fSZixu Wang std::move(OS)); 21789f6b26fSZixu Wang } 21889f6b26fSZixu Wang 21989f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> 22089f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { 22189f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream> OS = 22289f6b26fSZixu Wang CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json", 22389f6b26fSZixu Wang /*RemoveFileOnSignal=*/false); 22489f6b26fSZixu Wang if (!OS) 22589f6b26fSZixu Wang return nullptr; 22689f6b26fSZixu Wang return OS; 22789f6b26fSZixu Wang } 228