Simplify; improve $ccls/inheritanceHierarchy

This commit is contained in:
Fangrui Song 2018-05-25 22:48:58 -07:00
parent f5ce45fd55
commit a6094ef714
9 changed files with 141 additions and 173 deletions

View File

@ -2,6 +2,8 @@
#include "query_utils.h" #include "query_utils.h"
#include "queue_manager.h" #include "queue_manager.h"
#include <unordered_set>
namespace { namespace {
MethodType kMethodType = "$ccls/inheritanceHierarchy"; MethodType kMethodType = "$ccls/inheritanceHierarchy";
@ -79,19 +81,22 @@ bool ExpandHelper(MessageHandler* m,
int levels, int levels,
Q& entity) { Q& entity) {
const auto* def = entity.AnyDef(); const auto* def = entity.AnyDef();
if (!def) { if (def) {
entry->name = def->Name(qualified);
if (def->spell) {
if (auto loc = GetLsLocation(m->db, m->working_files, *def->spell))
entry->location = *loc;
}
} else if (!derived) {
entry->numChildren = 0; entry->numChildren = 0;
return false; return false;
} }
entry->name = def->Name(qualified); std::unordered_set<Usr> seen;
if (def->spell) {
if (std::optional<lsLocation> loc =
GetLsLocation(m->db, m->working_files, *def->spell))
entry->location = *loc;
}
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)
continue;
Out_CclsInheritanceHierarchy::Entry entry1; Out_CclsInheritanceHierarchy::Entry entry1;
entry1.id = std::to_string(usr); entry1.id = std::to_string(usr);
entry1.usr = usr; entry1.usr = usr;
@ -105,6 +110,8 @@ 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)
continue;
Out_CclsInheritanceHierarchy::Entry entry1; Out_CclsInheritanceHierarchy::Entry entry1;
entry1.id = std::to_string(usr); entry1.id = std::to_string(usr);
entry1.usr = usr; entry1.usr = usr;

View File

@ -267,12 +267,8 @@ struct lsTextDocumentClientCapabilities {
// and `${3:foo}`. `$0` defines the final tab stop, it defaults to // and `${3:foo}`. `$0` defines the final tab stop, it defaults to
// the end of the snippet. Placeholders with equal identifiers are linked, // the end of the snippet. Placeholders with equal identifiers are linked,
// that is typing in one will update others too. // that is typing in one will update others too.
std::optional<bool> snippetSupport; bool snippetSupport = false;
}; } completionItem;
// The client supports the following `CompletionItem` specific
// capabilities.
std::optional<lsCompletionItem> completionItem;
} completion; } completion;
struct lsGenericDynamicReg { struct lsGenericDynamicReg {
@ -426,58 +422,56 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_InitializeRequest* request) override { void Run(In_InitializeRequest* request) override {
// Log initialization parameters. auto& params = request->params;
if (!params.rootUri)
return;
{
rapidjson::StringBuffer output; rapidjson::StringBuffer output;
rapidjson::Writer<rapidjson::StringBuffer> writer(output); rapidjson::Writer<rapidjson::StringBuffer> writer(output);
JsonWriter json_writer(&writer); JsonWriter json_writer(&writer);
Reflect(json_writer, request->params.initializationOptions); Reflect(json_writer, params.initializationOptions);
LOG_S(INFO) << "Init parameters: " << output.GetString(); LOG_S(INFO) << "initializationOptions: " << output.GetString();
std::unique_ptr<Config> config; }
if (request->params.rootUri) { std::string project_path = NormalizePath(params.rootUri->GetPath());
std::string project_path = LOG_S(INFO) << "initialize in directory " << project_path << " with uri "
NormalizePath(request->params.rootUri->GetPath()); << params.rootUri->raw_uri;
LOG_S(INFO) << "[querydb] Initialize in directory " << project_path
<< " with uri " << request->params.rootUri->raw_uri;
{ {
if (request->params.initializationOptions) if (params.initializationOptions)
config = std::make_unique<Config>(*request->params.initializationOptions); g_config = std::make_unique<Config>(*params.initializationOptions);
else else
config = std::make_unique<Config>(); g_config = std::make_unique<Config>();
rapidjson::Document reader; rapidjson::Document reader;
reader.Parse(g_init_options.c_str()); reader.Parse(g_init_options.c_str());
if (!reader.HasParseError()) { if (!reader.HasParseError()) {
JsonReader json_reader{&reader}; JsonReader json_reader{&reader};
try { try {
Reflect(json_reader, *config); Reflect(json_reader, *g_config);
} catch (std::invalid_argument&) { } catch (std::invalid_argument&) {
// This will not trigger because parse error is handled in // This will not trigger because parse error is handled in
// MessageRegistry::Parse in lsp.cc // MessageRegistry::Parse in lsp.cc
} }
} }
if (config->cacheDirectory.empty()) { if (g_config->cacheDirectory.empty()) {
LOG_S(ERROR) << "cacheDirectory cannot be empty."; LOG_S(ERROR) << "cacheDirectory cannot be empty.";
exit(1); exit(1);
} else { } else {
config->cacheDirectory = NormalizePath(config->cacheDirectory); g_config->cacheDirectory = NormalizePath(g_config->cacheDirectory);
EnsureEndsInSlash(config->cacheDirectory); EnsureEndsInSlash(g_config->cacheDirectory);
} }
} }
// Client capabilities // Client capabilities
{ const auto& capabilities = params.capabilities;
const auto& cap = request->params.capabilities.textDocument; g_config->client.snippetSupport =
if (cap.completion.completionItem) capabilities.textDocument.completion.completionItem.snippetSupport;
config->client.snippetSupport =
cap.completion.completionItem->snippetSupport.value_or(false);
}
// Ensure there is a resource directory. // Ensure there is a resource directory.
if (config->clang.resourceDir.empty()) if (g_config->clang.resourceDir.empty())
config->clang.resourceDir = GetDefaultResourceDirectory(); g_config->clang.resourceDir = GetDefaultResourceDirectory();
LOG_S(INFO) << "Using -resource-dir=" << config->clang.resourceDir; LOG_S(INFO) << "Using -resource-dir=" << g_config->clang.resourceDir;
// Send initialization before starting indexers, so we don't send a // Send initialization before starting indexers, so we don't send a
// status update too early. // status update too early.
@ -491,15 +485,14 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
// Set project root. // Set project root.
EnsureEndsInSlash(project_path); EnsureEndsInSlash(project_path);
config->projectRoot = project_path; g_config->projectRoot = project_path;
// Create two cache directories for files inside and outside of the // Create two cache directories for files inside and outside of the
// project. // project.
sys::fs::create_directories(config->cacheDirectory + sys::fs::create_directories(g_config->cacheDirectory +
EscapeFileName(config->projectRoot)); EscapeFileName(g_config->projectRoot));
sys::fs::create_directories(config->cacheDirectory + '@' + sys::fs::create_directories(g_config->cacheDirectory + '@' +
EscapeFileName(config->projectRoot)); EscapeFileName(g_config->projectRoot));
g_config = std::move(config);
Timer time; Timer time;
diag_engine->Init(); diag_engine->Init();
semantic_cache->Init(); semantic_cache->Init();
@ -534,7 +527,6 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
// 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");
} }
}
}; };
REGISTER_MESSAGE_HANDLER(Handler_Initialize); REGISTER_MESSAGE_HANDLER(Handler_Initialize);
} // namespace } // namespace

