Infer system include paths from CompilerInvocation

This commit is contained in:
Fangrui Song 2018-06-03 00:29:33 -07:00
parent 18fa5efa2a
commit 732e002b13
10 changed files with 85 additions and 37 deletions

View File

@ -193,7 +193,7 @@ target_sources(ccls PRIVATE
src/clang_tu.cc src/clang_tu.cc
src/clang_utils.cc src/clang_utils.cc
src/config.cc src/config.cc
src/diagnostics_engine.cc src/diagnostics_publisher.cc
src/file_consumer.cc src/file_consumer.cc
src/filesystem.cc src/filesystem.cc
src/fuzzy_match.cc src/fuzzy_match.cc

View File

@ -69,6 +69,8 @@ set(_Clang_REQUIRED_VARS Clang_LIBRARY Clang_INCLUDE_DIR Clang_EXECUTABLE
LLVM_INCLUDE_DIR LLVM_BUILD_INCLUDE_DIR) LLVM_INCLUDE_DIR LLVM_BUILD_INCLUDE_DIR)
_Clang_find_library(Clang_LIBRARY clang) _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(clangAST)
_Clang_find_add_library(clangLex) _Clang_find_add_library(clangLex)
_Clang_find_add_library(clangDriver) _Clang_find_add_library(clangDriver)
@ -76,9 +78,11 @@ _Clang_find_add_library(clangBasic)
if(USE_SHARED_LLVM) if(USE_SHARED_LLVM)
_Clang_find_add_library(LLVM) _Clang_find_add_library(LLVM)
else() 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(LLVMCore)
_Clang_find_add_library(LLVMBinaryFormat) _Clang_find_add_library(LLVMBinaryFormat)
_Clang_find_add_library(LLVMOption)
_Clang_find_add_library(LLVMSupport) _Clang_find_add_library(LLVMSupport)
_Clang_find_add_library(LLVMDemangle) _Clang_find_add_library(LLVMDemangle)
endif() endif()

View File

