Simplify pipeline

This commit is contained in:
Fangrui Song 2018-05-27 17:50:02 -07:00
parent 8fabe3d1ae
commit c9f0b65062
61 changed files with 479 additions and 722 deletions

View File

@ -189,11 +189,8 @@ file(GLOB SOURCES src/*.cc src/*.h src/serializers/*.cc src/serializers/*.h
target_sources(ccls PRIVATE third_party/siphash.cc) target_sources(ccls PRIVATE third_party/siphash.cc)
target_sources(ccls PRIVATE target_sources(ccls PRIVATE
src/cache_manager.cc
src/clang_complete.cc src/clang_complete.cc
src/clang_cursor.cc src/clang_tu.cc
src/clang_indexer.cc
src/clang_translation_unit.cc
src/clang_utils.cc src/clang_utils.cc
src/config.cc src/config.cc
src/diagnostics_engine.cc src/diagnostics_engine.cc
@ -202,6 +199,7 @@ target_sources(ccls PRIVATE
src/fuzzy_match.cc src/fuzzy_match.cc
src/main.cc src/main.cc
src/include_complete.cc src/include_complete.cc
src/indexer.cc
src/method.cc src/method.cc
src/language.cc src/language.cc
src/lex_utils.cc src/lex_utils.cc
@ -212,12 +210,10 @@ target_sources(ccls PRIVATE
src/pipeline.cc src/pipeline.cc
src/platform_posix.cc src/platform_posix.cc
src/platform_win.cc src/platform_win.cc
src/port.cc
src/position.cc src/position.cc
src/project.cc src/project.cc
src/query_utils.cc src/query_utils.cc
src/query.cc src/query.cc
src/queue_manager.cc
src/serializer.cc src/serializer.cc
src/test.cc src/test.cc
src/third_party_impl.cc src/third_party_impl.cc

View File

@ -1,62 +0,0 @@
#include "cache_manager.h"
#include "config.h"
#include "indexer.h"
#include "lsp.h"
#include "platform.h"
#include <algorithm>
#include <unordered_map>
namespace {
std::string GetCachePath(const std::string& source_file) {
assert(!g_config->cacheDirectory.empty());
std::string cache_file;
size_t len = g_config->projectRoot.size();
if (StartsWith(source_file, g_config->projectRoot)) {
cache_file = EscapeFileName(g_config->projectRoot) +
EscapeFileName(source_file.substr(len));
} else {
cache_file = '@' + EscapeFileName(g_config->projectRoot) +
EscapeFileName(source_file);
}
return g_config->cacheDirectory + cache_file;
}
std::string AppendSerializationFormat(const std::string& base) {
switch (g_config->cacheFormat) {
case SerializeFormat::Binary:
return base + ".blob";
case SerializeFormat::Json:
return base + ".json";
}
}
}
// Manages loading caches from file paths for the indexer process.
void ICacheManager::WriteToCache(IndexFile& file) {
std::string cache_path = GetCachePath(file.path);
WriteToFile(cache_path, file.file_contents);
std::string indexed_content = Serialize(g_config->cacheFormat, file);
WriteToFile(AppendSerializationFormat(cache_path), indexed_content);
}
std::optional<std::string> ICacheManager::LoadCachedFileContents(
const std::string& path) {
return ReadContent(GetCachePath(path));
}
std::unique_ptr<IndexFile> ICacheManager::RawCacheLoad(
const std::string& path) {
std::string cache_path = GetCachePath(path);
std::optional<std::string> file_content = ReadContent(cache_path);
std::optional<std::string> serialized_indexed_content =
ReadContent(AppendSerializationFormat(cache_path));
if (!file_content || !serialized_indexed_content)
return nullptr;
return Deserialize(g_config->cacheFormat, path, *serialized_indexed_content,
*file_content, IndexFile::kMajorVersion);
}

View File

@ -1,26 +0,0 @@
#pragma once
#include <optional>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
struct IndexFile;
struct ICacheManager {
void WriteToCache(IndexFile& file);
std::optional<std::string> LoadCachedFileContents(const std::string& path);
template <typename Fn>
void IterateLoadedCaches(Fn fn) {
for (const auto& cache : caches_)
fn(cache.second.get());
}
std::unique_ptr<IndexFile> RawCacheLoad(const std::string& path);
std::unordered_map<std::string, std::unique_ptr<IndexFile>> caches_;
};

View File

@ -21,14 +21,8 @@ unsigned Flags() {
CXTranslationUnit_CacheCompletionResults | CXTranslationUnit_CacheCompletionResults |
CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_PrecompiledPreamble |
CXTranslationUnit_IncludeBriefCommentsInCodeCompletion | CXTranslationUnit_IncludeBriefCommentsInCodeCompletion |
CXTranslationUnit_DetailedPreprocessingRecord CXTranslationUnit_DetailedPreprocessingRecord |
#if !defined(_WIN32) CXTranslationUnit_CreatePreambleOnFirstParse;
// For whatever reason, CreatePreambleOnFirstParse causes clang to
// become very crashy on windows.
// TODO: do more investigation, submit fixes to clang.
| CXTranslationUnit_CreatePreambleOnFirstParse
#endif
;
} }
std::string StripFileType(const std::string& path) { std::string StripFileType(const std::string& path) {
@ -57,23 +51,6 @@ unsigned GetCompletionPriority(const CXCompletionString& str,
return priority; return priority;
} }
/*
bool IsCallKind(CXCursorKind kind) {
switch (kind) {
case CXCursor_ObjCInstanceMethodDecl:
case CXCursor_CXXMethod:
case CXCursor_FunctionTemplate:
case CXCursor_FunctionDecl:
case CXCursor_Constructor:
case CXCursor_Destructor:
case CXCursor_ConversionFunction:
return true;
default:
return false;
}
}
*/
lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) { lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
switch (cursor_kind) { switch (cursor_kind) {
case CXCursor_UnexposedDecl: case CXCursor_UnexposedDecl:
@ -383,8 +360,8 @@ void TryEnsureDocumentParsed(ClangCompleteManager* manager,
std::vector<std::string> args = session->file.args; std::vector<std::string> args = session->file.args;
// -fspell-checking enables FixIts for, ie, misspelled types. // -fspell-checking enables FixIts for, ie, misspelled types.
if (!AnyStartsWith(args, "-fno-spell-checking") && if (!std::count(args.begin(), args.end(), "-fno-spell-checking") &&
!AnyStartsWith(args, "-fspell-checking")) { !std::count(args.begin(), args.end(), "-fspell-checking")) {
args.push_back("-fspell-checking"); args.push_back("-fspell-checking");
} }

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "clang_cursor.h" #include "clang_tu.h"
#include "clang_translation_unit.h"
#include "lru_cache.h" #include "lru_cache.h"
#include "lsp_completion.h" #include "lsp_completion.h"
#include "lsp_diagnostic.h" #include "lsp_diagnostic.h"

View File

@ -1,155 +0,0 @@
#include "clang_translation_unit.h"
#include "clang_utils.h"
#include "log.hh"
#include "platform.h"
#include "utils.h"
namespace {
void EmitDiagnostics(std::string path,
std::vector<const char*> args,
CXTranslationUnit tu) {
std::string output = "Fatal errors while trying to parse " + path + "\n";
output +=
"Args: " +
StringJoinMap(args, [](const char* arg) { return std::string(arg); }) +
"\n";
size_t num_diagnostics = clang_getNumDiagnostics(tu);
for (unsigned i = 0; i < num_diagnostics; ++i) {
output += " - ";
CXDiagnostic diagnostic = clang_getDiagnostic(tu, i);
// Location.
CXFile file;
unsigned int line, column;
clang_getSpellingLocation(clang_getDiagnosticLocation(diagnostic), &file,
&line, &column, nullptr);
std::string path = FileName(file);
output += path + ":" + std::to_string(line - 1) + ":" +
std::to_string(column) + " ";
// Severity
switch (clang_getDiagnosticSeverity(diagnostic)) {
case CXDiagnostic_Ignored:
case CXDiagnostic_Note:
output += "[info]";
break;
case CXDiagnostic_Warning:
output += "[warning]";
break;
case CXDiagnostic_Error:
output += "[error]";
break;
case CXDiagnostic_Fatal:
output += "[fatal]";
break;
}
// Content.
output += " " + ToString(clang_getDiagnosticSpelling(diagnostic));
clang_disposeDiagnostic(diagnostic);
output += "\n";
}
LOG_S(WARNING) << output;
}
} // namespace
// static
std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Create(
ClangIndex* index,
const std::string& filepath,
const std::vector<std::string>& arguments,
std::vector<CXUnsavedFile>& unsaved_files,
unsigned flags) {
std::vector<const char*> args;
for (auto& arg : arguments)
args.push_back(arg.c_str());
CXTranslationUnit cx_tu;
CXErrorCode error_code;
{
error_code = clang_parseTranslationUnit2FullArgv(
index->cx_index, nullptr, args.data(), (int)args.size(),
unsaved_files.data(), (unsigned)unsaved_files.size(), flags, &cx_tu);
}
if (error_code != CXError_Success && cx_tu)
EmitDiagnostics(filepath, args, cx_tu);
// We sometimes dump the command to logs and ask the user to run it. Include
// -fsyntax-only so they don't do a full compile.
auto make_msg = [&]() {
return "Please try running the following, identify which flag causes the "
"issue, and report a bug. ccls will then filter the flag for you "
" automatically:\n " +
StringJoin(args, " ") + " -fsyntax-only";
};
switch (error_code) {
case CXError_Success:
return std::make_unique<ClangTranslationUnit>(cx_tu);
case CXError_Failure:
LOG_S(ERROR) << "libclang generic failure for " << filepath << ". "
<< make_msg();
return nullptr;
case CXError_Crashed:
LOG_S(ERROR) << "libclang crashed for " << filepath << ". " << make_msg();
return nullptr;
case CXError_InvalidArguments:
LOG_S(ERROR) << "libclang had invalid arguments for " << filepath << ". "
<< make_msg();
return nullptr;
case CXError_ASTReadError:
LOG_S(ERROR) << "libclang had ast read error for " << filepath << ". "
<< make_msg();
return nullptr;
}
return nullptr;
}
// static
std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Reparse(
std::unique_ptr<ClangTranslationUnit> tu,
std::vector<CXUnsavedFile>& unsaved) {
int error_code;
{
error_code = clang_reparseTranslationUnit(
tu->cx_tu, (unsigned)unsaved.size(), unsaved.data(),
clang_defaultReparseOptions(tu->cx_tu));
}
if (error_code != CXError_Success && tu->cx_tu)
EmitDiagnostics("<unknown>", {}, tu->cx_tu);
switch (error_code) {
case CXError_Success:
return tu;
case CXError_Failure:
LOG_S(ERROR) << "libclang reparse generic failure";
return nullptr;
case CXError_Crashed:
LOG_S(ERROR) << "libclang reparse crashed";
return nullptr;
case CXError_InvalidArguments:
LOG_S(ERROR) << "libclang reparse had invalid arguments";
return nullptr;
case CXError_ASTReadError:
LOG_S(ERROR) << "libclang reparse had ast read error";
return nullptr;
}
return nullptr;
}
ClangTranslationUnit::ClangTranslationUnit(CXTranslationUnit tu) : cx_tu(tu) {}
ClangTranslationUnit::~ClangTranslationUnit() {
clang_disposeTranslationUnit(cx_tu);
}

View File

@ -1,30 +0,0 @@
#pragma once
#include "clang_cursor.h"
#include <clang-c/Index.h>
#include <memory>
#include <string>
#include <vector>
// RAII wrapper around CXTranslationUnit which also makes it much more
// challenging to use a CXTranslationUnit instance that is not correctly
// initialized.
struct ClangTranslationUnit {
static std::unique_ptr<ClangTranslationUnit> Create(
ClangIndex* index,
const std::string& filepath,
const std::vector<std::string>& arguments,
std::vector<CXUnsavedFile>& unsaved_files,
unsigned flags);
static std::unique_ptr<ClangTranslationUnit> Reparse(
std::unique_ptr<ClangTranslationUnit> tu,
std::vector<CXUnsavedFile>& unsaved);
explicit ClangTranslationUnit(CXTranslationUnit tu);
~ClangTranslationUnit();
CXTranslationUnit cx_tu;
};

View File

@ -1,12 +1,70 @@
#include "clang_cursor.h" #include "clang_tu.h"
#include "clang_utils.h" #include "clang_utils.h"
#include "log.hh"
#include "platform.h"
#include "utils.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
#include <mutex> #include <mutex>
namespace {
void EmitDiagnostics(std::string path,
std::vector<const char*> args,
CXTranslationUnit tu) {
std::string output = "Fatal errors while trying to parse " + path + "\n";
output +=
"Args: " +
StringJoinMap(args, [](const char* arg) { return std::string(arg); }) +
"\n";
size_t num_diagnostics = clang_getNumDiagnostics(tu);
for (unsigned i = 0; i < num_diagnostics; ++i) {
output += " - ";
CXDiagnostic diagnostic = clang_getDiagnostic(tu, i);
// Location.
CXFile file;
unsigned int line, column;
clang_getSpellingLocation(clang_getDiagnosticLocation(diagnostic), &file,
&line, &column, nullptr);
std::string path = FileName(file);
output += path + ":" + std::to_string(line - 1) + ":" +
std::to_string(column) + " ";
// Severity
switch (clang_getDiagnosticSeverity(diagnostic)) {
case CXDiagnostic_Ignored:
case CXDiagnostic_Note:
output += "[info]";
break;
case CXDiagnostic_Warning:
output += "[warning]";
break;
case CXDiagnostic_Error:
output += "[error]";
break;
case CXDiagnostic_Fatal:
output += "[fatal]";
break;
}
// Content.
output += " " + ToString(clang_getDiagnosticSpelling(diagnostic));
clang_disposeDiagnostic(diagnostic);
output += "\n";
}
LOG_S(WARNING) << output;
}
} // namespace
Range ResolveCXSourceRange(const CXSourceRange& range, CXFile* cx_file) { Range ResolveCXSourceRange(const CXSourceRange& range, CXFile* cx_file) {
CXSourceLocation start = clang_getRangeStart(range); CXSourceLocation start = clang_getRangeStart(range);
CXSourceLocation end = clang_getRangeEnd(range); CXSourceLocation end = clang_getRangeEnd(range);
@ -284,3 +342,97 @@ ClangIndex::ClangIndex(int exclude_declarations_from_pch,
ClangIndex::~ClangIndex() { ClangIndex::~ClangIndex() {
clang_disposeIndex(cx_index); clang_disposeIndex(cx_index);
} }
// static
std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Create(
ClangIndex* index,
const std::string& filepath,
const std::vector<std::string>& arguments,
std::vector<CXUnsavedFile>& unsaved_files,
unsigned flags) {
std::vector<const char*> args;
for (auto& arg : arguments)
args.push_back(arg.c_str());
CXTranslationUnit cx_tu;
CXErrorCode error_code;
{
error_code = clang_parseTranslationUnit2FullArgv(
index->cx_index, nullptr, args.data(), (int)args.size(),
unsaved_files.data(), (unsigned)unsaved_files.size(), flags, &cx_tu);
}
if (error_code != CXError_Success && cx_tu)
EmitDiagnostics(filepath, args, cx_tu);
// We sometimes dump the command to logs and ask the user to run it. Include
// -fsyntax-only so they don't do a full compile.
auto make_msg = [&]() {
return "Please try running the following, identify which flag causes the "
"issue, and report a bug. ccls will then filter the flag for you "
" automatically:\n " +
StringJoin(args, " ") + " -fsyntax-only";
};
switch (error_code) {
case CXError_Success:
return std::make_unique<ClangTranslationUnit>(cx_tu);
case CXError_Failure:
LOG_S(ERROR) << "libclang generic failure for " << filepath << ". "
<< make_msg();
return nullptr;
case CXError_Crashed:
LOG_S(ERROR) << "libclang crashed for " << filepath << ". " << make_msg();
return nullptr;
case CXError_InvalidArguments:
LOG_S(ERROR) << "libclang had invalid arguments for " << filepath << ". "
<< make_msg();
return nullptr;
case CXError_ASTReadError:
LOG_S(ERROR) << "libclang had ast read error for " << filepath << ". "
<< make_msg();
return nullptr;
}
return nullptr;
}
// static
std::unique_ptr<ClangTranslationUnit> ClangTranslationUnit::Reparse(
std::unique_ptr<ClangTranslationUnit> tu,
std::vector<CXUnsavedFile>& unsaved) {
int error_code;
{
error_code = clang_reparseTranslationUnit(
tu->cx_tu, (unsigned)unsaved.size(), unsaved.data(),
clang_defaultReparseOptions(tu->cx_tu));
}
if (error_code != CXError_Success && tu->cx_tu)
EmitDiagnostics("<unknown>", {}, tu->cx_tu);
switch (error_code) {
case CXError_Success:
return tu;
case CXError_Failure:
LOG_S(ERROR) << "libclang reparse generic failure";
return nullptr;
case CXError_Crashed:
LOG_S(ERROR) << "libclang reparse crashed";
return nullptr;
case CXError_InvalidArguments:
LOG_S(ERROR) << "libclang reparse had invalid arguments";
return nullptr;
case CXError_ASTReadError:
LOG_S(ERROR) << "libclang reparse had ast read error";
return nullptr;
}
return nullptr;
}
ClangTranslationUnit::ClangTranslationUnit(CXTranslationUnit tu) : cx_tu(tu) {}
ClangTranslationUnit::~ClangTranslationUnit() {
clang_disposeTranslationUnit(cx_tu);
}

View File

@ -1,12 +1,10 @@
#pragma once #pragma once
#include "nt_string.h" #include "nt_string.h"
#include "position.h" #include "position.h"
#include <clang-c/Index.h> #include <clang-c/Index.h>
#include <optional>
#include <array> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@ -119,3 +117,24 @@ class ClangIndex {
~ClangIndex(); ~ClangIndex();
CXIndex cx_index; CXIndex cx_index;
}; };
// RAII wrapper around CXTranslationUnit which also makes it much more
// challenging to use a CXTranslationUnit instance that is not correctly
// initialized.
struct ClangTranslationUnit {
static std::unique_ptr<ClangTranslationUnit> Create(
ClangIndex* index,
const std::string& filepath,
const std::vector<std::string>& arguments,
std::vector<CXUnsavedFile>& unsaved_files,
unsigned flags);
static std::unique_ptr<ClangTranslationUnit> Reparse(
std::unique_ptr<ClangTranslationUnit> tu,
std::vector<CXUnsavedFile>& unsaved);
explicit ClangTranslationUnit(CXTranslationUnit tu);
~ClangTranslationUnit();
CXTranslationUnit cx_tu;
};

View File

@ -1,6 +1,7 @@
#include "diagnostics_engine.h" #include "diagnostics_engine.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
#include <chrono> #include <chrono>
@ -30,6 +31,6 @@ void DiagnosticsEngine::Publish(WorkingFiles* working_files,
Out_TextDocumentPublishDiagnostics out; Out_TextDocumentPublishDiagnostics out;
out.params.uri = lsDocumentUri::FromPath(path); out.params.uri = lsDocumentUri::FromPath(path);
out.params.diagnostics = diagnostics; out.params.diagnostics = diagnostics;
QueueManager::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, out); pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, out);
} }
} }