View File

@ -26,17 +26,11 @@ struct Handler_TextDocumentDidChange
std::string path = request->params.textDocument.uri.GetPath(); std::string path = request->params.textDocument.uri.GetPath();
working_files->OnChange(request->params); working_files->OnChange(request->params);
if (g_config->index.onDidChange) { if (g_config->index.onDidChange) {
std::optional<std::string> content = ReadContent(path);
if (!content) {
LOG_S(ERROR) << "Unable to read file content after saving " << path;
} else {
Project::Entry entry = project->FindCompilationEntryForFile(path); Project::Entry entry = project->FindCompilationEntryForFile(path);
QueueManager::instance()->index_request.PushBack( QueueManager::instance()->index_request.PushBack(
Index_Request(entry.filename, entry.args, true /*is_interactive*/, Index_Request(entry.filename, entry.args, true /*is_interactive*/),
*content),
true); true);
} }
}
clang_complete->NotifyEdit(path); clang_complete->NotifyEdit(path);
clang_complete->DiagnosticsUpdate( clang_complete->DiagnosticsUpdate(
request->params.textDocument.AsTextDocumentIdentifier()); request->params.textDocument.AsTextDocumentIdentifier());

View File

@ -65,7 +65,7 @@ struct Handler_TextDocumentDidOpen
QueueManager::instance()->index_request.PushBack( QueueManager::instance()->index_request.PushBack(
Index_Request(entry.filename, Index_Request(entry.filename,
params.args.size() ? params.args : entry.args, params.args.size() ? params.args : entry.args,
true /*is_interactive*/, params.textDocument.text), true /*is_interactive*/),
true /* priority */); true /* priority */);
clang_complete->FlushSession(entry.filename); clang_complete->FlushSession(entry.filename);