@ -1,17 +1,17 @@
#include "diagnostics_engine.h" #include "diagnostics_publisher.hh"
#include "pipeline.hh" #include "pipeline.hh"
using namespace ccls; using namespace ccls;
#include <chrono> #include <chrono>
void DiagnosticsEngine::Init() { void DiagnosticsPublisher::Init() {
frequencyMs_ = g_config->diagnostics.frequencyMs; frequencyMs_ = g_config->diagnostics.frequencyMs;
match_ = std::make_unique<GroupMatch>(g_config->diagnostics.whitelist, match_ = std::make_unique<GroupMatch>(g_config->diagnostics.whitelist,
g_config->diagnostics.blacklist); g_config->diagnostics.blacklist);
} }
void DiagnosticsEngine::Publish(WorkingFiles* working_files, void DiagnosticsPublisher::Publish(WorkingFiles* working_files,
std::string path, std::string path,
std::vector<lsDiagnostic> diagnostics) { std::vector<lsDiagnostic> diagnostics) {
// Cache diagnostics so we can show fixits. // Cache diagnostics so we can show fixits.

View File

@ -3,7 +3,7 @@
#include "match.h" #include "match.h"
#include "working_files.h" #include "working_files.h"
class DiagnosticsEngine { class DiagnosticsPublisher {
std::unique_ptr<GroupMatch> match_; std::unique_ptr<GroupMatch> match_;
int64_t nextPublish_ = 0; int64_t nextPublish_ = 0;
int frequencyMs_; int frequencyMs_;

View File

@ -2070,9 +2070,6 @@ std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
const std::string& file, const std::string& file,
const std::vector<std::string>& args, const std::vector<std::string>& args,
const std::vector<CXUnsavedFile>& file_contents) { const std::vector<CXUnsavedFile>& file_contents) {
Timer timer;
timer.startTimer();
IndexerCallbacks callback = {0}; IndexerCallbacks callback = {0};
// Available callbacks: // Available callbacks:
// - abortQuery // - abortQuery
@ -2114,8 +2111,6 @@ std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
ClangCursor(clang_getTranslationUnitCursor(tu->cx_tu)) ClangCursor(clang_getTranslationUnitCursor(tu->cx_tu))
.VisitChildren(&VisitMacroDefinitionAndExpansions, &param); .VisitChildren(&VisitMacroDefinitionAndExpansions, &param);
timer.stopTimer();
std::unordered_map<std::string, int> inc_to_line; std::unordered_map<std::string, int> inc_to_line;
// TODO // TODO
if (param.primary_file) if (param.primary_file)

View File

@ -14,7 +14,7 @@
struct ClangCompleteManager; struct ClangCompleteManager;
struct CodeCompleteCache; struct CodeCompleteCache;
struct Config; struct Config;
class DiagnosticsEngine; class DiagnosticsPublisher;
struct VFS; struct VFS;
struct ImportManager; struct ImportManager;
struct IncludeComplete; struct IncludeComplete;
@ -104,7 +104,7 @@ struct MessageHandler {
DB* db = nullptr; DB* db = nullptr;
MultiQueueWaiter* waiter = nullptr; MultiQueueWaiter* waiter = nullptr;
Project* project = nullptr; Project* project = nullptr;
DiagnosticsEngine* diag_engine = nullptr; DiagnosticsPublisher* diag_pub = nullptr;
VFS* vfs = nullptr; VFS* vfs = nullptr;
ImportManager* import_manager = nullptr; ImportManager* import_manager = nullptr;
SemanticHighlightSymbolCache* semantic_cache = nullptr; SemanticHighlightSymbolCache* semantic_cache = nullptr;

View File

@ -1,4 +1,4 @@
#include "diagnostics_engine.h" #include "diagnostics_publisher.hh"
#include "filesystem.hh" #include "filesystem.hh"
#include "include_complete.h" #include "include_complete.h"
#include "log.hh" #include "log.hh"
@ -492,7 +492,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
sys::fs::create_directories(g_config->cacheDirectory + '@' + sys::fs::create_directories(g_config->cacheDirectory + '@' +
EscapeFileName(g_config->projectRoot)); EscapeFileName(g_config->projectRoot));
diag_engine->Init(); diag_pub->Init();
semantic_cache->Init(); semantic_cache->Init();
// Open up / load the project. // Open up / load the project.
@ -510,7 +510,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
g_thread_id = i + 1; g_thread_id = i + 1;
std::string name = "indexer" + std::to_string(i); std::string name = "indexer" + std::to_string(i);
set_thread_name(name.c_str()); 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(); }).detach();
} }

View File

@ -2,7 +2,7 @@
#include "clang_complete.h" #include "clang_complete.h"
#include "config.h" #include "config.h"
#include "diagnostics_engine.h" #include "diagnostics_publisher.hh"
#include "include_complete.h" #include "include_complete.h"
#include "log.hh" #include "log.hh"
#include "lsp.h" #include "lsp.h"
@ -119,7 +119,7 @@ std::unique_ptr<IndexFile> RawCacheLoad(
*file_content, IndexFile::kMajorVersion); *file_content, IndexFile::kMajorVersion);
} }
bool Indexer_Parse(DiagnosticsEngine* diag_engine, bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
WorkingFiles* working_files, WorkingFiles* working_files,
Project* project, Project* project,
VFS* vfs, VFS* vfs,
@ -224,7 +224,7 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
// to identify indexing problems. For interactive sessions, diagnostics are // to identify indexing problems. For interactive sessions, diagnostics are
// handled by code completion. // handled by code completion.
if (!request.is_interactive) 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; std::string path = curr->path;
if (!(vfs->Stamp(path, curr->last_write_time) || path == path_to_index)) if (!(vfs->Stamp(path, curr->last_write_time) || path == path_to_index))
@ -275,7 +275,7 @@ void Init() {
for_stdout = new ThreadedQueue<Stdout_Request>(stdout_waiter); for_stdout = new ThreadedQueue<Stdout_Request>(stdout_waiter);
} }
void Indexer_Main(DiagnosticsEngine* diag_engine, void Indexer_Main(DiagnosticsPublisher* diag_pub,
VFS* vfs, VFS* vfs,
Project* project, Project* project,
WorkingFiles* working_files) { WorkingFiles* working_files) {
@ -283,7 +283,7 @@ void Indexer_Main(DiagnosticsEngine* diag_engine,
ClangIndexer indexer; ClangIndexer indexer;
while (true) 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); indexer_waiter->Wait(index_request);
} }
@ -386,12 +386,12 @@ void MainLoop() {
SemanticHighlightSymbolCache semantic_cache; SemanticHighlightSymbolCache semantic_cache;
WorkingFiles working_files; WorkingFiles working_files;
VFS vfs; VFS vfs;
DiagnosticsEngine diag_engine; DiagnosticsPublisher diag_pub;
ClangCompleteManager clang_complete( ClangCompleteManager clang_complete(
&project, &working_files, &project, &working_files,
[&](std::string path, std::vector<lsDiagnostic> diagnostics) { [&](std::string path, std::vector<lsDiagnostic> diagnostics) {
diag_engine.Publish(&working_files, path, diagnostics); diag_pub.Publish(&working_files, path, diagnostics);
}, },
[](lsRequestId id) { [](lsRequestId id) {
if (id.Valid()) { if (id.Valid()) {
@ -416,7 +416,7 @@ void MainLoop() {
handler->db = &db; handler->db = &db;
handler->waiter = indexer_waiter; handler->waiter = indexer_waiter;
handler->project = &project; handler->project = &project;
handler->diag_engine = &diag_engine; handler->diag_pub = &diag_pub;
handler->vfs = &vfs; handler->vfs = &vfs;
handler->semantic_cache = &semantic_cache; handler->semantic_cache = &semantic_cache;
handler->working_files = &working_files; handler->working_files = &working_files;

View File

@ -7,7 +7,7 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
class DiagnosticsEngine; class DiagnosticsPublisher;
struct VFS; struct VFS;
struct Project; struct Project;
struct WorkingFiles; struct WorkingFiles;
@ -18,7 +18,7 @@ namespace ccls::pipeline {
void Init(); void Init();
void LaunchStdin(); void LaunchStdin();
void LaunchStdout(); void LaunchStdout();
void Indexer_Main(DiagnosticsEngine* diag_engine, void Indexer_Main(DiagnosticsPublisher* diag_pub,
VFS* vfs, VFS* vfs,
Project* project, Project* project,
WorkingFiles* working_files); WorkingFiles* working_files);

View File

@ -12,7 +12,10 @@
#include "working_files.h" #include "working_files.h"
using namespace ccls; using namespace ccls;
#include <clang/Driver/Compilation.h>
#include <clang/Driver/Driver.h>
#include <clang/Driver/Options.h> #include <clang/Driver/Options.h>
#include <clang/Frontend/CompilerInstance.h>
#include <llvm/ADT/ArrayRef.h> #include <llvm/ADT/ArrayRef.h>
#include <llvm/Option/ArgList.h> #include <llvm/Option/ArgList.h>
#include <llvm/Option/OptTable.h> #include <llvm/Option/OptTable.h>
@ -97,6 +100,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
args.insert(args.end(), config->extra_flags.begin(), args.insert(args.end(), config->extra_flags.begin(),
config->extra_flags.end()); config->extra_flags.end());
#if 1
std::unique_ptr<OptTable> Opts = driver::createDriverOptTable(); std::unique_ptr<OptTable> Opts = driver::createDriverOptTable();
unsigned MissingArgIndex, MissingArgCount; unsigned MissingArgIndex, MissingArgCount;
std::vector<const char*> cargs; std::vector<const char*> cargs;
@ -105,18 +109,63 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
InputArgList Args = InputArgList Args =
Opts->ParseArgs(makeArrayRef(cargs), MissingArgIndex, MissingArgCount, Opts->ParseArgs(makeArrayRef(cargs), MissingArgIndex, MissingArgCount,
driver::options::CC1Option); driver::options::CC1Option);
using namespace clang::driver::options; using namespace clang::driver::options;
for (const auto* A : for (const auto* A : Args.filtered(OPT_I, OPT_c_isystem, OPT_cxx_isystem,
Args.filtered(OPT_I, OPT_c_isystem, OPT_cxx_isystem, OPT_isystem)) OPT_isystem, OPT_idirafter))
config->angle_dirs.insert(entry.ResolveIfRelative(A->getValue())); config->angle_dirs.insert(entry.ResolveIfRelative(A->getValue()));
for (const auto* A : Args.filtered(OPT_I, OPT_iquote)) for (const auto* A : Args.filtered(OPT_I, OPT_iquote))
config->quote_dirs.insert(entry.ResolveIfRelative(A->getValue())); config->quote_dirs.insert(entry.ResolveIfRelative(A->getValue()));
for (const auto* A : Args.filtered(OPT_idirafter)) { #else
std::string dir = entry.ResolveIfRelative(A->getValue()); // a weird C++ deduction guide heap-use-after-free causes libclang to crash.
config->angle_dirs.insert(dir); IgnoringDiagConsumer DiagC;
config->quote_dirs.insert(dir); IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
DiagnosticsEngine Diags(
IntrusiveRefCntPtr<DiagnosticIDs>(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<const char*> cargs;
for (auto& arg : args)
cargs.push_back(arg.c_str());
cargs.push_back("-fsyntax-only");
std::unique_ptr<driver::Compilation> 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>();
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++) for (size_t i = 1; i < args.size(); i++)
// This is most likely the file path we will be passing to clang. The // This is most likely the file path we will be passing to clang. The
@ -128,9 +177,9 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
continue; continue;
} }
if (!Args.hasArg(OPT_resource_dir)) // if (HeaderOpts.ResourceDir.empty() && HeaderOpts.UseBuiltinIncludes)
args.push_back("-resource-dir=" + g_config->clang.resourceDir); 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); args.push_back("-working-directory=" + entry.directory);
// There could be a clang version mismatch between what the project uses and // There could be a clang version mismatch between what the project uses and