View File

@ -107,7 +107,7 @@ void IncludeComplete::Rescan() {
is_scanning = true; is_scanning = true;
std::thread([this]() { std::thread([this]() {
set_thread_name("scan_includes"); set_thread_name("include");
Timer timer; Timer timer;
for (const std::string& dir : project_->quote_include_directories) for (const std::string& dir : project_->quote_include_directories)

View File

@ -1,7 +1,5 @@
#include "indexer.h" #include "indexer.h"
#include "clang_cursor.h"
#include "clang_utils.h"
#include "log.hh" #include "log.hh"
#include "platform.h" #include "platform.h"
#include "serializer.h" #include "serializer.h"

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "clang_cursor.h" #include "clang_tu.h"
#include "clang_translation_unit.h"
#include "clang_utils.h" #include "clang_utils.h"
#include "file_consumer.h" #include "file_consumer.h"
#include "language.h" #include "language.h"

View File

@ -5,6 +5,7 @@
#include "serializers/json.h" #include "serializers/json.h"
#include "test.h" #include "test.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
#include <llvm/Support/CommandLine.h> #include <llvm/Support/CommandLine.h>
#include <llvm/Support/Process.h> #include <llvm/Support/Process.h>
@ -56,8 +57,7 @@ int main(int argc, char** argv) {
return 0; return 0;
} }
MultiQueueWaiter querydb_waiter, indexer_waiter, stdout_waiter; pipeline::Init();
QueueManager::Init(&querydb_waiter, &indexer_waiter, &stdout_waiter);
#ifdef _WIN32 #ifdef _WIN32
// We need to write to stdout in binary mode because in Windows, writing // We need to write to stdout in binary mode because in Windows, writing
@ -132,11 +132,11 @@ int main(int argc, char** argv) {
std::unordered_map<MethodType, Timer> request_times; std::unordered_map<MethodType, Timer> request_times;
// The thread that reads from stdin and dispatchs commands to the main thread. // The thread that reads from stdin and dispatchs commands to the main thread.
LaunchStdinLoop(&request_times); pipeline::LaunchStdin(&request_times);
// The thread that writes responses from the main thread to stdout. // The thread that writes responses from the main thread to stdout.
LaunchStdoutThread(&request_times, &stdout_waiter); pipeline::LaunchStdout(&request_times);
// Main thread which also spawns indexer threads upon the "initialize" request. // Main thread which also spawns indexer threads upon the "initialize" request.
MainLoop(&querydb_waiter, &indexer_waiter); pipeline::MainLoop();
} }
return 0; return 0;

View File

@ -1,7 +1,8 @@
#include "match.h" #include "match.h"
#include "lsp.h" #include "lsp.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
#include <doctest/doctest.h> #include <doctest/doctest.h>
@ -32,7 +33,7 @@ std::optional<Matcher> Matcher::Create(const std::string& search) {
out.params.type = lsMessageType::Error; out.params.type = lsMessageType::Error;
out.params.message = "ccls: Parsing EMCAScript regex \"" + search + out.params.message = "ccls: Parsing EMCAScript regex \"" + search +
"\" failed; " + e.what(); "\" failed; " + e.what();
QueueManager::WriteStdout(kMethodType_Unknown, out); pipeline::WriteStdout(kMethodType_Unknown, out);
return std::nullopt; return std::nullopt;
} }
} }