View File

@ -48,17 +48,11 @@ struct Handler_TextDocumentDidSave
// if so, ignore that index response. // if so, ignore that index response.
// TODO: send as priority request // TODO: send as priority request
if (!g_config->index.onDidChange) { if (!g_config->index.onDidChange) {
std::optional<std::string> content = ReadContent(path);
if (!content) {
LOG_S(ERROR) << "Unable to read file content after saving " << path;
} else {
Project::Entry entry = project->FindCompilationEntryForFile(path); Project::Entry entry = project->FindCompilationEntryForFile(path);
QueueManager::instance()->index_request.PushBack( QueueManager::instance()->index_request.PushBack(
Index_Request(entry.filename, entry.args, true /*is_interactive*/, Index_Request(entry.filename, entry.args, true /*is_interactive*/),
*content),
true); true);
} }
}
clang_complete->NotifySave(path); clang_complete->NotifySave(path);
} }

View File

@ -54,20 +54,15 @@ struct Handler_WorkspaceDidChangeWatchedFiles
switch (event.type) { switch (event.type) {
case lsFileChangeType::Created: case lsFileChangeType::Created:
case lsFileChangeType::Changed: { case lsFileChangeType::Changed: {
std::optional<std::string> content = ReadContent(path);
if (!content)
LOG_S(ERROR) << "Unable to read file content after saving " << path;
else {
QueueManager::instance()->index_request.PushBack( QueueManager::instance()->index_request.PushBack(
Index_Request(path, entry.args, is_interactive, *content)); 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( QueueManager::instance()->index_request.PushBack(
Index_Request(path, entry.args, is_interactive, std::string())); Index_Request(path, entry.args, is_interactive));
break; break;
} }
} }

View File

@ -458,19 +458,13 @@ void Project::Index(QueueManager* queue,
WorkingFiles* wfiles, WorkingFiles* wfiles,
lsRequestId id) { lsRequestId id) {
ForAllFilteredFiles([&](int i, const Project::Entry& entry) { ForAllFilteredFiles([&](int i, const Project::Entry& entry) {
std::optional<std::string> content = ReadContent(entry.filename);
if (!content) {
LOG_S(ERROR) << "When loading project, canont read file "
<< entry.filename;
return;
}
bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr; bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr;
queue->index_request.PushBack(Index_Request(entry.filename, entry.args, queue->index_request.PushBack(
is_interactive, *content, 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, "")); queue->index_request.PushBack(Index_Request("", {}, false));
} }
TEST_SUITE("Project") { TEST_SUITE("Project") {

View File

@ -6,17 +6,11 @@
#include <sstream> #include <sstream>
Index_Request::Index_Request( Index_Request::Index_Request(const std::string& path,
const std::string& path,
const std::vector<std::string>& args, const std::vector<std::string>& args,
bool is_interactive, bool is_interactive,
const std::string& contents,
lsRequestId id) lsRequestId id)
: path(path), : path(path), args(args), is_interactive(is_interactive), id(id) {}
args(args),
is_interactive(is_interactive),
contents(contents),
id(id) {}
Index_OnIndexed::Index_OnIndexed(IndexUpdate&& update, Index_OnIndexed::Index_OnIndexed(IndexUpdate&& update,
PerformanceImportFile perf) PerformanceImportFile perf)

View File

@ -19,13 +19,11 @@ struct Index_Request {
// TODO: make |args| a string that is parsed lazily. // TODO: make |args| a string that is parsed lazily.
std::vector<std::string> args; std::vector<std::string> args;
bool is_interactive; bool is_interactive;
std::string contents; // Preloaded contents.
lsRequestId id; lsRequestId id;
Index_Request(const std::string& path, Index_Request(const std::string& path,
const std::vector<std::string>& args, const std::vector<std::string>& args,
bool is_interactive, bool is_interactive,
const std::string& contents,
lsRequestId id = {}); lsRequestId id = {});
}; };