Add 'cquery: Freshen Index' command.

This validates every file is indexed to its current state. It is very useful after, ie, a git checkout.
This commit is contained in:
Jacob Dufault 2017-04-20 21:50:31 -07:00
parent ead75bb7a3
commit 145bf87d70
7 changed files with 125 additions and 64 deletions

View File

@ -187,6 +187,7 @@ struct IpcManager {
RegisterId<Ipc_IsAlive>(ipc.get()); RegisterId<Ipc_IsAlive>(ipc.get());
RegisterId<Ipc_OpenProject>(ipc.get()); RegisterId<Ipc_OpenProject>(ipc.get());
RegisterId<Ipc_Cout>(ipc.get()); RegisterId<Ipc_Cout>(ipc.get());
RegisterId<Ipc_CqueryFreshenIndex>(ipc.get());
return ipc; return ipc;
} }
}; };
@ -784,6 +785,7 @@ struct Index_DoIndex {
ImportAndUpdate, ImportAndUpdate,
ImportOnly, ImportOnly,
Parse, Parse,
Freshen,
}; };
Index_DoIndex(Type type, const std::string& path, const optional<std::vector<std::string>>& args) Index_DoIndex(Type type, const std::string& path, const optional<std::vector<std::string>>& args)
@ -839,6 +841,7 @@ void RegisterMessageTypes() {
MessageRegistry::instance()->Register<Ipc_TextDocumentCodeLens>(); MessageRegistry::instance()->Register<Ipc_TextDocumentCodeLens>();
MessageRegistry::instance()->Register<Ipc_CodeLensResolve>(); MessageRegistry::instance()->Register<Ipc_CodeLensResolve>();
MessageRegistry::instance()->Register<Ipc_WorkspaceSymbol>(); MessageRegistry::instance()->Register<Ipc_WorkspaceSymbol>();
MessageRegistry::instance()->Register<Ipc_CqueryFreshenIndex>();
} }
@ -870,7 +873,16 @@ void RegisterMessageTypes() {
void DispatchDependencyImports(Index_DoIndexQueue* queue_do_index,
Index_DoIndex::Type request_type,
const std::vector<std::string>& dependencies) {
// Import all dependencies.
for (auto& dependency_path : dependencies) {
std::cerr << "- Dispatching dependency import " << dependency_path << std::endl;
queue_do_index->PriorityEnqueue(Index_DoIndex(request_type, dependency_path, nullopt));
}
}
void ImportCachedIndex(IndexerConfig* config, void ImportCachedIndex(IndexerConfig* config,
Index_DoIndexQueue* queue_do_index, Index_DoIndexQueue* queue_do_index,
@ -886,11 +898,7 @@ void ImportCachedIndex(IndexerConfig* config,
if (!cache) if (!cache)
return; return;
// Import all dependencies. DispatchDependencyImports(queue_do_index, Index_DoIndex::Type::ImportOnly, cache->dependencies);
for (auto& dependency_path : cache->dependencies) {
std::cerr << "- Dispatching dependency import " << dependency_path << std::endl;
queue_do_index->PriorityEnqueue(Index_DoIndex(Index_DoIndex::Type::ImportOnly, dependency_path, nullopt));
}
*last_modification_time = cache->last_modification_time; *last_modification_time = cache->last_modification_time;
Index_DoIdMap response(nullptr, std::move(cache)); Index_DoIdMap response(nullptr, std::move(cache));
@ -901,16 +909,27 @@ void ParseFile(IndexerConfig* config,
FileConsumer::SharedState* file_consumer_shared, FileConsumer::SharedState* file_consumer_shared,
Index_DoIdMapQueue* queue_do_id_map, Index_DoIdMapQueue* queue_do_id_map,
const std::string& path, const std::string& path,
const optional<std::vector<std::string>>& args) { const optional<std::vector<std::string>>& args,
std::vector<std::string>* opt_out_dependencies) {
Timer time; Timer time;
// Parse request and send a response. // Parse request and send a response.
std::unique_ptr<IndexedFile> cached_path_index = LoadCachedFile(config, path); std::unique_ptr<IndexedFile> cached_path_index = LoadCachedFile(config, path);
// Skip index if file modification time didn't change. if (cached_path_index) {
if (cached_path_index && GetLastModificationTime(path) == cached_path_index->last_modification_time) { // Give the user dependencies if requested.
time.ResetAndPrint("Skipping index update on " + path + " since file modification time has not changed"); if (opt_out_dependencies)
return; *opt_out_dependencies = cached_path_index->dependencies;
// Skip index if file modification time didn't change.
int64_t modification_time = GetLastModificationTime(path);
if (modification_time == cached_path_index->last_modification_time) {
time.ResetAndPrint("Skipping index update on " + path + " since file modification time has not changed");
return;
}
else {
time.ResetAndPrint("Modification time on " + path + " has changed from " + std::to_string(cached_path_index->last_modification_time) + " to " + std::to_string(modification_time));
}
} }
std::vector<std::unique_ptr<IndexedFile>> indexes = Parse( std::vector<std::unique_ptr<IndexedFile>> indexes = Parse(
@ -982,7 +1001,14 @@ bool IndexMain_DoIndex(IndexerConfig* config,
} }
case Index_DoIndex::Type::Parse: { case Index_DoIndex::Type::Parse: {
ParseFile(config, file_consumer_shared, queue_do_id_map, index_request->path, index_request->args); ParseFile(config, file_consumer_shared, queue_do_id_map, index_request->path, index_request->args, nullptr);
break;
}
case Index_DoIndex::Type::Freshen: {
std::vector<std::string> dependencies;
ParseFile(config, file_consumer_shared, queue_do_id_map, index_request->path, index_request->args, &dependencies);
DispatchDependencyImports(queue_do_index, Index_DoIndex::Type::Freshen, dependencies);
break; break;
} }
} }
@ -1145,60 +1171,28 @@ void QueryDbMainLoop(
Ipc_OpenProject* msg = static_cast<Ipc_OpenProject*>(message.get()); Ipc_OpenProject* msg = static_cast<Ipc_OpenProject*>(message.get());
std::string path = msg->project_path; std::string path = msg->project_path;
std::vector<Matcher> whitelist;
std::cerr << "Using whitelist" << std::endl;
for (const std::string& entry : config->whitelist) {
std::cerr << " - " << entry << std::endl;
whitelist.push_back(Matcher(entry));
}
std::vector<Matcher> blacklist;
std::cerr << "Using blacklist" << std::endl;
for (const std::string& entry : config->blacklist) {
std::cerr << " - " << entry << std::endl;
blacklist.push_back(Matcher(entry));
}
project->Load(path); project->Load(path);
std::cerr << "Loaded compilation entries (" << project->entries.size() << " files)" << std::endl; std::cerr << "Loaded compilation entries (" << project->entries.size() << " files)" << std::endl;
//for (int i = 0; i < 10; ++i)
//std::cerr << project->entries[i].filename << std::endl;
for (int i = 0; i < project->entries.size(); ++i) {
const Project::Entry& entry = project->entries[i];
std::string filepath = entry.filename;
const Matcher* is_bad = nullptr;
for (const Matcher& m : whitelist) {
if (!m.IsMatch(filepath)) {
is_bad = &m;
break;
}
}
if (is_bad) {
std::cerr << "[" << i << "/" << (project->entries.size() - 1) << "] Failed whitelist check \"" << is_bad->regex_string << "\"; skipping " << filepath << std::endl;
continue;
}
for (const Matcher& m : blacklist) {
if (m.IsMatch(filepath)) {
is_bad = &m;
break;
}
}
if (is_bad) {
std::cerr << "[" << i << "/" << (project->entries.size() - 1) << "] Failed blacklist check \"" << is_bad->regex_string << "\"; skipping " << filepath << std::endl;
continue;
}
project->ForAllFilteredFiles(config, [&](int i, const Project::Entry& entry) {
std::cerr << "[" << i << "/" << (project->entries.size() - 1) std::cerr << "[" << i << "/" << (project->entries.size() - 1)
<< "] Dispatching index request for file " << filepath << "] Dispatching index request for file " << entry.filename
<< std::endl; << std::endl;
queue_do_index->Enqueue(Index_DoIndex(Index_DoIndex::Type::ImportAndUpdate, filepath, entry.args)); queue_do_index->Enqueue(Index_DoIndex(Index_DoIndex::Type::ImportAndUpdate, entry.filename, entry.args));
} });
break;
}
case IpcId::CqueryFreshenIndex: {
std::cerr << "Freshening " << project->entries.size() << " files" << std::endl;
project->ForAllFilteredFiles(config, [&](int i, const Project::Entry& entry) {
std::cerr << "[" << i << "/" << (project->entries.size() - 1)
<< "] Dispatching index request for file " << entry.filename
<< std::endl;
queue_do_index->Enqueue(Index_DoIndex(Index_DoIndex::Type::Freshen, entry.filename, entry.args));
});
break; break;
} }
@ -1876,7 +1870,8 @@ void LanguageServerStdinLoop(IndexerConfig* config) {
case IpcId::TextDocumentReferences: case IpcId::TextDocumentReferences:
case IpcId::TextDocumentDocumentSymbol: case IpcId::TextDocumentDocumentSymbol:
case IpcId::TextDocumentCodeLens: case IpcId::TextDocumentCodeLens:
case IpcId::WorkspaceSymbol: { case IpcId::WorkspaceSymbol:
case IpcId::CqueryFreshenIndex: {
ipc->SendMessage(IpcManager::Destination::Server, std::move(message)); ipc->SendMessage(IpcManager::Destination::Server, std::move(message));
break; break;
} }

View File

@ -465,7 +465,7 @@ struct IdCache {
struct IndexedFile { struct IndexedFile {
IdCache id_cache; IdCache id_cache;
static constexpr int kCurrentVersion = 1; static constexpr int kCurrentVersion = 2;
int version = 0; int version = 0;
std::string path; std::string path;

View File

@ -39,6 +39,9 @@ const char* IpcIdToString(IpcId id) {
case IpcId::WorkspaceSymbol: case IpcId::WorkspaceSymbol:
return "workspace/symbol"; return "workspace/symbol";
case IpcId::CqueryFreshenIndex: {
return "$cquery/freshenIndex";
}
case IpcId::Quit: case IpcId::Quit:
return "$quit"; return "$quit";

View File

@ -25,6 +25,9 @@ enum class IpcId : int {
CodeLensResolve, CodeLensResolve,
WorkspaceSymbol, WorkspaceSymbol,
// Custom messages
CqueryFreshenIndex,
// Internal implementation detail. // Internal implementation detail.
Quit, Quit,
IsAlive, IsAlive,

View File

@ -1340,7 +1340,7 @@ struct lsWorkspaceSymbolParams {
std::string query; std::string query;
}; };
MAKE_REFLECT_STRUCT(lsWorkspaceSymbolParams, query); MAKE_REFLECT_STRUCT(lsWorkspaceSymbolParams, query);
struct Ipc_WorkspaceSymbol : public IpcMessage<Ipc_WorkspaceSymbol > { struct Ipc_WorkspaceSymbol : public IpcMessage<Ipc_WorkspaceSymbol> {
const static IpcId kIpcId = IpcId::WorkspaceSymbol; const static IpcId kIpcId = IpcId::WorkspaceSymbol;
lsRequestId id; lsRequestId id;
lsWorkspaceSymbolParams params; lsWorkspaceSymbolParams params;
@ -1381,4 +1381,11 @@ void Reflect(TVisitor& visitor, Out_ShowLogMessage& value) {
REFLECT_MEMBER2("method", value.method()); REFLECT_MEMBER2("method", value.method());
REFLECT_MEMBER(params); REFLECT_MEMBER(params);
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
struct Ipc_CqueryFreshenIndex : public IpcMessage<Ipc_CqueryFreshenIndex> {
const static IpcId kIpcId = IpcId::CqueryFreshenIndex;
lsRequestId id;
};
MAKE_REFLECT_STRUCT(Ipc_CqueryFreshenIndex, id);

View File

@ -1,5 +1,6 @@
#include "project.h" #include "project.h"
#include "fuzzy.h"
#include "libclangmm/Utility.h" #include "libclangmm/Utility.h"
#include "platform.h" #include "platform.h"
#include "serializer.h" #include "serializer.h"
@ -261,4 +262,51 @@ optional<std::vector<std::string>> Project::FindArgsForFile(const std::string& f
if (!entry) if (!entry)
return nullopt; return nullopt;
return entry->args; return entry->args;
} }
void Project::ForAllFilteredFiles(IndexerConfig* config, std::function<void(int i, const Entry& entry)> action) {
std::vector<Matcher> whitelist;
std::cerr << "Using whitelist" << std::endl;
for (const std::string& entry : config->whitelist) {
std::cerr << " - " << entry << std::endl;
whitelist.push_back(Matcher(entry));
}
std::vector<Matcher> blacklist;
std::cerr << "Using blacklist" << std::endl;
for (const std::string& entry : config->blacklist) {
std::cerr << " - " << entry << std::endl;
blacklist.push_back(Matcher(entry));
}
for (int i = 0; i < entries.size(); ++i) {
const Project::Entry& entry = entries[i];
std::string filepath = entry.filename;
const Matcher* is_bad = nullptr;
for (const Matcher& m : whitelist) {
if (!m.IsMatch(filepath)) {
is_bad = &m;
break;
}
}
if (is_bad) {
std::cerr << "[" << i << "/" << (entries.size() - 1) << "] Failed whitelist check \"" << is_bad->regex_string << "\"; skipping " << filepath << std::endl;
continue;
}
for (const Matcher& m : blacklist) {
if (m.IsMatch(filepath)) {
is_bad = &m;
break;
}
}
if (is_bad) {
std::cerr << "[" << i << "/" << (entries.size() - 1) << "] Failed blacklist check \"" << is_bad->regex_string << "\"; skipping " << filepath << std::endl;
continue;
}
action(i, entries[i]);
}
}

View File

@ -1,8 +1,11 @@
#pragma once #pragma once
#include "language_server_api.h"
#include <optional.h> #include <optional.h>
#include <sparsepp/spp.h> #include <sparsepp/spp.h>
#include <functional>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <vector> #include <vector>
@ -32,5 +35,7 @@ struct Project {
// Helper that uses FindCompilationEntryForFile. // Helper that uses FindCompilationEntryForFile.
optional<std::vector<std::string>> FindArgsForFile(const std::string& filename); optional<std::vector<std::string>> FindArgsForFile(const std::string& filename);
void ForAllFilteredFiles(IndexerConfig* config, std::function<void(int i, const Entry& entry)> action);
}; };