View File

@ -4,7 +4,8 @@
#include "log.hh" #include "log.hh"
#include "project.h" #include "project.h"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
#include <algorithm> #include <algorithm>
@ -167,7 +168,7 @@ bool FindFileOrFail(QueryDatabase* db,
out.error.code = lsErrorCodes::InternalError; out.error.code = lsErrorCodes::InternalError;
out.error.message = "Unable to find file " + absolute_path; out.error.message = "Unable to find file " + absolute_path;
} }
QueueManager::WriteStdout(kMethodType_Unknown, out); pipeline::WriteStdout(kMethodType_Unknown, out);
} }
return false; return false;
@ -182,7 +183,7 @@ void EmitInactiveLines(WorkingFile* working_file,
if (ls_skipped) if (ls_skipped)
out.params.inactiveRegions.push_back(*ls_skipped); out.params.inactiveRegions.push_back(*ls_skipped);
} }
QueueManager::WriteStdout(kMethodType_CclsPublishInactiveRegions, out); pipeline::WriteStdout(kMethodType_CclsPublishInactiveRegions, out);
} }
void EmitSemanticHighlighting(QueryDatabase* db, void EmitSemanticHighlighting(QueryDatabase* db,
@ -343,5 +344,5 @@ void EmitSemanticHighlighting(QueryDatabase* db,
for (auto& entry : grouped_symbols) for (auto& entry : grouped_symbols)
if (entry.second.ranges.size()) if (entry.second.ranges.size())
out.params.symbols.push_back(entry.second); out.params.symbols.push_back(entry.second);
QueueManager::WriteStdout(kMethodType_CclsPublishSemanticHighlighting, out); pipeline::WriteStdout(kMethodType_CclsPublishSemanticHighlighting, out);
} }

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" using namespace ccls;
namespace { namespace {
@ -43,7 +44,7 @@ struct Handler_CclsBase : BaseMessageHandler<In_CclsBase> {
break; break;
} }
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsBase); REGISTER_MESSAGE_HANDLER(Handler_CclsBase);

View File

@ -1,6 +1,8 @@
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
using namespace ccls;
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" using namespace ccls;
#include <unordered_set> #include <unordered_set>
@ -225,7 +227,7 @@ struct Handler_CclsCallHierarchy
} }
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsCallHierarchy); REGISTER_MESSAGE_HANDLER(Handler_CclsCallHierarchy);

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" using namespace ccls;
namespace { namespace {
MethodType kMethodType = "$ccls/callers"; MethodType kMethodType = "$ccls/callers";
@ -39,7 +40,7 @@ struct Handler_CclsCallers : BaseMessageHandler<In_CclsCallers> {
break; break;
} }
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsCallers); REGISTER_MESSAGE_HANDLER(Handler_CclsCallers);

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" using namespace ccls;
MAKE_REFLECT_STRUCT(QueryFile::Def, MAKE_REFLECT_STRUCT(QueryFile::Def,
path, path,
@ -49,7 +50,7 @@ struct Handler_CclsFileInfo : BaseMessageHandler<In_CclsFileInfo> {
out.result.language = file->def->language; out.result.language = file->def->language;
out.result.includes = file->def->includes; out.result.includes = file->def->includes;
out.result.inactive_regions = file->def->inactive_regions; out.result.inactive_regions = file->def->inactive_regions;
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsFileInfo); REGISTER_MESSAGE_HANDLER(Handler_CclsFileInfo);

View File

@ -1,12 +1,11 @@
#include "cache_manager.h"
#include "match.h" #include "match.h"
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "platform.h" #include "platform.h"
#include "project.h" #include "project.h"
#include "queue_manager.h" #include "pipeline.hh"
#include "timer.h" #include "timer.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
#include <queue> #include <queue>
#include <unordered_set> #include <unordered_set>
@ -79,7 +78,7 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
} }
// Send index requests for every file. // Send index requests for every file.
project->Index(QueueManager::instance(), working_files, lsRequestId()); project->Index(working_files, lsRequestId());
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsFreshenIndex); REGISTER_MESSAGE_HANDLER(Handler_CclsFreshenIndex);

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
#include <unordered_set> #include <unordered_set>
@ -95,7 +96,7 @@ bool ExpandHelper(MessageHandler* m,
if (derived) { if (derived) {
if (levels > 0) { if (levels > 0) {
for (auto usr : entity.derived) { for (auto usr : entity.derived) {
if (seen.insert(usr).second) if (!seen.insert(usr).second)
continue; continue;
Out_CclsInheritanceHierarchy::Entry entry1; Out_CclsInheritanceHierarchy::Entry entry1;
entry1.id = std::to_string(usr); entry1.id = std::to_string(usr);
@ -110,7 +111,7 @@ bool ExpandHelper(MessageHandler* m,
} else { } else {
if (levels > 0) { if (levels > 0) {
for (auto usr : def->bases) { for (auto usr : def->bases) {
if (seen.insert(usr).second) if (!seen.insert(usr).second)
continue; continue;
Out_CclsInheritanceHierarchy::Entry entry1; Out_CclsInheritanceHierarchy::Entry entry1;
entry1.id = std::to_string(usr); entry1.id = std::to_string(usr);
@ -180,17 +181,15 @@ struct Handler_CclsInheritanceHierarchy
WorkingFile* wfile = WorkingFile* wfile =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
for (SymbolRef sym : for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position))
FindSymbolsAtLocation(wfile, file, params.position)) {
if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) { if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) {
out.result = BuildInitial(sym, params.derived, params.qualified, out.result = BuildInitial(sym, params.derived, params.qualified,
params.levels); params.levels);
break; break;
} }
} }
}
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsInheritanceHierarchy); REGISTER_MESSAGE_HANDLER(Handler_CclsInheritanceHierarchy);

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" using namespace ccls;
#include <unordered_set> #include <unordered_set>
@ -264,7 +265,7 @@ struct Handler_CclsMemberHierarchy
} }
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsMemberHierarchy); REGISTER_MESSAGE_HANDLER(Handler_CclsMemberHierarchy);

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
@ -126,7 +127,7 @@ struct Handler_CclsRandom : BaseMessageHandler<In_CclsRandom> {
break; break;
} }
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsRandom); REGISTER_MESSAGE_HANDLER(Handler_CclsRandom);

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "$ccls/vars"; MethodType kMethodType = "$ccls/vars";
@ -48,7 +49,7 @@ struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> {
break; break;
} }
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsVars); REGISTER_MESSAGE_HANDLER(Handler_CclsVars);

