mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-25 09:05:10 +00:00
Add DiagnosticsEngine and add config->diagnostics.frequencyMs to allow reducing textDocument/publishDiagnostics frequency
This commit is contained in:
parent
df95cd4780
commit
df55e79e4e
@ -383,7 +383,7 @@ void TryEnsureDocumentParsed(ClangCompleteManager* manager,
|
||||
unsaved, Flags());
|
||||
|
||||
// Build diagnostics.
|
||||
if (manager->config_->diagnosticsOnParse && *tu) {
|
||||
if (manager->config_->diagnostics.onParse && *tu) {
|
||||
// If we're emitting diagnostics, do an immediate reparse, otherwise we will
|
||||
// emit stale/bad diagnostics.
|
||||
*tu = ClangTranslationUnit::Reparse(std::move(*tu), unsaved);
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "cache_manager.h"
|
||||
#include "clang_complete.h"
|
||||
#include "code_complete_cache.h"
|
||||
#include "diagnostics_engine.h"
|
||||
#include "file_consumer.h"
|
||||
#include "import_manager.h"
|
||||
#include "import_pipeline.h"
|
||||
@ -177,11 +178,12 @@ void RunQueryDbThread(const std::string& bin_name,
|
||||
SemanticHighlightSymbolCache semantic_cache;
|
||||
WorkingFiles working_files;
|
||||
FileConsumerSharedState file_consumer_shared;
|
||||
DiagnosticsEngine diag_engine(config);
|
||||
|
||||
ClangCompleteManager clang_complete(
|
||||
config, &project, &working_files,
|
||||
[&](std::string path, std::vector<lsDiagnostic> diagnostics) {
|
||||
EmitDiagnostics(&working_files, path, diagnostics);
|
||||
diag_engine.Publish(&working_files, path, diagnostics);
|
||||
},
|
||||
[&](ClangTranslationUnit* tu, const std::vector<CXUnsavedFile>& unsaved,
|
||||
const std::string& path, const std::vector<std::string>& args) {
|
||||
@ -214,6 +216,7 @@ void RunQueryDbThread(const std::string& bin_name,
|
||||
handler->db = &db;
|
||||
handler->waiter = indexer_waiter;
|
||||
handler->project = &project;
|
||||
handler->diag_engine = &diag_engine;
|
||||
handler->file_consumer_shared = &file_consumer_shared;
|
||||
handler->import_manager = &import_manager;
|
||||
handler->import_pipeline_status = &import_pipeline_status;
|
||||
|
28
src/config.h
28
src/config.h
@ -72,9 +72,6 @@ struct Config {
|
||||
// If true, document links are reported for #include directives.
|
||||
bool showDocumentLinksOnIncludes = true;
|
||||
|
||||
// If true, diagnostics from a full document parse will be reported.
|
||||
bool diagnosticsOnParse = true;
|
||||
|
||||
// Version of the client. If undefined the version check is skipped. Used to
|
||||
// inform users their vscode client is too old and needs to be updated.
|
||||
optional<int> clientVersion;
|
||||
@ -144,6 +141,23 @@ struct Config {
|
||||
std::vector<std::string> includeWhitelist;
|
||||
} completion;
|
||||
|
||||
struct Diagnostics {
|
||||
// Like index.{whitelist,blacklist}, don't publish diagnostics to
|
||||
// blacklisted files.
|
||||
std::vector<std::string> blacklist;
|
||||
|
||||
// How often should cquery publish diagnostics in completion?
|
||||
// -1: never
|
||||
// 0: as often as possible
|
||||
// xxx: at most every xxx milliseconds
|
||||
int frequencyMs = 0;
|
||||
|
||||
// If true, diagnostics from a full document parse will be reported.
|
||||
bool onParse = true;
|
||||
|
||||
std::vector<std::string> whitelist;
|
||||
} diagnostics;
|
||||
|
||||
struct Index {
|
||||
// Attempt to convert calls of make* functions to constructors based on
|
||||
// hueristics.
|
||||
@ -210,6 +224,11 @@ MAKE_REFLECT_STRUCT(Config::Completion,
|
||||
includeMaxPathSize,
|
||||
includeSuffixWhitelist,
|
||||
includeWhitelist);
|
||||
MAKE_REFLECT_STRUCT(Config::Diagnostics,
|
||||
blacklist,
|
||||
frequencyMs,
|
||||
onParse,
|
||||
whitelist)
|
||||
MAKE_REFLECT_STRUCT(Config::Index,
|
||||
attributeMakeCallsToCtor,
|
||||
blacklist,
|
||||
@ -233,13 +252,12 @@ MAKE_REFLECT_STRUCT(Config,
|
||||
|
||||
showDocumentLinksOnIncludes,
|
||||
|
||||
diagnosticsOnParse,
|
||||
|
||||
clientVersion,
|
||||
|
||||
client,
|
||||
codeLens,
|
||||
completion,
|
||||
diagnostics,
|
||||
index,
|
||||
workspaceSymbol,
|
||||
xref,
|
||||
|
30
src/diagnostics_engine.cc
Normal file
30
src/diagnostics_engine.cc
Normal file
@ -0,0 +1,30 @@
|
||||
#include "diagnostics_engine.h"
|
||||
|
||||
#include "queue_manager.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
DiagnosticsEngine::DiagnosticsEngine(Config* config)
|
||||
: match_(config->diagnostics.whitelist, config->diagnostics.blacklist) {}
|
||||
|
||||
void DiagnosticsEngine::Publish(WorkingFiles* working_files,
|
||||
std::string path,
|
||||
std::vector<lsDiagnostic> diagnostics) {
|
||||
// Cache diagnostics so we can show fixits.
|
||||
working_files->DoActionOnFile(path, [&](WorkingFile* working_file) {
|
||||
if (working_file)
|
||||
working_file->diagnostics_ = diagnostics;
|
||||
});
|
||||
|
||||
int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()).count();
|
||||
if (frequencyMs_ >= 0 && (nextPublish_ <= now || diagnostics.empty()) &&
|
||||
match_.IsMatch(path)) {
|
||||
nextPublish_ = now + frequencyMs_;
|
||||
|
||||
Out_TextDocumentPublishDiagnostics out;
|
||||
out.params.uri = lsDocumentUri::FromPath(path);
|
||||
out.params.diagnostics = diagnostics;
|
||||
QueueManager::WriteStdout(IpcId::TextDocumentPublishDiagnostics, out);
|
||||
}
|
||||
}
|
17
src/diagnostics_engine.h
Normal file
17
src/diagnostics_engine.h
Normal file
@ -0,0 +1,17 @@
|
||||
#include "lsp_diagnostic.h"
|
||||
|
||||
#include "match.h"
|
||||
#include "working_files.h"
|
||||
|
||||
class DiagnosticsEngine {
|
||||
int frequencyMs_ = 0;
|
||||
GroupMatch match_;
|
||||
int64_t nextPublish_ = 0;
|
||||
|
||||
public:
|
||||
DiagnosticsEngine(Config* config);
|
||||
void SetFrequencyMs(int ms) { frequencyMs_ = ms; }
|
||||
void Publish(WorkingFiles* working_files,
|
||||
std::string path,
|
||||
std::vector<lsDiagnostic> diagnostics);
|
||||
};
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "cache_manager.h"
|
||||
#include "config.h"
|
||||
#include "diagnostics_engine.h"
|
||||
#include "iindexer.h"
|
||||
#include "import_manager.h"
|
||||
#include "lsp.h"
|
||||
@ -340,6 +341,7 @@ std::vector<FileContents> PreloadFileContents(
|
||||
}
|
||||
|
||||
void ParseFile(Config* config,
|
||||
DiagnosticsEngine* diag_engine,
|
||||
WorkingFiles* working_files,
|
||||
FileConsumerSharedState* file_consumer_shared,
|
||||
TimestampManager* timestamp_manager,
|
||||
@ -394,7 +396,8 @@ void ParseFile(Config* config,
|
||||
// to identify indexing problems. For interactive sessions, diagnostics are
|
||||
// handled by code completion.
|
||||
if (!request.is_interactive)
|
||||
EmitDiagnostics(working_files, new_index->path, new_index->diagnostics_);
|
||||
diag_engine->Publish(working_files, new_index->path,
|
||||
new_index->diagnostics_);
|
||||
|
||||
// When main thread does IdMap request it will request the previous index if
|
||||
// needed.
|
||||
@ -410,6 +413,7 @@ void ParseFile(Config* config,
|
||||
|
||||
bool IndexMain_DoParse(
|
||||
Config* config,
|
||||
DiagnosticsEngine* diag_engine,
|
||||
WorkingFiles* working_files,
|
||||
FileConsumerSharedState* file_consumer_shared,
|
||||
TimestampManager* timestamp_manager,
|
||||
@ -424,9 +428,9 @@ bool IndexMain_DoParse(
|
||||
Project::Entry entry;
|
||||
entry.filename = request->path;
|
||||
entry.args = request->args;
|
||||
ParseFile(config, working_files, file_consumer_shared, timestamp_manager,
|
||||
modification_timestamp_fetcher, import_manager, indexer,
|
||||
request.value(), entry);
|
||||
ParseFile(config, diag_engine, working_files, file_consumer_shared,
|
||||
timestamp_manager, modification_timestamp_fetcher, import_manager,
|
||||
indexer, request.value(), entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -582,6 +586,7 @@ void IndexWithTuFromCodeCompletion(
|
||||
}
|
||||
|
||||
void Indexer_Main(Config* config,
|
||||
DiagnosticsEngine* diag_engine,
|
||||
FileConsumerSharedState* file_consumer_shared,
|
||||
TimestampManager* timestamp_manager,
|
||||
ImportManager* import_manager,
|
||||
@ -609,11 +614,11 @@ void Indexer_Main(Config* config,
|
||||
// IndexMain_DoCreateIndexUpdate so we don't starve querydb from doing any
|
||||
// work. Running both also lets the user query the partially constructed
|
||||
// index.
|
||||
did_work =
|
||||
IndexMain_DoParse(config, working_files, file_consumer_shared,
|
||||
timestamp_manager, &modification_timestamp_fetcher,
|
||||
import_manager, indexer.get()) ||
|
||||
did_work;
|
||||
did_work = IndexMain_DoParse(config, diag_engine, working_files,
|
||||
file_consumer_shared, timestamp_manager,
|
||||
&modification_timestamp_fetcher,
|
||||
import_manager, indexer.get()) ||
|
||||
did_work;
|
||||
|
||||
did_work = IndexMain_DoCreateIndexUpdate(timestamp_manager) || did_work;
|
||||
|
||||
@ -767,9 +772,10 @@ TEST_SUITE("ImportPipeline") {
|
||||
}
|
||||
|
||||
bool PumpOnce() {
|
||||
return IndexMain_DoParse(
|
||||
&config, &working_files, &file_consumer_shared, ×tamp_manager,
|
||||
&modification_timestamp_fetcher, &import_manager, indexer.get());
|
||||
return IndexMain_DoParse(&config, &diag_engine, &working_files,
|
||||
&file_consumer_shared, ×tamp_manager,
|
||||
&modification_timestamp_fetcher, &import_manager,
|
||||
indexer.get());
|
||||
}
|
||||
|
||||
void MakeRequest(const std::string& path,
|
||||
@ -786,6 +792,7 @@ TEST_SUITE("ImportPipeline") {
|
||||
|
||||
QueueManager* queue = nullptr;
|
||||
Config config;
|
||||
DiagnosticsEngine diag_engine{&config};
|
||||
WorkingFiles working_files;
|
||||
FileConsumerSharedState file_consumer_shared;
|
||||
TimestampManager timestamp_manager;
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
struct ClangTranslationUnit;
|
||||
struct Config;
|
||||
class DiagnosticsEngine;
|
||||
struct FileConsumerSharedState;
|
||||
struct ImportManager;
|
||||
struct MultiQueueWaiter;
|
||||
@ -35,6 +36,7 @@ void IndexWithTuFromCodeCompletion(
|
||||
const std::vector<std::string>& args);
|
||||
|
||||
void Indexer_Main(Config* config,
|
||||
DiagnosticsEngine* diag_engine,
|
||||
FileConsumerSharedState* file_consumer_shared,
|
||||
TimestampManager* timestamp_manager,
|
||||
ImportManager* import_manager,
|
||||
|
@ -1,20 +1,5 @@
|
||||
#include "lsp_diagnostic.h"
|
||||
|
||||
#include "match.h"
|
||||
#include "queue_manager.h"
|
||||
#include "working_files.h"
|
||||
|
||||
void EmitDiagnostics(WorkingFiles* working_files,
|
||||
std::string path,
|
||||
std::vector<lsDiagnostic> diagnostics) {
|
||||
// Emit diagnostics.
|
||||
Out_TextDocumentPublishDiagnostics out;
|
||||
out.params.uri = lsDocumentUri::FromPath(path);
|
||||
out.params.diagnostics = diagnostics;
|
||||
QueueManager::WriteStdout(IpcId::TextDocumentPublishDiagnostics, out);
|
||||
|
||||
// Cache diagnostics so we can show fixits.
|
||||
working_files->DoActionOnFile(path, [&](WorkingFile* working_file) {
|
||||
if (working_file)
|
||||
working_file->diagnostics_ = diagnostics;
|
||||
});
|
||||
}
|
||||
|
@ -99,8 +99,3 @@ void Reflect(TVisitor& visitor, Out_TextDocumentPublishDiagnostics& value) {
|
||||
MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params,
|
||||
uri,
|
||||
diagnostics);
|
||||
|
||||
struct WorkingFiles;
|
||||
void EmitDiagnostics(WorkingFiles* working_files,
|
||||
std::string path,
|
||||
std::vector<lsDiagnostic> diagnostics);
|
||||
|
@ -12,6 +12,7 @@
|
||||
struct ClangCompleteManager;
|
||||
struct CodeCompleteCache;
|
||||
struct Config;
|
||||
class DiagnosticsEngine;
|
||||
struct FileConsumerSharedState;
|
||||
struct ImportManager;
|
||||
struct ImportPipelineStatus;
|
||||
@ -72,6 +73,7 @@ struct MessageHandler {
|
||||
QueryDatabase* db = nullptr;
|
||||
MultiQueueWaiter* waiter = nullptr;
|
||||
Project* project = nullptr;
|
||||
DiagnosticsEngine* diag_engine = nullptr;
|
||||
FileConsumerSharedState* file_consumer_shared = nullptr;
|
||||
ImportManager* import_manager = nullptr;
|
||||
ImportPipelineStatus* import_pipeline_status = nullptr;
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "cache_manager.h"
|
||||
#include "diagnostics_engine.h"
|
||||
#include "import_pipeline.h"
|
||||
#include "include_complete.h"
|
||||
#include "message_handler.h"
|
||||
@ -581,6 +582,7 @@ struct InitializeHandler : BaseMessageHandler<Ipc_InitializeRequest> {
|
||||
EscapeFileName(config->projectRoot));
|
||||
|
||||
Timer time;
|
||||
diag_engine->SetFrequencyMs(config->diagnostics.frequencyMs);
|
||||
|
||||
// Open up / load the project.
|
||||
project->Load(config, config->extraClangArguments,
|
||||
@ -604,9 +606,9 @@ struct InitializeHandler : BaseMessageHandler<Ipc_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), [=]() {
|
||||
Indexer_Main(config, file_consumer_shared, timestamp_manager,
|
||||
import_manager, import_pipeline_status, project,
|
||||
working_files, waiter);
|
||||
Indexer_Main(config, diag_engine, file_consumer_shared,
|
||||
timestamp_manager, import_manager,
|
||||
import_pipeline_status, project, working_files, waiter);
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user