mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-21 23:25:07 +00:00
Infer system include paths from CompilerInvocation
This commit is contained in:
parent
18fa5efa2a
commit
732e002b13
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
#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.
|
||||||
working_files->DoActionOnFile(path, [&](WorkingFile* working_file) {
|
working_files->DoActionOnFile(path, [&](WorkingFile* working_file) {
|
||||||
if (working_file)
|
if (working_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_;
|
@ -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, ¶m);
|
.VisitChildren(&VisitMacroDefinitionAndExpansions, ¶m);
|
||||||
|
|
||||||
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)
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user