View File

@ -1,4 +1,3 @@
#include "cache_manager.h"
#include "diagnostics_engine.h" #include "diagnostics_engine.h"
#include "filesystem.hh" #include "filesystem.hh"
#include "include_complete.h" #include "include_complete.h"
@ -7,10 +6,10 @@
#include "pipeline.hh" #include "pipeline.hh"
#include "platform.h" #include "platform.h"
#include "project.h" #include "project.h"
#include "queue_manager.h"
#include "serializers/json.h" #include "serializers/json.h"
#include "timer.h" #include "timer.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
#include <llvm/ADT/Twine.h> #include <llvm/ADT/Twine.h>
#include <llvm/Support/Threading.h> #include <llvm/Support/Threading.h>
@ -482,7 +481,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
Out_InitializeResponse out; Out_InitializeResponse out;
out.id = request->id; out.id = request->id;
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
// Set project root. // Set project root.
EnsureEndsInSlash(project_path); EnsureEndsInSlash(project_path);
@ -515,7 +514,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());
Indexer_Main(diag_engine, vfs, project, working_files, waiter); pipeline::Indexer_Main(diag_engine, vfs, project, working_files);
}).detach(); }).detach();
} }
@ -524,7 +523,7 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
include_complete->Rescan(); include_complete->Rescan();
time.Reset(); time.Reset();
project->Index(QueueManager::instance(), working_files, request->id); project->Index(working_files, request->id);
// We need to support multiple concurrent index processes. // We need to support multiple concurrent index processes.
time.ResetAndPrint("[perf] Dispatched initial index requests"); time.ResetAndPrint("[perf] Dispatched initial index requests");
} }

View File

@ -1,5 +1,6 @@
#include "message_handler.h" #include "message_handler.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "shutdown"; MethodType kMethodType = "shutdown";
@ -21,7 +22,7 @@ struct Handler_Shutdown : BaseMessageHandler<In_Shutdown> {
void Run(In_Shutdown* request) override { void Run(In_Shutdown* request) override {
Out_Shutdown out; Out_Shutdown out;
out.id = request->id; out.id = request->id;
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_Shutdown); REGISTER_MESSAGE_HANDLER(Handler_Shutdown);

View File

@ -2,7 +2,8 @@
#include "lsp_code_action.h" #include "lsp_code_action.h"
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/codeLens"; MethodType kMethodType = "textDocument/codeLens";
@ -225,7 +226,7 @@ struct Handler_TextDocumentCodeLens
}; };
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens);

View File

@ -2,9 +2,10 @@
#include "fuzzy_match.h" #include "fuzzy_match.h"
#include "include_complete.h" #include "include_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "queue_manager.h" #include "pipeline.hh"
#include "timer.h" #include "timer.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
#include "lex_utils.h" #include "lex_utils.h"
@ -270,7 +271,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
auto write_empty_result = [request]() { auto write_empty_result = [request]() {
Out_TextDocumentComplete out; Out_TextDocumentComplete out;
out.id = request->id; out.id = request->id;
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
}; };
std::string path = request->params.textDocument.uri.GetPath(); std::string path = request->params.textDocument.uri.GetPath();
@ -377,7 +378,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
item.textEdit->range.end.character = (int)buffer_line.size(); item.textEdit->range.end.character = (int)buffer_line.size();
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} else { } else {
ClangCompleteManager::OnComplete callback = std::bind( ClangCompleteManager::OnComplete callback = std::bind(
[this, request, is_global_completion, existing_completion, [this, request, is_global_completion, existing_completion,
@ -389,7 +390,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
// Emit completion results. // Emit completion results.
FilterAndSortCompletionResponse(&out, existing_completion, has_open_paren); FilterAndSortCompletionResponse(&out, existing_completion, has_open_paren);
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
// Cache completion results. // Cache completion results.
if (!is_cached_result) { if (!is_cached_result) {

View File

@ -1,7 +1,8 @@
#include "lex_utils.h" #include "lex_utils.h"
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" using namespace ccls;
#include <ctype.h> #include <ctype.h>
#include <limits.h> #include <limits.h>
@ -173,7 +174,7 @@ struct Handler_TextDocumentDefinition
} }
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDefinition); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDefinition);

View File

@ -1,9 +1,9 @@
#include "cache_manager.h"
#include "clang_complete.h" #include "clang_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "project.h" #include "project.h"
#include "working_files.h" #include "working_files.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/didChange"; MethodType kMethodType = "textDocument/didChange";
@ -25,9 +25,7 @@ struct Handler_TextDocumentDidChange
working_files->OnChange(request->params); working_files->OnChange(request->params);
if (g_config->index.onDidChange) { if (g_config->index.onDidChange) {
Project::Entry entry = project->FindCompilationEntryForFile(path); Project::Entry entry = project->FindCompilationEntryForFile(path);
QueueManager::instance()->index_request.PushBack( pipeline::Index(entry.filename, entry.args, true);
Index_Request(entry.filename, entry.args, true /*is_interactive*/),
true);
} }
clang_complete->NotifyEdit(path); clang_complete->NotifyEdit(path);
clang_complete->DiagnosticsUpdate( clang_complete->DiagnosticsUpdate(

View File

@ -1,7 +1,8 @@
#include "clang_complete.h" #include "clang_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "queue_manager.h" #include "pipeline.hh"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/didClose"; MethodType kMethodType = "textDocument/didClose";
@ -27,7 +28,7 @@ struct Handler_TextDocumentDidClose
// Clear any diagnostics for the file. // Clear any diagnostics for the file.
Out_TextDocumentPublishDiagnostics out; Out_TextDocumentPublishDiagnostics out;
out.params.uri = request->params.textDocument.uri; out.params.uri = request->params.textDocument.uri;
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
// Remove internal state. // Remove internal state.
working_files->OnClose(request->params.textDocument); working_files->OnClose(request->params.textDocument);

View File

@ -1,9 +1,9 @@
#include "cache_manager.h"
#include "clang_complete.h" #include "clang_complete.h"
#include "include_complete.h" #include "include_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "project.h" #include "project.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
#include "timer.h" #include "timer.h"
#include "working_files.h" #include "working_files.h"
@ -38,11 +38,9 @@ struct Handler_TextDocumentDidOpen
const auto& params = request->params; const auto& params = request->params;
std::string path = params.textDocument.uri.GetPath(); std::string path = params.textDocument.uri.GetPath();
ICacheManager cache;
WorkingFile* working_file = working_files->OnOpen(params.textDocument); WorkingFile* working_file = working_files->OnOpen(params.textDocument);
std::optional<std::string> cached_file_contents = if (std::optional<std::string> cached_file_contents =
cache.LoadCachedFileContents(path); pipeline::LoadCachedFileContents(path))
if (cached_file_contents)
working_file->SetIndexContent(*cached_file_contents); working_file->SetIndexContent(*cached_file_contents);
QueryFile* file = nullptr; QueryFile* file = nullptr;
@ -60,11 +58,8 @@ struct Handler_TextDocumentDidOpen
// Submit new index request if it is not a header file. // Submit new index request if it is not a header file.
if (SourceFileLanguage(path) != LanguageId::Unknown) { if (SourceFileLanguage(path) != LanguageId::Unknown) {
Project::Entry entry = project->FindCompilationEntryForFile(path); Project::Entry entry = project->FindCompilationEntryForFile(path);
QueueManager::instance()->index_request.PushBack( pipeline::Index(entry.filename,
Index_Request(entry.filename, params.args.size() ? params.args : entry.args, true);
params.args.size() ? params.args : entry.args,
true /*is_interactive*/),
true /* priority */);
clang_complete->FlushSession(entry.filename); clang_complete->FlushSession(entry.filename);
} }

View File

@ -1,8 +1,8 @@
#include "cache_manager.h"
#include "clang_complete.h" #include "clang_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "project.h" #include "project.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/didSave"; MethodType kMethodType = "textDocument/didSave";
@ -29,7 +29,8 @@ struct Handler_TextDocumentDidSave
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentDidSave* request) override { void Run(In_TextDocumentDidSave* request) override {
std::string path = request->params.textDocument.uri.GetPath(); const auto& params = request->params;
std::string path = params.textDocument.uri.GetPath();
// Send out an index request, and copy the current buffer state so we // Send out an index request, and copy the current buffer state so we
// can update the cached index contents when the index is done. // can update the cached index contents when the index is done.
@ -47,9 +48,7 @@ struct Handler_TextDocumentDidSave
// TODO: send as priority request // TODO: send as priority request
if (!g_config->index.onDidChange) { if (!g_config->index.onDidChange) {
Project::Entry entry = project->FindCompilationEntryForFile(path); Project::Entry entry = project->FindCompilationEntryForFile(path);
QueueManager::instance()->index_request.PushBack( pipeline::Index(entry.filename, entry.args, true);
Index_Request(entry.filename, entry.args, true /*is_interactive*/),
true);
} }
clang_complete->NotifySave(path); clang_complete->NotifySave(path);

View File

@ -1,7 +1,8 @@
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h"
#include "symbol.h" #include "symbol.h"
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/documentHighlight"; MethodType kMethodType = "textDocument/documentHighlight";
@ -61,7 +62,7 @@ struct Handler_TextDocumentDocumentHighlight
break; break;
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight);

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/documentSymbol"; MethodType kMethodType = "textDocument/documentSymbol";
@ -64,7 +65,7 @@ struct Handler_TextDocumentDocumentSymbol
} }
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentSymbol); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentSymbol);

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/hover"; MethodType kMethodType = "textDocument/hover";
@ -99,7 +100,7 @@ struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
} }
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentHover); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentHover);

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/implementation"; MethodType kMethodType = "textDocument/implementation";
@ -41,7 +42,7 @@ struct Handler_TextDocumentImplementation
break; break;
} }
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation);

