OikawaKirie created this revision. OikawaKirie added reviewers: steakhal, gamesh411, martong, balazske. OikawaKirie added a project: clang. Herald added subscribers: ASDenysPetrov, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware, xazax.hun, mgorny. OikawaKirie requested review of this revision. Herald added a subscriber: cfe-commits.
It seems to be simpler and more convenient to reuse the compilation database generated for ClangTool when using clang-check to run the analyzer. In this patch, when the invocation list file is failed to be loaded, the ASTLoader will try to find a compilation database from the `ctu-dir` and convert the detected database to an invocation list. For each compile command objects in the database: - the "directory" entry is converted to option `-working-directory` appended to the invocation commands; - the "file" entry is updated to an absolute path based on the "directory" entry as the index; - and the "command" entry is converted to the invocation commands. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D102149 Files: clang/include/clang/CrossTU/CrossTranslationUnit.h clang/lib/CrossTU/CMakeLists.txt clang/lib/CrossTU/CrossTranslationUnit.cpp clang/test/Analysis/ctu-on-demand-parsing.c clang/test/Analysis/ctu-on-demand-parsing.cpp
Index: clang/test/Analysis/ctu-on-demand-parsing.cpp =================================================================== --- clang/test/Analysis/ctu-on-demand-parsing.cpp +++ clang/test/Analysis/ctu-on-demand-parsing.cpp @@ -13,6 +13,7 @@ // // RUN: cd "%t" && %clang_extdef_map Inputs/ctu-chain.cpp Inputs/ctu-other.cpp > externalDefMap.txt // +// Run with invocation list. // RUN: cd "%t" && %clang_analyze_cc1 \ // RUN: -analyzer-checker=core,debug.ExprInspection \ // RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \ @@ -26,6 +27,19 @@ // RUN: -analyzer-config ctu-invocation-list=invocations.yaml \ // RUN: -analyzer-config display-ctu-progress=true ctu-on-demand-parsing.cpp 2>&1 | FileCheck %t/ctu-on-demand-parsing.cpp // +// Run with compilation database. +// RUN: rm %t/invocations.yaml +// RUN: cd "%t" && %clang_analyze_cc1 \ +// RUN: -analyzer-checker=core,debug.ExprInspection \ +// RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \ +// RUN: -analyzer-config ctu-dir=. \ +// RUN: -verify ctu-on-demand-parsing.cpp +// RUN: cd "%t" && %clang_analyze_cc1 \ +// RUN: -analyzer-checker=core,debug.ExprInspection \ +// RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \ +// RUN: -analyzer-config ctu-dir=. \ +// RUN: -analyzer-config display-ctu-progress=true ctu-on-demand-parsing.cpp 2>&1 | FileCheck %t/ctu-on-demand-parsing.cpp +// // CHECK: CTU loaded AST file: {{.*}}ctu-other.cpp // CHECK: CTU loaded AST file: {{.*}}ctu-chain.cpp // Index: clang/test/Analysis/ctu-on-demand-parsing.c =================================================================== --- clang/test/Analysis/ctu-on-demand-parsing.c +++ clang/test/Analysis/ctu-on-demand-parsing.c @@ -11,6 +11,7 @@ // // RUN: cd "%t" && %clang_extdef_map "%t/ctu-other.c" > externalDefMap.txt // +// Run with invocation list. // RUN: cd "%t" && %clang_cc1 -fsyntax-only -std=c89 -analyze \ // RUN: -analyzer-checker=core,debug.ExprInspection \ // RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \ @@ -18,6 +19,14 @@ // RUN: -analyzer-config ctu-invocation-list=invocations.yaml \ // RUN: -verify ctu-on-demand-parsing.c // +// Run with compilation database. +// RUN: rm %t/invocations.yaml +// RUN: cd "%t" && %clang_cc1 -fsyntax-only -std=c89 -analyze \ +// RUN: -analyzer-checker=core,debug.ExprInspection \ +// RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \ +// RUN: -analyzer-config ctu-dir=. \ +// RUN: -verify ctu-on-demand-parsing.c +// // FIXME: Path handling should work on all platforms. // REQUIRES: system-linux Index: clang/lib/CrossTU/CrossTranslationUnit.cpp =================================================================== --- clang/lib/CrossTU/CrossTranslationUnit.cpp +++ clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -19,6 +19,8 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Index/USRGeneration.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/Tooling.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/Triple.h" @@ -119,14 +121,14 @@ case index_error_code::invocation_list_ambiguous: return "Invocation list file contains multiple references to the same " "source file."; - case index_error_code::invocation_list_file_not_found: - return "Invocation list file is not found."; case index_error_code::invocation_list_empty: return "Invocation list file is empty."; case index_error_code::invocation_list_wrong_format: return "Invocation list file is in wrong format."; - case index_error_code::invocation_list_lookup_unsuccessful: - return "Invocation list file does not contain the requested source file."; + case index_error_code::loader_lookup_unsuccessful: + return "Compile commands for the requested source file is not found."; + case index_error_code::loader_index_not_found: + return "Invocation list file or loader compilation database not found."; } llvm_unreachable("Unrecognized index_error_code."); } @@ -565,7 +567,7 @@ auto Invocation = InvocationList->find(SourceFilePath); if (Invocation == InvocationList->end()) return llvm::make_error<IndexError>( - index_error_code::invocation_list_lookup_unsuccessful); + index_error_code::loader_lookup_unsuccessful); const InvocationListTy::mapped_type &InvocationCommand = Invocation->second; @@ -668,24 +670,65 @@ if (InvocationList) return llvm::Error::success(); - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileContent = - llvm::MemoryBuffer::getFile(InvocationListFilePath); - if (!FileContent) - return llvm::make_error<IndexError>( - index_error_code::invocation_list_file_not_found); - std::unique_ptr<llvm::MemoryBuffer> ContentBuffer = std::move(*FileContent); - assert(ContentBuffer && "If no error was produced after loading, the pointer " - "should not be nullptr."); + llvm::Optional<llvm::Error> InvocationListParsingError; + if (llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileContent = + llvm::MemoryBuffer::getFile(InvocationListFilePath)) { + std::unique_ptr<llvm::MemoryBuffer> ContentBuffer = std::move(*FileContent); + assert(ContentBuffer && "If no error was produced after loading, the " + "pointer should not be nullptr."); + + llvm::Expected<InvocationListTy> ExpectedInvocationList = + parseInvocationList(ContentBuffer->getBuffer(), PathStyle); + + if (ExpectedInvocationList) { + InvocationList = *ExpectedInvocationList; + return llvm::Error::success(); + } + + InvocationListParsingError = ExpectedInvocationList.takeError(); + } - llvm::Expected<InvocationListTy> ExpectedInvocationList = - parseInvocationList(ContentBuffer->getBuffer(), PathStyle); + std::string CDBLoadingErrorMsg; + if (auto CDB = tooling::CompilationDatabase::autoDetectFromDirectory( + CTUDir, CDBLoadingErrorMsg)) { + InvocationListTy IL; - if (!ExpectedInvocationList) - return ExpectedInvocationList.takeError(); + for (auto &CC : CDB->getAllCompileCommands()) { + SmallString<256> Filename(CC.Directory); + if (llvm::sys::path::is_absolute(CC.Filename)) Filename = CC.Filename; + else llvm::sys::path::append(Filename, CC.Filename); + llvm::sys::path::remove_dots(Filename); - InvocationList = *ExpectedInvocationList; + if (IL.end() != IL.find(Filename)) { + IL.clear(); + break; + } + + auto &List = IL[Filename]; + for (auto &Argv : CC.CommandLine) + List.emplace_back(Argv); + + List.emplace_back("-Xclang"); + List.emplace_back("-working-directory=" + CC.Directory); + } + + if (!IL.empty()) { + InvocationList = IL; + // Neutralize the stored error during parsing invocation list. + if (InvocationListParsingError) { + handleAllErrors(std::move(*InvocationListParsingError), + [&](const IndexError &) {}); + } + return llvm::Error::success(); + } + } - return llvm::Error::success(); + // If an invocation list parsing error is stored, return this error. + // Otherwise, report not found. + return InvocationListParsingError + ? std::move(*InvocationListParsingError) + : llvm::make_error<IndexError>( + index_error_code::loader_index_not_found); } template <typename T> Index: clang/lib/CrossTU/CMakeLists.txt =================================================================== --- clang/lib/CrossTU/CMakeLists.txt +++ clang/lib/CrossTU/CMakeLists.txt @@ -10,4 +10,5 @@ clangBasic clangFrontend clangIndex + clangTooling ) Index: clang/include/clang/CrossTU/CrossTranslationUnit.h =================================================================== --- clang/include/clang/CrossTU/CrossTranslationUnit.h +++ clang/include/clang/CrossTU/CrossTranslationUnit.h @@ -51,10 +51,10 @@ lang_dialect_mismatch, load_threshold_reached, invocation_list_ambiguous, - invocation_list_file_not_found, invocation_list_empty, invocation_list_wrong_format, - invocation_list_lookup_unsuccessful + loader_lookup_unsuccessful, + loader_index_not_found, }; class IndexError : public llvm::ErrorInfo<IndexError> {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits