diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -587,6 +587,13 @@ - Option ``InsertBraces`` has been added to insert optional braces after control statements. +clang-extdef-mapping +-------------------- + +- clang-extdef-mapping now accepts .ast files as input. This is faster than to + recompile the files from sources when extracting method definitons. This can + be really beneficial when creating .ast files for input to the clang-static-analyzer. + libclang -------- diff --git a/clang/test/Analysis/func-mapping-test.cpp b/clang/test/Analysis/func-mapping-test.cpp --- a/clang/test/Analysis/func-mapping-test.cpp +++ b/clang/test/Analysis/func-mapping-test.cpp @@ -1,4 +1,6 @@ // RUN: %clang_extdef_map %s -- | FileCheck --implicit-check-not "c:@y" --implicit-check-not "c:@z" %s +// RUN: %clang -emit-ast %s -o %t.ast +// RUN: %clang_extdef_map %t.ast -- | FileCheck --implicit-check-not "c:@y" --implicit-check-not "c:@z" %s int f(int) { return 0; diff --git a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp --- a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp +++ b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp @@ -1,4 +1,4 @@ -//===- ClangExtDefMapGen.cpp -----------------------------------------------===// +//===- ClangExtDefMapGen.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,10 +13,12 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/SourceManager.h" #include "clang/CrossTU/CrossTranslationUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/CommandLine.h" @@ -29,12 +31,16 @@ using namespace clang::cross_tu; using namespace clang::tooling; -static cl::OptionCategory ClangExtDefMapGenCategory("clang-extdefmapgen options"); +static cl::OptionCategory + ClangExtDefMapGenCategory("clang-extdefmapgen options"); class MapExtDefNamesConsumer : public ASTConsumer { public: - MapExtDefNamesConsumer(ASTContext &Context) - : Ctx(Context), SM(Context.getSourceManager()) {} + MapExtDefNamesConsumer(ASTContext &Context, + StringRef astFilePath = StringRef()) + : Ctx(Context), SM(Context.getSourceManager()) { + CurrentFileName = astFilePath.str(); + } ~MapExtDefNamesConsumer() { // Flush results to standard output. @@ -111,6 +117,82 @@ static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); +static IntrusiveRefCntPtr Diags; + +IntrusiveRefCntPtr GetDiagnosticsEngine() { + if (Diags) { + // Call reset to make sure we don't mix errors + Diags->Reset(false); + return Diags; + } + + IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); + TextDiagnosticPrinter *DiagClient = + new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); + DiagClient->setPrefix("clang-extdef-mappping"); + IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + + IntrusiveRefCntPtr DiagEngine( + new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient)); + Diags.swap(DiagEngine); + + // Retain this one time so it's not destroyed by ASTUnit::LoadFromASTFile + Diags->Retain(); + return Diags; +} + +static CompilerInstance *CI = nullptr; + +static bool HandleAST(StringRef AstPath) { + + if (!CI) + CI = new CompilerInstance(); + + IntrusiveRefCntPtr DiagEngine = GetDiagnosticsEngine(); + + std::unique_ptr Unit = ASTUnit::LoadFromASTFile( + AstPath.str(), CI->getPCHContainerOperations()->getRawReader(), + ASTUnit::LoadASTOnly, DiagEngine, CI->getFileSystemOpts()); + + if (!Unit) + return false; + + FileManager FM(CI->getFileSystemOpts()); + SmallString<128> AbsPath(AstPath); + FM.makeAbsolutePath(AbsPath); + + MapExtDefNamesConsumer Consumer = + MapExtDefNamesConsumer(Unit->getASTContext(), AbsPath); + Consumer.HandleTranslationUnit(Unit->getASTContext()); + + return true; +} + +static int HandleFiles(ArrayRef SourceFiles, + CompilationDatabase &compilations) { + std::vector SourcesToBeParsed; + + // Loop over all input files, if they are pre-compiled AST + // process them directly in HandleAST, otherwise put them + // on a list for ClangTool to handle. + for (StringRef Src : SourceFiles) { + if (Src.endswith(".ast")) { + if (!HandleAST(Src)) { + return 1; + } + } else { + SourcesToBeParsed.push_back(Src.str()); + } + } + + if (!SourcesToBeParsed.empty()) { + ClangTool Tool(compilations, SourcesToBeParsed); + return Tool.run(newFrontendActionFactory().get()); + } + + return 0; +} + int main(int argc, const char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(argv[0], false); @@ -118,7 +200,10 @@ const char *Overview = "\nThis tool collects the USR name and location " "of external definitions in the source files " - "(excluding headers).\n"; + "(excluding headers).\n" + "Input can be either source files that are compiled " + "with compile database or .ast files that are " + "created from clang's -emit-ast option.\n"; auto ExpectedParser = CommonOptionsParser::create( argc, argv, ClangExtDefMapGenCategory, cl::ZeroOrMore, Overview); if (!ExpectedParser) { @@ -127,8 +212,6 @@ } CommonOptionsParser &OptionsParser = ExpectedParser.get(); - ClangTool Tool(OptionsParser.getCompilations(), - OptionsParser.getSourcePathList()); - - return Tool.run(newFrontendActionFactory().get()); + return HandleFiles(OptionsParser.getSourcePathList(), + OptionsParser.getCompilations()); }