View File

@ -1,7 +1,8 @@
#include "clang_format.h" #include "clang_format.h"
#include "lex_utils.h" #include "lex_utils.h"
#include "message_handler.h" #include "message_handler.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
#include "working_files.h" #include "working_files.h"
#include <loguru.hpp> #include <loguru.hpp>
@ -64,7 +65,7 @@ struct Handler_TextDocumentRangeFormatting
response.result = {}; response.result = {};
#endif #endif
QueueManager::WriteStdout(kMethodType, response); pipeline::WriteStdout(kMethodType, response);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRangeFormatting); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRangeFormatting);

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" using namespace ccls;
#include <unordered_set> #include <unordered_set>
@ -135,7 +136,7 @@ struct Handler_TextDocumentReferences
if ((int)out.result.size() >= g_config->xref.maxNum) if ((int)out.result.size() >= g_config->xref.maxNum)
out.result.resize(g_config->xref.maxNum); out.result.resize(g_config->xref.maxNum);
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentReferences); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentReferences);

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/rename"; MethodType kMethodType = "textDocument/rename";
@ -102,7 +103,7 @@ struct Handler_TextDocumentRename : BaseMessageHandler<In_TextDocumentRename> {
break; break;
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRename); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRename);

View File

@ -1,6 +1,7 @@
#include "clang_complete.h" #include "clang_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
#include "timer.h" #include "timer.h"
#include <stdint.h> #include <stdint.h>
@ -142,7 +143,7 @@ struct Handler_TextDocumentSignatureHelp : MessageHandler {
out.result.activeParameter = active_param; out.result.activeParameter = active_param;
Timer timer; Timer timer;
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
if (!is_cached_result) { if (!is_cached_result) {
signature_cache->WithLock([&]() { signature_cache->WithLock([&]() {

View File

@ -1,6 +1,7 @@
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/typeDefinition"; MethodType kMethodType = "textDocument/typeDefinition";
@ -60,7 +61,7 @@ struct Handler_TextDocumentTypeDefinition
} }
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentTypeDefinition); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentTypeDefinition);

View File

@ -1,8 +1,8 @@
#include "cache_manager.h"
#include "clang_complete.h" #include "clang_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "project.h" #include "project.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
#include "timer.h" #include "timer.h"
#include "working_files.h" #include "working_files.h"
@ -31,7 +31,7 @@ struct Handler_WorkspaceDidChangeConfiguration
std::to_string(project->entries.size()) + " files)"); std::to_string(project->entries.size()) + " files)");
time.Reset(); time.Reset();
project->Index(QueueManager::instance(), working_files, lsRequestId()); project->Index(working_files, lsRequestId());
time.ResetAndPrint( time.ResetAndPrint(
"[perf] Dispatched workspace/didChangeConfiguration index requests"); "[perf] Dispatched workspace/didChangeConfiguration index requests");

View File

@ -1,9 +1,9 @@
#include "cache_manager.h"
#include "clang_complete.h" #include "clang_complete.h"
#include "message_handler.h" #include "message_handler.h"
#include "project.h" #include "project.h"
#include "queue_manager.h" #include "pipeline.hh"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "workspace/didChangeWatchedFiles"; MethodType kMethodType = "workspace/didChangeWatchedFiles";
@ -52,15 +52,13 @@ struct Handler_WorkspaceDidChangeWatchedFiles
switch (event.type) { switch (event.type) {
case lsFileChangeType::Created: case lsFileChangeType::Created:
case lsFileChangeType::Changed: { case lsFileChangeType::Changed: {
QueueManager::instance()->index_request.PushBack( pipeline::Index(path, entry.args, is_interactive);
Index_Request(path, entry.args, is_interactive));
if (is_interactive) if (is_interactive)
clang_complete->NotifySave(path); clang_complete->NotifySave(path);
break; break;
} }
case lsFileChangeType::Deleted: case lsFileChangeType::Deleted:
QueueManager::instance()->index_request.PushBack( pipeline::Index(path, entry.args, is_interactive);
Index_Request(path, entry.args, is_interactive));
break; break;
} }
} }

View File

@ -1,7 +1,8 @@
#include "lsp_code_action.h" #include "lsp_code_action.h"
#include "message_handler.h" #include "message_handler.h"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" #include "pipeline.hh"
using namespace ccls;
namespace { namespace {
MethodType kMethodType = "workspace/executeCommand"; MethodType kMethodType = "workspace/executeCommand";
@ -34,7 +35,7 @@ struct Handler_WorkspaceExecuteCommand
out.result = params.arguments.locations; out.result = params.arguments.locations;
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceExecuteCommand); REGISTER_MESSAGE_HANDLER(Handler_WorkspaceExecuteCommand);

View File

@ -1,8 +1,9 @@
#include "fuzzy_match.h" #include "fuzzy_match.h"
#include "lex_utils.h" #include "lex_utils.h"
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" using namespace ccls;
#include <ctype.h> #include <ctype.h>
#include <limits.h> #include <limits.h>
@ -124,7 +125,7 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
out.result.push_back(std::get<0>(entry)); out.result.push_back(std::get<0>(entry));
} }
QueueManager::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceSymbol); REGISTER_MESSAGE_HANDLER(Handler_WorkspaceSymbol);

View File

