mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-30 11:27:07 +00:00
.
This commit is contained in:
parent
d83be5adcc
commit
46fc3b8323
@ -179,6 +179,7 @@ target_sources(ccls PRIVATE
|
||||
src/clang_translation_unit.cc
|
||||
src/clang_utils.cc
|
||||
src/command_line.cc
|
||||
src/config.cc
|
||||
src/diagnostics_engine.cc
|
||||
src/file_consumer.cc
|
||||
src/file_contents.cc
|
||||
@ -209,7 +210,6 @@ target_sources(ccls PRIVATE
|
||||
src/timestamp_manager.cc
|
||||
src/type_printer.cc
|
||||
src/utils.cc
|
||||
src/work_thread.cc
|
||||
src/working_files.cc)
|
||||
|
||||
target_sources(ccls PRIVATE
|
||||
@ -217,7 +217,6 @@ target_sources(ccls PRIVATE
|
||||
src/messages/ccls_call_hierarchy.cc
|
||||
src/messages/ccls_callers.cc
|
||||
src/messages/ccls_derived.cc
|
||||
src/messages/ccls_did_view.cc
|
||||
src/messages/ccls_file_info.cc
|
||||
src/messages/ccls_freshen_index.cc
|
||||
src/messages/ccls_index_file.cc
|
||||
@ -225,7 +224,6 @@ target_sources(ccls PRIVATE
|
||||
src/messages/ccls_member_hierarchy.cc
|
||||
src/messages/ccls_random.cc
|
||||
src/messages/ccls_vars.cc
|
||||
src/messages/ccls_wait.cc
|
||||
src/messages/exit.cc
|
||||
src/messages/initialize.cc
|
||||
src/messages/shutdown.cc
|
||||
|
@ -9,10 +9,10 @@
|
||||
|
||||
#include <loguru.hpp>
|
||||
|
||||
#include <limits.h>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
|
||||
// TODO: See if we can use clang_indexLoc_getFileLocation to get a type ref on
|
||||
@ -861,7 +861,7 @@ CXIdxClientFile OnIndexIncludedFile(CXClientData client_data,
|
||||
IndexInclude include;
|
||||
include.line = line;
|
||||
include.resolved_path = FileName(file->file);
|
||||
if (!include.resolved_path.empty())
|
||||
if (include.resolved_path.size())
|
||||
db->includes.push_back(include);
|
||||
|
||||
return nullptr;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "clang_utils.h"
|
||||
|
||||
#include "filesystem.hh"
|
||||
#include "platform.h"
|
||||
|
||||
namespace {
|
||||
@ -106,8 +107,11 @@ std::optional<lsDiagnostic> BuildAndDisposeDiagnostic(CXDiagnostic diagnostic,
|
||||
|
||||
std::string FileName(CXFile file) {
|
||||
CXString cx_name = clang_getFileName(file);
|
||||
std::string name = ToString(cx_name);
|
||||
return NormalizePath(name);
|
||||
std::string ret = NormalizePath(ToString(cx_name));
|
||||
// Resolve /usr/include/c++/7.3.0 symlink.
|
||||
if (!StartsWith(ret, g_config.projectRoot))
|
||||
ret = fs::canonical(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string ToString(CXString cx_string) {
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "test.h"
|
||||
#include "timer.h"
|
||||
#include "timestamp_manager.h"
|
||||
#include "work_thread.h"
|
||||
#include "working_files.h"
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
@ -35,7 +34,6 @@
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@ -255,7 +253,7 @@ void LaunchStdinLoop(Config* config,
|
||||
// clients.
|
||||
std::cin.tie(nullptr);
|
||||
|
||||
WorkThread::StartThread("stdin", [request_times]() {
|
||||
StartThread("stdin", [request_times]() {
|
||||
auto* queue = QueueManager::instance();
|
||||
while (true) {
|
||||
std::unique_ptr<InMessage> message;
|
||||
@ -295,7 +293,7 @@ void LaunchStdinLoop(Config* config,
|
||||
|
||||
void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
|
||||
MultiQueueWaiter* waiter) {
|
||||
WorkThread::StartThread("stdout", [=]() {
|
||||
StartThread("stdout", [=]() {
|
||||
auto* queue = QueueManager::instance();
|
||||
|
||||
while (true) {
|
||||
|
3
src/config.cc
Normal file
3
src/config.cc
Normal file
@ -0,0 +1,3 @@
|
||||
#include "config.h"
|
||||
|
||||
Config g_config;
|
@ -281,5 +281,4 @@ MAKE_REFLECT_STRUCT(Config,
|
||||
|
||||
dumpAST);
|
||||
|
||||
// Expected client version. We show an error if this doesn't match.
|
||||
constexpr const int kExpectedClientVersion = 3;
|
||||
extern Config g_config;
|
||||
|
@ -5,9 +5,6 @@
|
||||
#include "project.h"
|
||||
#include "standard_includes.h"
|
||||
#include "timer.h"
|
||||
#include "work_thread.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace {
|
||||
|
||||
@ -116,7 +113,7 @@ void IncludeComplete::Rescan() {
|
||||
config_->completion.includeBlacklist);
|
||||
|
||||
is_scanning = true;
|
||||
WorkThread::StartThread("scan_includes", [this]() {
|
||||
StartThread("scan_includes", [this]() {
|
||||
Timer timer;
|
||||
|
||||
InsertStlIncludes();
|
||||
|
@ -1,40 +0,0 @@
|
||||
#include "clang_complete.h"
|
||||
#include "message_handler.h"
|
||||
#include "working_files.h"
|
||||
|
||||
namespace {
|
||||
MethodType kMethodType = "$ccls/textDocumentDidView";
|
||||
|
||||
struct In_CclsTextDocumentDidView : public NotificationInMessage {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
struct Params {
|
||||
lsDocumentUri textDocumentUri;
|
||||
};
|
||||
Params params;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(In_CclsTextDocumentDidView::Params, textDocumentUri);
|
||||
MAKE_REFLECT_STRUCT(In_CclsTextDocumentDidView, params);
|
||||
REGISTER_IN_MESSAGE(In_CclsTextDocumentDidView);
|
||||
|
||||
struct Handler_CclsDidView
|
||||
: BaseMessageHandler<In_CclsTextDocumentDidView> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_CclsTextDocumentDidView* request) override {
|
||||
std::string path = request->params.textDocumentUri.GetPath();
|
||||
|
||||
WorkingFile* working_file = working_files->GetFileByFilename(path);
|
||||
if (!working_file)
|
||||
return;
|
||||
QueryFile* file = nullptr;
|
||||
if (!FindFileOrFail(db, project, std::nullopt, path, &file))
|
||||
return;
|
||||
|
||||
clang_complete->NotifyView(path);
|
||||
if (file->def) {
|
||||
EmitInactiveLines(working_file, file->def->inactive_regions);
|
||||
EmitSemanticHighlighting(db, semantic_cache, working_file, file);
|
||||
}
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsDidView);
|
||||
} // namespace
|
@ -1,47 +0,0 @@
|
||||
#include "import_manager.h"
|
||||
#include "import_pipeline.h"
|
||||
#include "message_handler.h"
|
||||
#include "queue_manager.h"
|
||||
|
||||
#include <loguru.hpp>
|
||||
|
||||
namespace {
|
||||
MethodType kMethodType = "$ccls/wait";
|
||||
|
||||
struct In_CclsWait : public NotificationInMessage {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
};
|
||||
MAKE_REFLECT_EMPTY_STRUCT(In_CclsWait);
|
||||
REGISTER_IN_MESSAGE(In_CclsWait);
|
||||
|
||||
struct Handler_CclsWait : MessageHandler {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
|
||||
void Run(std::unique_ptr<InMessage> request) override {
|
||||
// TODO: use status message system here, then run querydb as normal? Maybe
|
||||
// this cannot be a normal message, ie, it needs to be re-entrant.
|
||||
|
||||
LOG_S(INFO) << "Waiting for idle";
|
||||
int idle_count = 0;
|
||||
while (true) {
|
||||
bool has_work = false;
|
||||
has_work |= import_pipeline_status->num_active_threads != 0;
|
||||
has_work |= QueueManager::instance()->HasWork();
|
||||
has_work |=
|
||||
QueryDb_ImportMain(config, db, import_manager, import_pipeline_status,
|
||||
semantic_cache, working_files);
|
||||
if (!has_work)
|
||||
++idle_count;
|
||||
else
|
||||
idle_count = 0;
|
||||
|
||||
// There are race conditions between each of the three checks above,
|
||||
// so we retry a bunch of times to try to avoid any.
|
||||
if (idle_count > 10)
|
||||
break;
|
||||
}
|
||||
LOG_S(INFO) << "Done waiting for idle";
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsWait);
|
||||
} // namespace
|
@ -8,7 +8,6 @@
|
||||
#include "queue_manager.h"
|
||||
#include "serializers/json.h"
|
||||
#include "timer.h"
|
||||
#include "work_thread.h"
|
||||
#include "working_files.h"
|
||||
|
||||
#include <loguru.hpp>
|
||||
@ -270,45 +269,13 @@ struct lsTextDocumentClientCapabilities {
|
||||
// The client supports the following `CompletionItem` specific
|
||||
// capabilities.
|
||||
std::optional<lsCompletionItem> completionItem;
|
||||
};
|
||||
// Capabilities specific to the `textDocument/completion`
|
||||
std::optional<lsCompletion> completion;
|
||||
} completion;
|
||||
|
||||
struct lsGenericDynamicReg {
|
||||
// Whether foo supports dynamic registration.
|
||||
std::optional<bool> dynamicRegistration;
|
||||
};
|
||||
|
||||
// Capabilities specific to the `textDocument/hover`
|
||||
std::optional<lsGenericDynamicReg> hover;
|
||||
|
||||
// Capabilities specific to the `textDocument/signatureHelp`
|
||||
std::optional<lsGenericDynamicReg> signatureHelp;
|
||||
|
||||
// Capabilities specific to the `textDocument/references`
|
||||
std::optional<lsGenericDynamicReg> references;
|
||||
|
||||
// Capabilities specific to the `textDocument/documentHighlight`
|
||||
std::optional<lsGenericDynamicReg> documentHighlight;
|
||||
|
||||
// Capabilities specific to the `textDocument/documentSymbol`
|
||||
std::optional<lsGenericDynamicReg> documentSymbol;
|
||||
|
||||
// Capabilities specific to the `textDocument/formatting`
|
||||
std::optional<lsGenericDynamicReg> formatting;
|
||||
|
||||
// Capabilities specific to the `textDocument/rangeFormatting`
|
||||
std::optional<lsGenericDynamicReg> rangeFormatting;
|
||||
|
||||
// Capabilities specific to the `textDocument/onTypeFormatting`
|
||||
std::optional<lsGenericDynamicReg> onTypeFormatting;
|
||||
|
||||
// Capabilities specific to the `textDocument/definition`
|
||||
std::optional<lsGenericDynamicReg> definition;
|
||||
|
||||
// Capabilities specific to the `textDocument/codeAction`
|
||||
std::optional<lsGenericDynamicReg> codeAction;
|
||||
|
||||
struct CodeLensRegistrationOptions : public lsGenericDynamicReg {
|
||||
// Code lens has a resolve provider as well.
|
||||
bool resolveProvider;
|
||||
@ -317,9 +284,6 @@ struct lsTextDocumentClientCapabilities {
|
||||
// Capabilities specific to the `textDocument/codeLens`
|
||||
std::optional<CodeLensRegistrationOptions> codeLens;
|
||||
|
||||
// Capabilities specific to the `textDocument/documentLink`
|
||||
std::optional<lsGenericDynamicReg> documentLink;
|
||||
|
||||
// Capabilities specific to the `textDocument/rename`
|
||||
std::optional<lsGenericDynamicReg> rename;
|
||||
};
|
||||
@ -344,18 +308,6 @@ MAKE_REFLECT_STRUCT(
|
||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities,
|
||||
synchronization,
|
||||
completion,
|
||||
hover,
|
||||
signatureHelp,
|
||||
references,
|
||||
documentHighlight,
|
||||
documentSymbol,
|
||||
formatting,
|
||||
rangeFormatting,
|
||||
onTypeFormatting,
|
||||
definition,
|
||||
codeAction,
|
||||
codeLens,
|
||||
documentLink,
|
||||
rename);
|
||||
|
||||
struct lsClientCapabilities {
|
||||
@ -512,29 +464,9 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
|
||||
// Client capabilities
|
||||
{
|
||||
const auto& cap = request->params.capabilities.textDocument;
|
||||
if (cap.completion && cap.completion->completionItem)
|
||||
if (cap.completion.completionItem)
|
||||
config->client.snippetSupport =
|
||||
cap.completion->completionItem->snippetSupport.value_or(false);
|
||||
}
|
||||
|
||||
// Check client version.
|
||||
if (config->clientVersion.has_value() &&
|
||||
*config->clientVersion != kExpectedClientVersion) {
|
||||
Out_ShowLogMessage out;
|
||||
out.display_type = Out_ShowLogMessage::DisplayType::Show;
|
||||
out.params.type = lsMessageType::Error;
|
||||
out.params.message =
|
||||
"ccls client (v" + std::to_string(*config->clientVersion) +
|
||||
") and server (v" + std::to_string(kExpectedClientVersion) +
|
||||
") version mismatch. Please update ";
|
||||
if (config->clientVersion > kExpectedClientVersion)
|
||||
out.params.message += "the ccls binary.";
|
||||
else
|
||||
out.params.message +=
|
||||
"your extension client (VSIX file). Make sure to uninstall "
|
||||
"the ccls extension and restart vscode before "
|
||||
"reinstalling.";
|
||||
out.Write(std::cout);
|
||||
cap.completion.completionItem->snippetSupport.value_or(false);
|
||||
}
|
||||
|
||||
// Ensure there is a resource directory.
|
||||
@ -576,6 +508,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
|
||||
MakeDirectoryRecursive(config->cacheDirectory + '@' +
|
||||
EscapeFileName(config->projectRoot));
|
||||
|
||||
g_config = *config;
|
||||
Timer time;
|
||||
diag_engine->Init(config);
|
||||
semantic_cache->Init(config);
|
||||
@ -599,7 +532,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
|
||||
}
|
||||
LOG_S(INFO) << "Starting " << config->index.threads << " indexers";
|
||||
for (int i = 0; i < config->index.threads; ++i) {
|
||||
WorkThread::StartThread("indexer" + std::to_string(i), [=]() {
|
||||
StartThread("indexer" + std::to_string(i), [=]() {
|
||||
Indexer_Main(config, diag_engine, file_consumer_shared,
|
||||
timestamp_manager, import_manager,
|
||||
import_pipeline_status, project, working_files, waiter);
|
||||
|
@ -72,10 +72,9 @@ struct Handler_TextDocumentDidOpen
|
||||
|
||||
clang_complete->FlushSession(entry.filename);
|
||||
LOG_S(INFO) << "Flushed clang complete sessions for " << entry.filename;
|
||||
if (params.args.size()) {
|
||||
if (params.args.size())
|
||||
project->SetFlagsForFile(params.args, path);
|
||||
}
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidOpen);
|
||||
} // namespace
|
||||
|
@ -1,62 +0,0 @@
|
||||
#include "clang_format.h"
|
||||
#include "message_handler.h"
|
||||
#include "queue_manager.h"
|
||||
#include "working_files.h"
|
||||
|
||||
#include <loguru.hpp>
|
||||
|
||||
namespace {
|
||||
MethodType kMethodType = "textDocument/formatting";
|
||||
|
||||
struct In_TextDocumentFormatting : public RequestInMessage {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
struct Params {
|
||||
lsTextDocumentIdentifier textDocument;
|
||||
lsFormattingOptions options;
|
||||
};
|
||||
Params params;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentFormatting::Params, textDocument, options);
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentFormatting, id, params);
|
||||
REGISTER_IN_MESSAGE(In_TextDocumentFormatting);
|
||||
|
||||
struct Out_TextDocumentFormatting
|
||||
: public lsOutMessage<Out_TextDocumentFormatting> {
|
||||
lsRequestId id;
|
||||
std::vector<lsTextEdit> result;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(Out_TextDocumentFormatting, jsonrpc, id, result);
|
||||
|
||||
struct Handler_TextDocumentFormatting
|
||||
: BaseMessageHandler<In_TextDocumentFormatting> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_TextDocumentFormatting* request) override {
|
||||
Out_TextDocumentFormatting response;
|
||||
response.id = request->id;
|
||||
#if USE_CLANG_CXX
|
||||
QueryFile* file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
request->params.textDocument.uri.GetPath(), &file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkingFile* working_file =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
response.result = ConvertClangReplacementsIntoTextEdits(
|
||||
working_file->buffer_content,
|
||||
ClangFormatDocument(working_file, 0,
|
||||
working_file->buffer_content.size(),
|
||||
request->params.options));
|
||||
#else
|
||||
LOG_S(WARNING) << "You must compile ccls with --use-clang-cxx to use "
|
||||
"textDocument/formatting.";
|
||||
// TODO: Fallback to execute the clang-format binary?
|
||||
response.result = {};
|
||||
#endif
|
||||
|
||||
QueueManager::WriteStdout(kMethodType, response);
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentFormatting);
|
||||
} // namespace
|
@ -277,7 +277,7 @@ void TraceMe() {
|
||||
// If the environment variable is defined, wait for a debugger.
|
||||
// In gdb, you need to invoke `signal SIGCONT` if you want ccls to continue
|
||||
// after detaching.
|
||||
if (getenv("CQUERY_TRACEME"))
|
||||
if (getenv("CCLS_TRACEME"))
|
||||
raise(SIGTSTP);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,6 @@
|
||||
|
||||
void ccls_unreachable_internal(const char* msg, const char* file, int line) {
|
||||
fprintf(stderr, "unreachable %s:%d %s\n", file, line, msg);
|
||||
CQUERY_BUILTIN_UNREACHABLE;
|
||||
CCLS_BUILTIN_UNREACHABLE;
|
||||
abort();
|
||||
}
|
||||
|
10
src/port.h
10
src/port.h
@ -12,17 +12,17 @@
|
||||
|
||||
// TODO GCC
|
||||
#if __has_builtin(__builtin_unreachable)
|
||||
#define CQUERY_BUILTIN_UNREACHABLE __builtin_unreachable()
|
||||
#define CCLS_BUILTIN_UNREACHABLE __builtin_unreachable()
|
||||
#elif defined(_MSC_VER)
|
||||
#define CQUERY_BUILTIN_UNREACHABLE __assume(false)
|
||||
#define CCLS_BUILTIN_UNREACHABLE __assume(false)
|
||||
#else
|
||||
#define CQUERY_BUILTIN_UNREACHABLE
|
||||
#define CCLS_BUILTIN_UNREACHABLE
|
||||
#endif
|
||||
|
||||
void ccls_unreachable_internal(const char* msg, const char* file, int line);
|
||||
#ifndef NDEBUG
|
||||
#define CQUERY_UNREACHABLE(msg) \
|
||||
#define CCLS_UNREACHABLE(msg) \
|
||||
ccls_unreachable_internal(msg, __FILE__, __LINE__)
|
||||
#else
|
||||
#define CQUERY_UNREACHABLE(msg)
|
||||
#define CCLS_UNREACHABLE(msg)
|
||||
#endif
|
||||
|
121
src/project.cc
121
src/project.cc
@ -2,6 +2,7 @@
|
||||
|
||||
#include "cache_manager.h"
|
||||
#include "clang_utils.h"
|
||||
#include "filesystem.hh"
|
||||
#include "language.h"
|
||||
#include "match.h"
|
||||
#include "platform.h"
|
||||
@ -27,41 +28,22 @@
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
extern bool gTestOutputMode;
|
||||
|
||||
struct CompileCommandsEntry {
|
||||
std::string directory;
|
||||
fs::path directory;
|
||||
std::string file;
|
||||
std::string command;
|
||||
std::vector<std::string> args;
|
||||
|
||||
fs::path ResolveIfRelative(fs::path path) const {
|
||||
if (path.is_absolute())
|
||||
return path;
|
||||
return directory / path;
|
||||
}
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(CompileCommandsEntry, directory, file, command, args);
|
||||
|
||||
namespace {
|
||||
|
||||
bool g_disable_normalize_path_for_test = false;
|
||||
|
||||
std::string NormalizePathWithTestOptOut(const std::string& path) {
|
||||
if (g_disable_normalize_path_for_test) {
|
||||
// Add a & so we can test to verify a path is normalized.
|
||||
return "&" + path;
|
||||
}
|
||||
return NormalizePath(path);
|
||||
}
|
||||
|
||||
bool IsUnixAbsolutePath(const std::string& path) {
|
||||
return !path.empty() && path[0] == '/';
|
||||
}
|
||||
|
||||
bool IsWindowsAbsolutePath(const std::string& path) {
|
||||
auto is_drive_letter = [](char c) {
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
|
||||
};
|
||||
|
||||
return path.size() > 3 && path[1] == ':' &&
|
||||
(path[2] == '/' || path[2] == '\\') && is_drive_letter(path[0]);
|
||||
}
|
||||
|
||||
enum class ProjectMode { CompileCommandsJson, DotCcls, ExternalCommand };
|
||||
|
||||
struct ProjectConfig {
|
||||
@ -127,22 +109,8 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||
Config* init_opts,
|
||||
ProjectConfig* config,
|
||||
const CompileCommandsEntry& entry) {
|
||||
auto cleanup_maybe_relative_path = [&](const std::string& path) {
|
||||
// TODO/FIXME: Normalization will fail for paths that do not exist. Should
|
||||
// it return an std::optional<std::string>?
|
||||
assert(!path.empty());
|
||||
if (entry.directory.empty() || IsUnixAbsolutePath(path) ||
|
||||
IsWindowsAbsolutePath(path)) {
|
||||
// We still want to normalize, as the path may contain .. characters.
|
||||
return NormalizePathWithTestOptOut(path);
|
||||
}
|
||||
if (EndsWith(entry.directory, "/"))
|
||||
return NormalizePathWithTestOptOut(entry.directory + path);
|
||||
return NormalizePathWithTestOptOut(entry.directory + "/" + path);
|
||||
};
|
||||
|
||||
Project::Entry result;
|
||||
result.filename = NormalizePathWithTestOptOut(entry.file);
|
||||
result.filename = entry.file;
|
||||
const std::string base_name = GetBaseName(entry.file);
|
||||
|
||||
// Expand %c %cpp %clang
|
||||
@ -185,7 +153,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||
|
||||
// Add -working-directory if not provided.
|
||||
if (!AnyStartsWith(args, "-working-directory"))
|
||||
result.args.emplace_back("-working-directory=" + entry.directory);
|
||||
result.args.emplace_back("-working-directory=" + entry.directory.string());
|
||||
|
||||
bool next_flag_is_path = false;
|
||||
bool add_next_flag_to_quote_dirs = false;
|
||||
@ -212,7 +180,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||
// Finish processing path for the previous argument, which was a switch.
|
||||
// {"-I", "foo"} style.
|
||||
if (next_flag_is_path) {
|
||||
std::string normalized_arg = cleanup_maybe_relative_path(arg);
|
||||
std::string normalized_arg = entry.ResolveIfRelative(arg);
|
||||
if (add_next_flag_to_quote_dirs)
|
||||
config->quote_dirs.insert(normalized_arg);
|
||||
if (add_next_flag_to_angle_dirs)
|
||||
@ -238,7 +206,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||
if (StartsWith(arg, flag_type)) {
|
||||
std::string path = arg.substr(flag_type.size());
|
||||
assert(!path.empty());
|
||||
path = cleanup_maybe_relative_path(path);
|
||||
path = entry.ResolveIfRelative(path);
|
||||
if (clang_cl || StartsWithAny(arg, kNormalizePathArgs))
|
||||
arg = flag_type + path;
|
||||
if (ShouldAddToQuoteIncludes(flag_type))
|
||||
@ -254,7 +222,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||
// slow. See
|
||||
// https://github.com/cquery-project/cquery/commit/af63df09d57d765ce12d40007bf56302a0446678.
|
||||
if (EndsWith(arg, base_name))
|
||||
arg = cleanup_maybe_relative_path(arg);
|
||||
arg = entry.ResolveIfRelative(arg);
|
||||
// TODO Exclude .a .o to make link command in compile_commands.json work.
|
||||
// Also, clang_parseTranslationUnit2FullArgv does not seem to accept
|
||||
// multiple source filenames.
|
||||
@ -450,13 +418,7 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
|
||||
|
||||
our_time.Resume();
|
||||
entry.directory = directory;
|
||||
std::string absolute_filename;
|
||||
if (IsUnixAbsolutePath(relative_filename) ||
|
||||
IsWindowsAbsolutePath(relative_filename))
|
||||
absolute_filename = relative_filename;
|
||||
else
|
||||
absolute_filename = directory + "/" + relative_filename;
|
||||
entry.file = NormalizePathWithTestOptOut(absolute_filename);
|
||||
entry.file = entry.ResolveIfRelative(relative_filename);
|
||||
|
||||
result.push_back(
|
||||
GetCompilationEntryFromCompileCommandEntry(config, project, entry));
|
||||
@ -513,8 +475,8 @@ void Project::Load(Config* config, const std::string& root_directory) {
|
||||
}
|
||||
|
||||
// Setup project entries.
|
||||
absolute_path_to_entry_index_.resize(entries.size());
|
||||
for (int i = 0; i < entries.size(); ++i)
|
||||
absolute_path_to_entry_index_.reserve(entries.size());
|
||||
for (size_t i = 0; i < entries.size(); ++i)
|
||||
absolute_path_to_entry_index_[entries[i].filename] = i;
|
||||
}
|
||||
|
||||
@ -616,9 +578,6 @@ TEST_SUITE("Project") {
|
||||
void CheckFlags(const std::string& directory, const std::string& file,
|
||||
std::vector<std::string> raw,
|
||||
std::vector<std::string> expected) {
|
||||
g_disable_normalize_path_for_test = true;
|
||||
gTestOutputMode = true;
|
||||
|
||||
Config config;
|
||||
ProjectConfig project;
|
||||
project.project_dir = "/w/c/s/";
|
||||
@ -656,7 +615,7 @@ TEST_SUITE("Project") {
|
||||
CheckFlags(
|
||||
/* raw */ {"clang", "-lstdc++", "myfile.cc"},
|
||||
/* expected */
|
||||
{"clang", "-working-directory=/dir/", "-lstdc++", "&/dir/myfile.cc",
|
||||
{"clang", "-working-directory=/dir/", "-lstdc++", "/dir/myfile.cc",
|
||||
"-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
|
||||
"-fparse-all-comments"});
|
||||
|
||||
@ -668,17 +627,18 @@ TEST_SUITE("Project") {
|
||||
"-fparse-all-comments"});
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST_CASE("Windows path normalization") {
|
||||
CheckFlags("E:/workdir", "E:/workdir/bar.cc", /* raw */ {"clang", "bar.cc"},
|
||||
/* expected */
|
||||
{"clang", "-working-directory=E:/workdir", "&E:/workdir/bar.cc",
|
||||
{"clang", "-working-directory=E:/workdir", "E:/workdir/bar.cc",
|
||||
"-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
|
||||
"-fparse-all-comments"});
|
||||
|
||||
CheckFlags("E:/workdir", "E:/workdir/bar.cc",
|
||||
/* raw */ {"clang", "E:/workdir/bar.cc"},
|
||||
/* expected */
|
||||
{"clang", "-working-directory=E:/workdir", "&E:/workdir/bar.cc",
|
||||
{"clang", "-working-directory=E:/workdir", "E:/workdir/bar.cc",
|
||||
"-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
|
||||
"-fparse-all-comments"});
|
||||
|
||||
@ -686,7 +646,7 @@ TEST_SUITE("Project") {
|
||||
/* raw */ {"clang-cl.exe", "/I./test", "E:/workdir/bar.cc"},
|
||||
/* expected */
|
||||
{"clang-cl.exe", "-working-directory=E:/workdir",
|
||||
"/I&E:/workdir/./test", "&E:/workdir/bar.cc",
|
||||
"/I&E:/workdir/./test", "E:/workdir/bar.cc",
|
||||
"-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
|
||||
"-fparse-all-comments"});
|
||||
|
||||
@ -696,28 +656,20 @@ TEST_SUITE("Project") {
|
||||
/* expected */
|
||||
{"cl.exe", "-working-directory=E:/workdir",
|
||||
"/I&E:/workdir/../third_party/test/include",
|
||||
"&E:/workdir/bar.cc", "-resource-dir=/w/resource_dir/",
|
||||
"E:/workdir/bar.cc", "-resource-dir=/w/resource_dir/",
|
||||
"-Wno-unknown-warning-option", "-fparse-all-comments"});
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("Path in args") {
|
||||
CheckFlags("/home/user", "/home/user/foo/bar.c",
|
||||
/* raw */ {"cc", "-O0", "foo/bar.c"},
|
||||
/* expected */
|
||||
{"cc", "-working-directory=/home/user", "-O0",
|
||||
"&/home/user/foo/bar.c", "-resource-dir=/w/resource_dir/",
|
||||
"/home/user/foo/bar.c", "-resource-dir=/w/resource_dir/",
|
||||
"-Wno-unknown-warning-option", "-fparse-all-comments"});
|
||||
}
|
||||
|
||||
TEST_CASE("Implied binary") {
|
||||
CheckFlags("/home/user", "/home/user/foo/bar.cc",
|
||||
/* raw */ {"clang", "-DDONT_IGNORE_ME"},
|
||||
/* expected */
|
||||
{"clang", "-working-directory=/home/user", "-DDONT_IGNORE_ME",
|
||||
"-resource-dir=/w/resource_dir/", "-Wno-unknown-warning-option",
|
||||
"-fparse-all-comments"});
|
||||
}
|
||||
|
||||
TEST_CASE("Directory extraction") {
|
||||
Config init_opts;
|
||||
ProjectConfig config;
|
||||
@ -752,11 +704,11 @@ TEST_SUITE("Project") {
|
||||
GetCompilationEntryFromCompileCommandEntry(&init_opts, &config, entry);
|
||||
|
||||
std::unordered_set<std::string> angle_expected{
|
||||
"&/a_absolute1", "&/a_absolute2", "&/base/a_relative1",
|
||||
"&/base/a_relative2"};
|
||||
"/a_absolute1", "/a_absolute2", "/base/a_relative1",
|
||||
"/base/a_relative2"};
|
||||
std::unordered_set<std::string> quote_expected{
|
||||
"&/q_absolute1", "&/q_absolute2", "&/base/q_relative1",
|
||||
"&/base/q_relative2"};
|
||||
"/q_absolute1", "/q_absolute2", "/base/q_relative1",
|
||||
"/base/q_relative2"};
|
||||
REQUIRE(config.angle_dirs == angle_expected);
|
||||
REQUIRE(config.quote_dirs == quote_expected);
|
||||
}
|
||||
@ -817,23 +769,6 @@ TEST_SUITE("Project") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("IsWindowsAbsolutePath works correctly") {
|
||||
REQUIRE(IsWindowsAbsolutePath("C:/Users/projects/"));
|
||||
REQUIRE(IsWindowsAbsolutePath("C:/Users/projects"));
|
||||
REQUIRE(IsWindowsAbsolutePath("C:/Users/projects"));
|
||||
REQUIRE(IsWindowsAbsolutePath("C:\\Users\\projects"));
|
||||
REQUIRE(IsWindowsAbsolutePath("C:\\\\Users\\\\projects"));
|
||||
REQUIRE(IsWindowsAbsolutePath("c:\\\\Users\\\\projects"));
|
||||
REQUIRE(IsWindowsAbsolutePath("A:\\\\Users\\\\projects"));
|
||||
|
||||
REQUIRE(!IsWindowsAbsolutePath("C:/"));
|
||||
REQUIRE(!IsWindowsAbsolutePath("../abc/test"));
|
||||
REQUIRE(!IsWindowsAbsolutePath("5:/test"));
|
||||
REQUIRE(!IsWindowsAbsolutePath("ccls/project/file.cc"));
|
||||
REQUIRE(!IsWindowsAbsolutePath(""));
|
||||
REQUIRE(!IsWindowsAbsolutePath("/etc/linux/path"));
|
||||
}
|
||||
|
||||
TEST_CASE("Entry inference prefers same file endings") {
|
||||
Project p;
|
||||
{
|
||||
|
@ -3,13 +3,12 @@
|
||||
#include "config.h"
|
||||
#include "method.h"
|
||||
|
||||
#include <optional>
|
||||
#include <sparsepp/spp.h>
|
||||
#include <variant>
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
class QueueManager;
|
||||
@ -29,7 +28,7 @@ struct Project {
|
||||
std::vector<std::string> angle_include_directories;
|
||||
|
||||
std::vector<Entry> entries;
|
||||
spp::sparse_hash_map<std::string, int> absolute_path_to_entry_index_;
|
||||
std::unordered_map<std::string, int> absolute_path_to_entry_index_;
|
||||
|
||||
// Loads a project for the given |directory|.
|
||||
//
|
||||
|
@ -270,7 +270,7 @@ struct QueryDatabase {
|
||||
std::vector<QueryVar> vars;
|
||||
|
||||
// Lookup symbol based on a usr.
|
||||
spp::sparse_hash_map<std::string, QueryFileId> usr_to_file;
|
||||
std::unordered_map<std::string, QueryFileId> usr_to_file;
|
||||
spp::sparse_hash_map<Usr, QueryTypeId> usr_to_type;
|
||||
spp::sparse_hash_map<Usr, QueryFuncId> usr_to_func;
|
||||
spp::sparse_hash_map<Usr, QueryVarId> usr_to_var;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
using namespace std::placeholders;
|
||||
|
||||
@ -277,6 +278,13 @@ std::string GetDefaultResourceDirectory() {
|
||||
return NormalizePath(result);
|
||||
}
|
||||
|
||||
void StartThread(const std::string& thread_name, std::function<void()> entry) {
|
||||
new std::thread([thread_name, entry]() {
|
||||
SetCurrentThreadName(thread_name);
|
||||
entry();
|
||||
});
|
||||
}
|
||||
|
||||
TEST_SUITE("StripFileType") {
|
||||
TEST_CASE("all") {
|
||||
REQUIRE(StripFileType("") == "");
|
||||
|
@ -149,3 +149,5 @@ inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
|
||||
}
|
||||
|
||||
std::string GetDefaultResourceDirectory();
|
||||
|
||||
void StartThread(const std::string& thread_name, std::function<void()> entry);
|
||||
|
@ -1,12 +0,0 @@
|
||||
#include "work_thread.h"
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
// static
|
||||
void WorkThread::StartThread(const std::string& thread_name,
|
||||
std::function<void()> entry_point) {
|
||||
new std::thread([thread_name, entry_point]() {
|
||||
SetCurrentThreadName(thread_name);
|
||||
entry_point();
|
||||
});
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
// Helper methods for starting threads that do some work. Enables test code to
|
||||
// wait for all work to complete.
|
||||
struct WorkThread {
|
||||
// Launch a new thread. |entry_point| will be called continously. It should
|
||||
// return true if it there is still known work to be done.
|
||||
static void StartThread(const std::string& thread_name,
|
||||
std::function<void()> entry_point);
|
||||
|
||||
// Static-only class.
|
||||
WorkThread() = delete;
|
||||
};
|
Loading…
Reference in New Issue
Block a user