From 732e002b1320271421c8bd0d3477f3ce716b2bbe Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 3 Jun 2018 00:29:33 -0700 Subject: [PATCH] Infer system include paths from CompilerInvocation --- CMakeLists.txt | 2 +- cmake/FindClang.cmake | 6 +- ...ics_engine.cc => diagnostics_publisher.cc} | 10 +-- ...tics_engine.h => diagnostics_publisher.hh} | 2 +- src/indexer.cc | 5 -- src/message_handler.h | 4 +- src/messages/initialize.cc | 6 +- src/pipeline.cc | 16 ++--- src/pipeline.hh | 4 +- src/project.cc | 67 ++++++++++++++++--- 10 files changed, 85 insertions(+), 37 deletions(-) rename src/{diagnostics_engine.cc => diagnostics_publisher.cc} (79%) rename src/{diagnostics_engine.h => diagnostics_publisher.hh} (91%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 49a3061a..2e829ca7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,7 +193,7 @@ target_sources(ccls PRIVATE src/clang_tu.cc src/clang_utils.cc src/config.cc - src/diagnostics_engine.cc + src/diagnostics_publisher.cc src/file_consumer.cc src/filesystem.cc src/fuzzy_match.cc diff --git a/cmake/FindClang.cmake b/cmake/FindClang.cmake index 6bfac108..4fd60949 100644 --- a/cmake/FindClang.cmake +++ b/cmake/FindClang.cmake @@ -69,6 +69,8 @@ set(_Clang_REQUIRED_VARS Clang_LIBRARY Clang_INCLUDE_DIR Clang_EXECUTABLE LLVM_INCLUDE_DIR LLVM_BUILD_INCLUDE_DIR) _Clang_find_library(Clang_LIBRARY clang) +_Clang_find_add_library(clangFrontend) +_Clang_find_add_library(clangSerialization) _Clang_find_add_library(clangAST) _Clang_find_add_library(clangLex) _Clang_find_add_library(clangDriver) @@ -76,9 +78,11 @@ _Clang_find_add_library(clangBasic) if(USE_SHARED_LLVM) _Clang_find_add_library(LLVM) else() + _Clang_find_add_library(LLVMBitReader) + _Clang_find_add_library(LLVMOption) + _Clang_find_add_library(LLVMProfileData) _Clang_find_add_library(LLVMCore) _Clang_find_add_library(LLVMBinaryFormat) - _Clang_find_add_library(LLVMOption) _Clang_find_add_library(LLVMSupport) _Clang_find_add_library(LLVMDemangle) endif() diff --git a/src/diagnostics_engine.cc b/src/diagnostics_publisher.cc similarity index 79% rename from src/diagnostics_engine.cc rename to src/diagnostics_publisher.cc index c714ec9b..6402d98c 100644 --- a/src/diagnostics_engine.cc +++ b/src/diagnostics_publisher.cc @@ -1,19 +1,19 @@ -#include "diagnostics_engine.h" +#include "diagnostics_publisher.hh" #include "pipeline.hh" using namespace ccls; #include -void DiagnosticsEngine::Init() { +void DiagnosticsPublisher::Init() { frequencyMs_ = g_config->diagnostics.frequencyMs; match_ = std::make_unique(g_config->diagnostics.whitelist, g_config->diagnostics.blacklist); } -void DiagnosticsEngine::Publish(WorkingFiles* working_files, - std::string path, - std::vector diagnostics) { +void DiagnosticsPublisher::Publish(WorkingFiles* working_files, + std::string path, + std::vector diagnostics) { // Cache diagnostics so we can show fixits. working_files->DoActionOnFile(path, [&](WorkingFile* working_file) { if (working_file) diff --git a/src/diagnostics_engine.h b/src/diagnostics_publisher.hh similarity index 91% rename from src/diagnostics_engine.h rename to src/diagnostics_publisher.hh index 2d3e7aee..a6b5a688 100644 --- a/src/diagnostics_engine.h +++ b/src/diagnostics_publisher.hh @@ -3,7 +3,7 @@ #include "match.h" #include "working_files.h" -class DiagnosticsEngine { +class DiagnosticsPublisher { std::unique_ptr match_; int64_t nextPublish_ = 0; int frequencyMs_; diff --git a/src/indexer.cc b/src/indexer.cc index 3777bfd6..d8fd7ad9 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -2070,9 +2070,6 @@ std::vector> ParseWithTu( const std::string& file, const std::vector& args, const std::vector& file_contents) { - Timer timer; - timer.startTimer(); - IndexerCallbacks callback = {0}; // Available callbacks: // - abortQuery @@ -2114,8 +2111,6 @@ std::vector> ParseWithTu( ClangCursor(clang_getTranslationUnitCursor(tu->cx_tu)) .VisitChildren(&VisitMacroDefinitionAndExpansions, ¶m); - timer.stopTimer(); - std::unordered_map inc_to_line; // TODO if (param.primary_file) diff --git a/src/message_handler.h b/src/message_handler.h index 64e73e57..58bb1329 100644 --- a/src/message_handler.h +++ b/src/message_handler.h @@ -14,7 +14,7 @@ struct ClangCompleteManager; struct CodeCompleteCache; struct Config; -class DiagnosticsEngine; +class DiagnosticsPublisher; struct VFS; struct ImportManager; struct IncludeComplete; @@ -104,7 +104,7 @@ struct MessageHandler { DB* db = nullptr; MultiQueueWaiter* waiter = nullptr; Project* project = nullptr; - DiagnosticsEngine* diag_engine = nullptr; + DiagnosticsPublisher* diag_pub = nullptr; VFS* vfs = nullptr; ImportManager* import_manager = nullptr; SemanticHighlightSymbolCache* semantic_cache = nullptr; diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index 02d6c1db..55d8a2e6 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -1,4 +1,4 @@ -#include "diagnostics_engine.h" +#include "diagnostics_publisher.hh" #include "filesystem.hh" #include "include_complete.h" #include "log.hh" @@ -492,7 +492,7 @@ struct Handler_Initialize : BaseMessageHandler { sys::fs::create_directories(g_config->cacheDirectory + '@' + EscapeFileName(g_config->projectRoot)); - diag_engine->Init(); + diag_pub->Init(); semantic_cache->Init(); // Open up / load the project. @@ -510,7 +510,7 @@ struct Handler_Initialize : BaseMessageHandler { g_thread_id = i + 1; std::string name = "indexer" + std::to_string(i); set_thread_name(name.c_str()); - pipeline::Indexer_Main(diag_engine, vfs, project, working_files); + pipeline::Indexer_Main(diag_pub, vfs, project, working_files); }).detach(); } diff --git a/src/pipeline.cc b/src/pipeline.cc index cece67d3..52d154f7 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -2,7 +2,7 @@ #include "clang_complete.h" #include "config.h" -#include "diagnostics_engine.h" +#include "diagnostics_publisher.hh" #include "include_complete.h" #include "log.hh" #include "lsp.h" @@ -119,7 +119,7 @@ std::unique_ptr RawCacheLoad( *file_content, IndexFile::kMajorVersion); } -bool Indexer_Parse(DiagnosticsEngine* diag_engine, +bool Indexer_Parse(DiagnosticsPublisher* diag_pub, WorkingFiles* working_files, Project* project, VFS* vfs, @@ -224,7 +224,7 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine, // to identify indexing problems. For interactive sessions, diagnostics are // handled by code completion. if (!request.is_interactive) - diag_engine->Publish(working_files, curr->path, curr->diagnostics_); + diag_pub->Publish(working_files, curr->path, curr->diagnostics_); std::string path = curr->path; if (!(vfs->Stamp(path, curr->last_write_time) || path == path_to_index)) @@ -275,7 +275,7 @@ void Init() { for_stdout = new ThreadedQueue(stdout_waiter); } -void Indexer_Main(DiagnosticsEngine* diag_engine, +void Indexer_Main(DiagnosticsPublisher* diag_pub, VFS* vfs, Project* project, WorkingFiles* working_files) { @@ -283,7 +283,7 @@ void Indexer_Main(DiagnosticsEngine* diag_engine, ClangIndexer indexer; while (true) - if (!Indexer_Parse(diag_engine, working_files, project, vfs, &indexer)) + if (!Indexer_Parse(diag_pub, working_files, project, vfs, &indexer)) indexer_waiter->Wait(index_request); } @@ -386,12 +386,12 @@ void MainLoop() { SemanticHighlightSymbolCache semantic_cache; WorkingFiles working_files; VFS vfs; - DiagnosticsEngine diag_engine; + DiagnosticsPublisher diag_pub; ClangCompleteManager clang_complete( &project, &working_files, [&](std::string path, std::vector diagnostics) { - diag_engine.Publish(&working_files, path, diagnostics); + diag_pub.Publish(&working_files, path, diagnostics); }, [](lsRequestId id) { if (id.Valid()) { @@ -416,7 +416,7 @@ void MainLoop() { handler->db = &db; handler->waiter = indexer_waiter; handler->project = &project; - handler->diag_engine = &diag_engine; + handler->diag_pub = &diag_pub; handler->vfs = &vfs; handler->semantic_cache = &semantic_cache; handler->working_files = &working_files; diff --git a/src/pipeline.hh b/src/pipeline.hh index f21a44c7..a3926594 100644 --- a/src/pipeline.hh +++ b/src/pipeline.hh @@ -7,7 +7,7 @@ #include #include -class DiagnosticsEngine; +class DiagnosticsPublisher; struct VFS; struct Project; struct WorkingFiles; @@ -18,7 +18,7 @@ namespace ccls::pipeline { void Init(); void LaunchStdin(); void LaunchStdout(); -void Indexer_Main(DiagnosticsEngine* diag_engine, +void Indexer_Main(DiagnosticsPublisher* diag_pub, VFS* vfs, Project* project, WorkingFiles* working_files); diff --git a/src/project.cc b/src/project.cc index 1310efc1..4c7bf737 100644 --- a/src/project.cc +++ b/src/project.cc @@ -12,7 +12,10 @@ #include "working_files.h" using namespace ccls; +#include +#include #include +#include #include #include #include @@ -97,6 +100,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry( args.insert(args.end(), config->extra_flags.begin(), config->extra_flags.end()); +#if 1 std::unique_ptr Opts = driver::createDriverOptTable(); unsigned MissingArgIndex, MissingArgCount; std::vector cargs; @@ -105,18 +109,63 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry( InputArgList Args = Opts->ParseArgs(makeArrayRef(cargs), MissingArgIndex, MissingArgCount, driver::options::CC1Option); - using namespace clang::driver::options; - for (const auto* A : - Args.filtered(OPT_I, OPT_c_isystem, OPT_cxx_isystem, OPT_isystem)) + for (const auto* A : Args.filtered(OPT_I, OPT_c_isystem, OPT_cxx_isystem, + OPT_isystem, OPT_idirafter)) config->angle_dirs.insert(entry.ResolveIfRelative(A->getValue())); for (const auto* A : Args.filtered(OPT_I, OPT_iquote)) config->quote_dirs.insert(entry.ResolveIfRelative(A->getValue())); - for (const auto* A : Args.filtered(OPT_idirafter)) { - std::string dir = entry.ResolveIfRelative(A->getValue()); - config->angle_dirs.insert(dir); - config->quote_dirs.insert(dir); +#else + // a weird C++ deduction guide heap-use-after-free causes libclang to crash. + IgnoringDiagConsumer DiagC; + IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); + DiagnosticsEngine Diags( + IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, + &DiagC, false); + + driver::Driver Driver(args[0], llvm::sys::getDefaultTargetTriple(), Diags); + auto TargetAndMode = + driver::ToolChain::getTargetAndModeFromProgramName(args[0]); + if (!TargetAndMode.TargetPrefix.empty()) { + const char* arr[] = {"-target", TargetAndMode.TargetPrefix.c_str()}; + args.insert(args.begin() + 1, std::begin(arr), std::end(arr)); + Driver.setTargetAndMode(TargetAndMode); } + Driver.setCheckInputsExist(false); + + std::vector cargs; + for (auto& arg : args) + cargs.push_back(arg.c_str()); + cargs.push_back("-fsyntax-only"); + std::unique_ptr C(Driver.BuildCompilation(cargs)); + const driver::JobList& Jobs = C->getJobs(); + if (Jobs.size() != 1) + return result; + const driver::ArgStringList& CCArgs = Jobs.begin()->getArguments(); + + auto Invocation = std::make_unique(); + CompilerInvocation::CreateFromArgs(*Invocation, CCArgs.data(), + CCArgs.data() + CCArgs.size(), Diags); + Invocation->getFrontendOpts().DisableFree = false; + Invocation->getCodeGenOpts().DisableFree = false; + + HeaderSearchOptions& HeaderOpts = Invocation->getHeaderSearchOpts(); + for (auto& E : HeaderOpts.UserEntries) { + std::string path = entry.ResolveIfRelative(E.Path); + switch (E.Group) { + default: + config->angle_dirs.insert(path); + break; + case frontend::Quoted: + config->quote_dirs.insert(path); + break; + case frontend::Angled: + config->angle_dirs.insert(path); + config->quote_dirs.insert(path); + break; + } + } +#endif for (size_t i = 1; i < args.size(); i++) // This is most likely the file path we will be passing to clang. The @@ -128,9 +177,9 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry( continue; } - if (!Args.hasArg(OPT_resource_dir)) + // if (HeaderOpts.ResourceDir.empty() && HeaderOpts.UseBuiltinIncludes) args.push_back("-resource-dir=" + g_config->clang.resourceDir); - if (!Args.hasArg(OPT_working_directory)) + // if (Invocation->getFileSystemOpts().WorkingDir.empty()) args.push_back("-working-directory=" + entry.directory); // There could be a clang version mismatch between what the project uses and