@ -1,6 +1,5 @@
#include "pipeline.hh" #include "pipeline.hh"
#include "cache_manager.h"
#include "clang_complete.h" #include "clang_complete.h"
#include "config.h" #include "config.h"
#include "diagnostics_engine.h" #include "diagnostics_engine.h"
@ -11,18 +10,43 @@
#include "platform.h" #include "platform.h"
#include "project.h" #include "project.h"
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" #include "pipeline.hh"
#include "timer.h" #include "timer.h"
#include <llvm/ADT/Twine.h> #include <llvm/ADT/Twine.h>
#include <llvm/Support/Threading.h> #include <llvm/Support/Threading.h>
using namespace llvm; using namespace llvm;
#include <chrono>
#include <thread> #include <thread>
struct Index_Request {
std::string path;
std::vector<std::string> args;
bool is_interactive;
lsRequestId id;
};
struct Index_OnIndexed {
IndexUpdate update;
PerformanceImportFile perf;
};
struct Stdout_Request {
MethodType method;
std::string content;
};
namespace ccls::pipeline {
namespace { namespace {
MultiQueueWaiter* main_waiter;
MultiQueueWaiter* indexer_waiter;
MultiQueueWaiter* stdout_waiter;
ThreadedQueue<std::unique_ptr<InMessage>>* on_request;
ThreadedQueue<Index_Request>* index_request;
ThreadedQueue<Index_OnIndexed>* on_indexed;
ThreadedQueue<Stdout_Request>* for_stdout;
// Checks if |path| needs to be reparsed. This will modify cached state // Checks if |path| needs to be reparsed. This will modify cached state
// such that calling this function twice with the same path may return true // such that calling this function twice with the same path may return true
// the first time but will return false the second. // the first time but will return false the second.
@ -64,24 +88,57 @@ bool FileNeedsParse(int64_t write_time,
return false; return false;
}; };
std::string AppendSerializationFormat(const std::string& base) {
switch (g_config->cacheFormat) {
case SerializeFormat::Binary:
return base + ".blob";
case SerializeFormat::Json:
return base + ".json";
}
}
std::string GetCachePath(const std::string& source_file) {
std::string cache_file;
size_t len = g_config->projectRoot.size();
if (StartsWith(source_file, g_config->projectRoot)) {
cache_file = EscapeFileName(g_config->projectRoot) +
EscapeFileName(source_file.substr(len));
} else {
cache_file = '@' + EscapeFileName(g_config->projectRoot) +
EscapeFileName(source_file);
}
return g_config->cacheDirectory + cache_file;
}
std::unique_ptr<IndexFile> RawCacheLoad(
const std::string& path) {
std::string cache_path = GetCachePath(path);
std::optional<std::string> file_content = ReadContent(cache_path);
std::optional<std::string> serialized_indexed_content =
ReadContent(AppendSerializationFormat(cache_path));
if (!file_content || !serialized_indexed_content)
return nullptr;
return Deserialize(g_config->cacheFormat, path, *serialized_indexed_content,
*file_content, IndexFile::kMajorVersion);
}
bool Indexer_Parse(DiagnosticsEngine* diag_engine, bool Indexer_Parse(DiagnosticsEngine* diag_engine,
WorkingFiles* working_files, WorkingFiles* working_files,
Project* project, Project* project,
VFS* vfs, VFS* vfs,
ClangIndexer* indexer) { ClangIndexer* indexer) {
auto* queue = QueueManager::instance(); std::optional<Index_Request> opt_request = index_request->TryPopFront();
std::optional<Index_Request> opt_request = queue->index_request.TryPopFront();
if (!opt_request) if (!opt_request)
return false; return false;
auto& request = *opt_request; auto& request = *opt_request;
ICacheManager cache;
// Dummy one to trigger refresh semantic highlight. // Dummy one to trigger refresh semantic highlight.
if (request.path.empty()) { if (request.path.empty()) {
IndexUpdate dummy; IndexUpdate dummy;
dummy.refresh = true; dummy.refresh = true;
queue->on_indexed.PushBack( on_indexed->PushBack({std::move(dummy), PerformanceImportFile()}, false);
Index_OnIndexed(std::move(dummy), PerformanceImportFile()), false);
return false; return false;
} }
@ -108,7 +165,7 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
return true; return true;
int reparse; // request.is_interactive; int reparse; // request.is_interactive;
prev = cache.RawCacheLoad(path_to_index); prev = RawCacheLoad(path_to_index);
if (!prev) if (!prev)
reparse = 2; reparse = 2;
else { else {
@ -132,15 +189,13 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
auto dependencies = prev->dependencies; auto dependencies = prev->dependencies;
if (reparse) { if (reparse) {
IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get()); IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get());
queue->on_indexed.PushBack(Index_OnIndexed(std::move(update), perf), on_indexed->PushBack({std::move(update), perf}, request.is_interactive);
request.is_interactive);
} }
for (const auto& dep : dependencies) for (const auto& dep : dependencies)
if (vfs->Mark(dep.first().str(), 0, 2)) { if (vfs->Mark(dep.first().str(), 0, 2)) {
prev = cache.RawCacheLoad(dep.first().str()); prev = RawCacheLoad(dep.first().str());
IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get()); IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get());
queue->on_indexed.PushBack(Index_OnIndexed(std::move(update), perf), on_indexed->PushBack({std::move(update), perf}, request.is_interactive);
request.is_interactive);
} }
std::lock_guard<std::mutex> lock(vfs->mutex); std::lock_guard<std::mutex> lock(vfs->mutex);
@ -152,7 +207,6 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
LOG_S(INFO) << "parse " << path_to_index; LOG_S(INFO) << "parse " << path_to_index;
std::vector<Index_OnIdMapped> result;
PerformanceImportFile perf; PerformanceImportFile perf;
auto indexes = indexer->Index(vfs, path_to_index, entry.args, {}, &perf); auto indexes = indexer->Index(vfs, path_to_index, entry.args, {}, &perf);
@ -162,7 +216,7 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
out.id = request.id; out.id = request.id;
out.error.code = lsErrorCodes::InternalError; out.error.code = lsErrorCodes::InternalError;
out.error.message = "Failed to index " + path_to_index; out.error.message = "Failed to index " + path_to_index;
QueueManager::WriteStdout(kMethodType_Unknown, out); pipeline::WriteStdout(kMethodType_Unknown, out);
} }
vfs->Reset(path_to_index); vfs->Reset(path_to_index);
return true; return true;
@ -179,12 +233,17 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
if (!(vfs->Stamp(path, curr->last_write_time) || path == path_to_index)) if (!(vfs->Stamp(path, curr->last_write_time) || path == path_to_index))
continue; continue;
LOG_S(INFO) << "emit index for " << path; LOG_S(INFO) << "emit index for " << path;
prev = cache.RawCacheLoad(path); prev = RawCacheLoad(path);
// Write current index to disk if requested. // Write current index to disk if requested.
LOG_S(INFO) << "store index for " << path; LOG_S(INFO) << "store index for " << path;
Timer time; Timer time;
cache.WriteToCache(*curr); {
std::string cache_path = GetCachePath(path);
WriteToFile(cache_path, curr->file_contents);
WriteToFile(AppendSerializationFormat(cache_path),
Serialize(g_config->cacheFormat, *curr));
}
perf.index_save_to_disk = time.ElapsedMicrosecondsAndReset(); perf.index_save_to_disk = time.ElapsedMicrosecondsAndReset();
vfs->Reset(path_to_index); vfs->Reset(path_to_index);
@ -199,8 +258,7 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
perf.index_make_delta = time.ElapsedMicrosecondsAndReset(); perf.index_make_delta = time.ElapsedMicrosecondsAndReset();
LOG_S(INFO) << "built index for " << path << " (is_delta=" << !!prev << ")"; LOG_S(INFO) << "built index for " << path << " (is_delta=" << !!prev << ")";
Index_OnIndexed reply(std::move(update), perf); on_indexed->PushBack({std::move(update), perf}, request.is_interactive);
queue->on_indexed.PushBack(std::move(reply), request.is_interactive);
} }
return true; return true;
@ -217,26 +275,34 @@ bool ShouldDisplayMethodTiming(MethodType type) {
} // namespace } // namespace
void Init() {
main_waiter = new MultiQueueWaiter;
on_request = new ThreadedQueue<std::unique_ptr<InMessage>>(main_waiter);
on_indexed = new ThreadedQueue<Index_OnIndexed>(main_waiter);
indexer_waiter = new MultiQueueWaiter;
index_request = new ThreadedQueue<Index_Request>(indexer_waiter);
stdout_waiter = new MultiQueueWaiter;
for_stdout = new ThreadedQueue<Stdout_Request>(stdout_waiter);
}
void Indexer_Main(DiagnosticsEngine* diag_engine, void Indexer_Main(DiagnosticsEngine* diag_engine,
VFS* vfs, VFS* vfs,
Project* project, Project* project,
WorkingFiles* working_files, WorkingFiles* working_files) {
MultiQueueWaiter* waiter) {
auto* queue = QueueManager::instance();
// Build one index per-indexer, as building the index acquires a global lock. // Build one index per-indexer, as building the index acquires a global lock.
ClangIndexer indexer; ClangIndexer indexer;
while (true) while (true)
if (!Indexer_Parse(diag_engine, working_files, project, vfs, &indexer)) if (!Indexer_Parse(diag_engine, working_files, project, vfs, &indexer))
waiter->Wait(&queue->index_request); indexer_waiter->Wait(index_request);
} }
void QueryDb_OnIndexed(QueueManager* queue, void Main_OnIndexed(QueryDatabase* db,
QueryDatabase* db,
SemanticHighlightSymbolCache* semantic_cache, SemanticHighlightSymbolCache* semantic_cache,
WorkingFiles* working_files, WorkingFiles* working_files,
Index_OnIndexed* response) { Index_OnIndexed* response) {
if (response->update.refresh) { if (response->update.refresh) {
LOG_S(INFO) << "Loaded project. Refresh semantic highlight for all working file."; LOG_S(INFO) << "Loaded project. Refresh semantic highlight for all working file.";
std::lock_guard<std::mutex> lock(working_files->files_mutex); std::lock_guard<std::mutex> lock(working_files->files_mutex);
@ -257,9 +323,8 @@ void QueryDb_OnIndexed(QueueManager* queue,
if (response->update.files_def_update) { if (response->update.files_def_update) {
auto& update = *response->update.files_def_update; auto& update = *response->update.files_def_update;
time.ResetAndPrint("apply index for " + update.value.path); time.ResetAndPrint("apply index for " + update.value.path);
WorkingFile* working_file = if (WorkingFile* working_file =
working_files->GetFileByFilename(update.value.path); working_files->GetFileByFilename(update.value.path)) {
if (working_file) {
// Update indexed content. // Update indexed content.
working_file->SetIndexContent(update.file_content); working_file->SetIndexContent(update.file_content);
@ -275,10 +340,9 @@ void QueryDb_OnIndexed(QueueManager* queue,
} }
} }
void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) { void LaunchStdin(std::unordered_map<MethodType, Timer>* request_times) {
std::thread([request_times]() { std::thread([request_times]() {
set_thread_name("stdin"); set_thread_name("stdin");
auto* queue = QueueManager::instance();
while (true) { while (true) {
std::unique_ptr<InMessage> message; std::unique_ptr<InMessage> message;
std::optional<std::string> err = std::optional<std::string> err =
@ -295,7 +359,7 @@ void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
out.id = id; out.id = id;
out.error.code = lsErrorCodes::InvalidParams; out.error.code = lsErrorCodes::InvalidParams;
out.error.message = std::move(*err); out.error.message = std::move(*err);
queue->WriteStdout(kMethodType_Unknown, out); WriteStdout(kMethodType_Unknown, out);
} }
} }
continue; continue;
@ -305,7 +369,7 @@ void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
MethodType method_type = message->GetMethodType(); MethodType method_type = message->GetMethodType();
(*request_times)[method_type] = Timer(); (*request_times)[method_type] = Timer();
queue->for_querydb.PushBack(std::move(message)); on_request->PushBack(std::move(message));
// If the message was to exit then querydb will take care of the actual // If the message was to exit then querydb will take care of the actual
// exit. Stop reading from stdin since it might be detached. // exit. Stop reading from stdin since it might be detached.
@ -315,16 +379,14 @@ void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
}).detach(); }).detach();
} }
void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times, void LaunchStdout(std::unordered_map<MethodType, Timer>* request_times) {
MultiQueueWaiter* waiter) {
std::thread([=]() { std::thread([=]() {
set_thread_name("stdout"); set_thread_name("stdout");
auto* queue = QueueManager::instance();
while (true) { while (true) {
std::vector<Stdout_Request> messages = queue->for_stdout.DequeueAll(); std::vector<Stdout_Request> messages = for_stdout->DequeueAll();
if (messages.empty()) { if (messages.empty()) {
waiter->Wait(&queue->for_stdout); stdout_waiter->Wait(for_stdout);
continue; continue;
} }
@ -341,8 +403,7 @@ void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
}).detach(); }).detach();
} }
void MainLoop(MultiQueueWaiter* querydb_waiter, void MainLoop() {
MultiQueueWaiter* indexer_waiter) {
Project project; Project project;
SemanticHighlightSymbolCache semantic_cache; SemanticHighlightSymbolCache semantic_cache;
WorkingFiles working_files; WorkingFiles working_files;
@ -362,7 +423,7 @@ void MainLoop(MultiQueueWaiter* querydb_waiter,
out.error.message = out.error.message =
"Dropping completion request; a newer request " "Dropping completion request; a newer request "
"has come in that will be serviced instead."; "has come in that will be serviced instead.";
QueueManager::WriteStdout(kMethodType_Unknown, out); pipeline::WriteStdout(kMethodType_Unknown, out);
} }
}); });
@ -389,11 +450,8 @@ void MainLoop(MultiQueueWaiter* querydb_waiter,
handler->signature_cache = signature_cache.get(); handler->signature_cache = signature_cache.get();
} }
// Run query db main loop.
auto* queue = QueueManager::instance();
while (true) { while (true) {
std::vector<std::unique_ptr<InMessage>> messages = std::vector<std::unique_ptr<InMessage>> messages = on_request->DequeueAll();
queue->for_querydb.DequeueAll();
bool did_work = messages.size(); bool did_work = messages.size();
for (auto& message : messages) { for (auto& message : messages) {
// TODO: Consider using std::unordered_map to lookup the handler // TODO: Consider using std::unordered_map to lookup the handler
@ -409,19 +467,40 @@ void MainLoop(MultiQueueWaiter* querydb_waiter,
} }
for (int i = 80; i--;) { for (int i = 80; i--;) {
std::optional<Index_OnIndexed> response = queue->on_indexed.TryPopFront(); std::optional<Index_OnIndexed> response = on_indexed->TryPopFront();
if (!response) if (!response)
break; break;
did_work = true; did_work = true;
QueryDb_OnIndexed(queue, &db, &semantic_cache, &working_files, &*response); Main_OnIndexed(&db, &semantic_cache, &working_files, &*response);
} }
// Cleanup and free any unused memory. // Cleanup and free any unused memory.
FreeUnusedMemory(); FreeUnusedMemory();
if (!did_work) { if (!did_work)
auto* queue = QueueManager::instance(); main_waiter->Wait(on_indexed, on_request);
querydb_waiter->Wait(&queue->on_indexed, &queue->for_querydb);
} }
} }
void Index(const std::string& path,
const std::vector<std::string>& args,
bool interactive,
lsRequestId id) {
index_request->PushBack({path, args, interactive, id}, interactive);
}
std::optional<std::string> LoadCachedFileContents(const std::string& path) {
return ReadContent(GetCachePath(path));
}
void WriteStdout(MethodType method, lsBaseOutMessage& response) {
std::ostringstream sstream;
response.Write(sstream);
Stdout_Request out;
out.content = sstream.str();
out.method = method;
for_stdout->PushBack(std::move(out));
}
} }

View File

@ -1,28 +1,35 @@
#pragma once #pragma once
#include "queue_manager.h" #include "method.h"
#include "query.h"
#include "timer.h" #include "timer.h"
#include <atomic> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector>
struct ClangTranslationUnit;
class DiagnosticsEngine; class DiagnosticsEngine;
struct VFS; struct VFS;
struct ICacheManager;
struct Project; struct Project;
struct QueryDatabase;
struct SemanticHighlightSymbolCache;
struct WorkingFiles; struct WorkingFiles;
struct lsBaseOutMessage;
namespace ccls::pipeline {
void Init();
void LaunchStdin(std::unordered_map<MethodType, Timer>* request_times);
void LaunchStdout(std::unordered_map<MethodType, Timer>* request_times);
void Indexer_Main(DiagnosticsEngine* diag_engine, void Indexer_Main(DiagnosticsEngine* diag_engine,
VFS* vfs, VFS* vfs,
Project* project, Project* project,
WorkingFiles* working_files, WorkingFiles* working_files);
MultiQueueWaiter* waiter); void MainLoop();
void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times); void Index(const std::string& path,
void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times, const std::vector<std::string>& args,
MultiQueueWaiter* waiter); bool is_interactive,
void MainLoop(MultiQueueWaiter* querydb_waiter, lsRequestId id = {});
MultiQueueWaiter* indexer_waiter);
std::optional<std::string> LoadCachedFileContents(const std::string& path);
void WriteStdout(MethodType method, lsBaseOutMessage& response);
}

View File

@ -1,10 +0,0 @@
#include "port.h"
#include <stdio.h>
#include <stdlib.h>
void ccls_unreachable_internal(const char* msg, const char* file, int line) {
fprintf(stderr, "unreachable %s:%d %s\n", file, line, msg);
CCLS_BUILTIN_UNREACHABLE;
abort();
}

View File

@ -1,34 +0,0 @@
#pragma once
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#if defined(__GNUC__)
#define ATTRIBUTE_UNUSED __attribute__((unused))
#else
#define ATTRIBUTE_UNUSED
#endif
#ifdef __clang__
#define GUARDED_BY(x) __attribute__((guarded_by(x)))
#else
#define GUARDED_BY(x)
#endif
// TODO GCC
#if __has_builtin(__builtin_unreachable)
#define CCLS_BUILTIN_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
#define CCLS_BUILTIN_UNREACHABLE __assume(false)
#else
#define CCLS_BUILTIN_UNREACHABLE
#endif
void ccls_unreachable_internal(const char* msg, const char* file, int line);
#ifndef NDEBUG
#define CCLS_UNREACHABLE(msg) \
ccls_unreachable_internal(msg, __FILE__, __LINE__)
#else
#define CCLS_UNREACHABLE(msg)
#endif

View File

@ -1,17 +1,17 @@
#include "project.h" #include "project.h"
#include "cache_manager.h"
#include "clang_utils.h" #include "clang_utils.h"
#include "filesystem.hh" #include "filesystem.hh"
#include "language.h" #include "language.h"
#include "log.hh" #include "log.hh"
#include "match.h" #include "match.h"
#include "platform.h" #include "platform.h"
#include "queue_manager.h" #include "pipeline.hh"
#include "serializers/json.h" #include "serializers/json.h"
#include "timer.h" #include "timer.h"
#include "utils.h" #include "utils.h"
#include "working_files.h" #include "working_files.h"
using namespace ccls;
#include <clang/Driver/Options.h> #include <clang/Driver/Options.h>
#include <llvm/ADT/ArrayRef.h> #include <llvm/ADT/ArrayRef.h>
@ -454,17 +454,15 @@ void Project::ForAllFilteredFiles(
} }
} }
void Project::Index(QueueManager* queue, void Project::Index(WorkingFiles* wfiles,
WorkingFiles* wfiles,
lsRequestId id) { lsRequestId id) {
ForAllFilteredFiles([&](int i, const Project::Entry& entry) { ForAllFilteredFiles([&](int i, const Project::Entry& entry) {
bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr; bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr;
queue->index_request.PushBack( pipeline::Index(entry.filename, entry.args, is_interactive, id);
Index_Request(entry.filename, entry.args, is_interactive, id));
}); });
// Dummy request to indicate that project is loaded and // Dummy request to indicate that project is loaded and
// trigger refreshing semantic highlight for all working files. // trigger refreshing semantic highlight for all working files.
queue->index_request.PushBack(Index_Request("", {}, false)); pipeline::Index("", {}, false);
} }
TEST_SUITE("Project") { TEST_SUITE("Project") {

View File

@ -5,12 +5,10 @@
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <optional>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
class QueueManager;
struct WorkingFiles; struct WorkingFiles;
struct Project { struct Project {
@ -29,7 +27,7 @@ struct Project {
std::vector<Entry> entries; std::vector<Entry> entries;
std::mutex mutex_; std::mutex mutex_;
std::unordered_map<std::string, int> absolute_path_to_entry_index_ GUARDED_BY(mutex_); std::unordered_map<std::string, int> absolute_path_to_entry_index_;
// Loads a project for the given |directory|. // Loads a project for the given |directory|.
// //
@ -58,5 +56,5 @@ struct Project {
void ForAllFilteredFiles( void ForAllFilteredFiles(
std::function<void(int i, const Entry& entry)> action); std::function<void(int i, const Entry& entry)> action);
void Index(QueueManager* queue, WorkingFiles* wfiles, lsRequestId id); void Index(WorkingFiles* wfiles, lsRequestId id);
}; };

View File

@ -1,6 +1,6 @@
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" #include "pipeline.hh"
#include <limits.h> #include <limits.h>
#include <unordered_set> #include <unordered_set>

View File

@ -1,46 +0,0 @@
#include "queue_manager.h"
#include "cache_manager.h"
#include "lsp.h"
#include "query.h"
#include <sstream>
Index_Request::Index_Request(const std::string& path,
const std::vector<std::string>& args,
bool is_interactive,
lsRequestId id)
: path(path), args(args), is_interactive(is_interactive), id(id) {}
Index_OnIndexed::Index_OnIndexed(IndexUpdate&& update,
PerformanceImportFile perf)
: update(std::move(update)), perf(perf) {}
std::unique_ptr<QueueManager> QueueManager::instance_;
// static
void QueueManager::Init(MultiQueueWaiter* querydb_waiter,
MultiQueueWaiter* indexer_waiter,
MultiQueueWaiter* stdout_waiter) {
instance_ = std::unique_ptr<QueueManager>(
new QueueManager(querydb_waiter, indexer_waiter, stdout_waiter));
}
// static
void QueueManager::WriteStdout(MethodType method, lsBaseOutMessage& response) {
std::ostringstream sstream;
response.Write(sstream);
Stdout_Request out;
out.content = sstream.str();
out.method = method;
instance()->for_stdout.PushBack(std::move(out));
}
QueueManager::QueueManager(MultiQueueWaiter* querydb_waiter,
MultiQueueWaiter* indexer_waiter,
MultiQueueWaiter* stdout_waiter)
: for_stdout(stdout_waiter),
for_querydb(querydb_waiter),
on_indexed(querydb_waiter),
index_request(indexer_waiter) {}

View File

@ -1,84 +0,0 @@
#pragma once
#include "method.h"
#include "query.h"
#include "threaded_queue.h"
#include <memory>
struct ICacheManager;
struct lsBaseOutMessage;
struct Stdout_Request {
MethodType method;
std::string content;
};
struct Index_Request {
std::string path;
// TODO: make |args| a string that is parsed lazily.
std::vector<std::string> args;
bool is_interactive;
lsRequestId id;
Index_Request(const std::string& path,
const std::vector<std::string>& args,
bool is_interactive,
lsRequestId id = {});
};
struct Index_OnIdMapped {
std::shared_ptr<ICacheManager> cache_manager;
std::unique_ptr<IndexFile> previous;
std::unique_ptr<IndexFile> current;
PerformanceImportFile perf;
bool is_interactive;
bool write_to_disk;
Index_OnIdMapped(const std::shared_ptr<ICacheManager>& cache_manager,
std::unique_ptr<IndexFile> previous,
std::unique_ptr<IndexFile> current,
PerformanceImportFile perf,
bool is_interactive,
bool write_to_disk)
: cache_manager(cache_manager),
previous(std::move(previous)),
current(std::move(current)),
perf(perf),
is_interactive(is_interactive),
write_to_disk(write_to_disk) {}
};
struct Index_OnIndexed {
IndexUpdate update;
PerformanceImportFile perf;
Index_OnIndexed(IndexUpdate&& update, PerformanceImportFile perf);
};
class QueueManager {
static std::unique_ptr<QueueManager> instance_;
public:
static QueueManager* instance() { return instance_.get(); }
static void Init(MultiQueueWaiter* querydb_waiter,
MultiQueueWaiter* indexer_waiter,
MultiQueueWaiter* stdout_waiter);
static void WriteStdout(MethodType method, lsBaseOutMessage& response);
// Messages received by "stdout" thread.
ThreadedQueue<Stdout_Request> for_stdout;
// Runs on querydb thread.
ThreadedQueue<std::unique_ptr<InMessage>> for_querydb;
ThreadedQueue<Index_OnIndexed> on_indexed;
// Runs on indexer threads.
ThreadedQueue<Index_Request> index_request;
private:
explicit QueueManager(MultiQueueWaiter* querydb_waiter,
MultiQueueWaiter* indexer_waiter,
MultiQueueWaiter* stdout_waiter);
};

View File

@ -2,7 +2,8 @@
#include "maybe.h" #include "maybe.h"
#include "nt_string.h" #include "nt_string.h"
#include "port.h"
#include <llvm/Support/Compiler.h>
#include <macro_map.h> #include <macro_map.h>
@ -84,12 +85,12 @@ struct IndexFile;
#define MAKE_REFLECT_TYPE_PROXY(type_name) \ #define MAKE_REFLECT_TYPE_PROXY(type_name) \
MAKE_REFLECT_TYPE_PROXY2(type_name, std::underlying_type_t<type_name>) MAKE_REFLECT_TYPE_PROXY2(type_name, std::underlying_type_t<type_name>)
#define MAKE_REFLECT_TYPE_PROXY2(type, as_type) \ #define MAKE_REFLECT_TYPE_PROXY2(type, as_type) \
ATTRIBUTE_UNUSED inline void Reflect(Reader& visitor, type& value) { \ LLVM_ATTRIBUTE_UNUSED inline void Reflect(Reader& visitor, type& value) { \
as_type value0; \ as_type value0; \
::Reflect(visitor, value0); \ ::Reflect(visitor, value0); \
value = static_cast<type>(value0); \ value = static_cast<type>(value0); \
} \ } \
ATTRIBUTE_UNUSED inline void Reflect(Writer& visitor, type& value) { \ LLVM_ATTRIBUTE_UNUSED inline void Reflect(Writer& visitor, type& value) { \
auto value0 = static_cast<as_type>(value); \ auto value0 = static_cast<as_type>(value); \
::Reflect(visitor, value0); \ ::Reflect(visitor, value0); \
} }

View File

@ -284,8 +284,6 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) {
&all_expected_output); &all_expected_output);
// Build flags. // Build flags.
if (!AnyStartsWith(flags, "-x"))
flags.push_back("-xc++");
flags.push_back("-resource-dir=" + GetDefaultResourceDirectory()); flags.push_back("-resource-dir=" + GetDefaultResourceDirectory());
flags.push_back(path); flags.push_back(path);

View File

@ -94,26 +94,6 @@ struct ThreadedQueue : public BaseThreadQueue {
Push<&std::deque<T>::push_back>(std::move(t), priority); Push<&std::deque<T>::push_back>(std::move(t), priority);
} }
// Add a set of elements to the queue.
void EnqueueAll(std::vector<T>&& elements, bool priority = false) {
if (elements.empty())
return;
std::lock_guard<std::mutex> lock(mutex_);
total_count_ += elements.size();
for (T& element : elements) {
if (priority)
priority_.push_back(std::move(element));
else
queue_.push_back(std::move(element));
}
elements.clear();
waiter_->cv.notify_all();
}
// Return all elements in the queue. // Return all elements in the queue.
std::vector<T> DequeueAll() { std::vector<T> DequeueAll() {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);

View File

@ -48,15 +48,6 @@ bool StartsWith(std::string_view s, std::string_view prefix) {
std::equal(prefix.begin(), prefix.end(), s.begin()); std::equal(prefix.begin(), prefix.end(), s.begin());
} }
bool AnyStartsWith(const std::vector<std::string>& xs,
std::string_view prefix) {
return std::any_of(xs.begin(), xs.end(), std::bind(StartsWith, _1, prefix));
}
bool StartsWithAny(std::string_view s, const std::vector<std::string>& ps) {
return std::any_of(ps.begin(), ps.end(), std::bind(StartsWith, s, _1));
}
bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss) { bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss) {
return std::any_of(ss.begin(), ss.end(), std::bind(EndsWith, s, _1)); return std::any_of(ss.begin(), ss.end(), std::bind(EndsWith, s, _1));
} }

View File

@ -17,8 +17,6 @@ uint64_t HashUsr(std::string_view s);
// Returns true if |value| starts/ends with |start| or |ending|. // Returns true if |value| starts/ends with |start| or |ending|.
bool StartsWith(std::string_view value, std::string_view start); bool StartsWith(std::string_view value, std::string_view start);
bool EndsWith(std::string_view value, std::string_view ending); bool EndsWith(std::string_view value, std::string_view ending);
bool AnyStartsWith(const std::vector<std::string>& xs, std::string_view prefix);
bool StartsWithAny(std::string_view s, const std::vector<std::string>& ps);
bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss); bool EndsWithAny(std::string_view s, const std::vector<std::string>& ss);
bool FindAnyPartial(const std::string& value, bool FindAnyPartial(const std::string& value,
const std::vector<std::string>& values); const std::vector<std::string>& values);