Group initialization options and rename $cquery/typeHierarchyTree to $cquery/inheritanceHierarchy

This commit is contained in:
Fangrui Song 2018-02-21 21:50:36 -08:00
parent 20d1636024
commit 702cdbe9bb
12 changed files with 153 additions and 151 deletions

View File

@ -332,7 +332,7 @@ void LaunchStdinLoop(Config* config,
case IpcId::WorkspaceSymbol:
case IpcId::CqueryFileInfo:
case IpcId::CqueryFreshenIndex:
case IpcId::CqueryTypeHierarchyTree:
case IpcId::CqueryInheritanceHierarchy:
case IpcId::CqueryCallTreeInitial:
case IpcId::CqueryCallTreeExpand:
case IpcId::CqueryMemberHierarchyInitial:

View File

@ -18,7 +18,7 @@ The language client plugin needs to send initialization options in the
If necessary, the command line option --init can be used to override
initialization options specified by the client. For example, in shell syntax:
'--init={"indexWhitelist": ["."], "index": {"comments": 2}}'
'--init={"index": {"comments": 2, "whitelist": ["."]}}'
*/
struct Config {
// Root directory of the project. **Not available for configuration**
@ -56,31 +56,6 @@ struct Config {
// Additional arguments to pass to clang.
std::vector<std::string> extraClangArguments;
// If a translation unit's absolute path matches any EMCAScript regex in the
// whitelist, or does not match any regex in the blacklist, it will be indexed.
// To only index files in the whitelist, add ".*" to the blacklist.
// `std::regex_search(path, regex, std::regex_constants::match_any)`
//
// Example: `ash/.*\.cc`
std::vector<std::string> indexWhitelist;
std::vector<std::string> indexBlacklist;
// If true, project paths that were skipped by the whitelist/blacklist will
// be logged.
bool logSkippedPathsForIndex = false;
// Maximum workspace search results.
int maxWorkspaceSearchResults = 500;
// If true, workspace search results will be dynamically rescored/reordered
// as the search progresses. Some clients do their own ordering and assume
// that the results stay sorted in the same order as the search progresses.
bool sortWorkspaceSearchResults = true;
// Force a certain number of indexer threads. If less than 1 a default value
// is be used (80% number of CPU cores).
int indexerCount = 0;
// If false, the indexer will be disabled.
bool enableIndexing = true;
// If true, cquery will send progress reports while indexing
// How often should cquery send progress report messages?
// -1: never
@ -97,31 +72,8 @@ struct Config {
// If true, document links are reported for #include directives.
bool showDocumentLinksOnIncludes = true;
// Maximum path length to show in completion results. Paths longer than this
// will be elided with ".." put at the front. Set to 0 or a negative number
// to disable eliding.
int includeCompletionMaximumPathLength = 30;
// Whitelist that file paths will be tested against. If a file path does not
// end in one of these values, it will not be considered for auto-completion.
// An example value is { ".h", ".hpp" }
//
// This is significantly faster than using a regex.
std::vector<std::string> includeCompletionWhitelistLiteralEnding = {
".h", ".hpp", ".hh"};
// Regex patterns to match include completion candidates against. They
// receive the absolute file path.
//
// For example, to hide all files in a /CACHE/ folder, use ".*/CACHE/.*"
std::vector<std::string> includeCompletionWhitelist;
std::vector<std::string> includeCompletionBlacklist;
// If true, diagnostics from a full document parse will be reported.
bool diagnosticsOnParse = true;
// If true, diagnostics from code completion will be reported.
bool diagnosticsOnCodeCompletion = true;
// Enables code lens on parameter and function variables.
bool codeLensOnLocalVariables = 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.
@ -133,14 +85,12 @@ struct Config {
};
ClientCapability client;
struct Completion {
// If true, filter and sort completion response. cquery filters and sorts
// completions to try to be nicer to clients that can't handle big numbers
// of completion candidates. This behaviour can be disabled by specifying
// false for the option. This option is the most useful for LSP clients
// that implement their own filtering and sorting logic.
bool filterAndSort = true;
struct CodeLens {
// Enables code lens on parameter and function variables.
bool localVariables = true;
} codeLens;
struct Completion {
// Some completion UI, such as Emacs' completion-at-point and company-lsp,
// display completion item label and detail side by side.
// This does not look right, when you see things like:
@ -159,25 +109,36 @@ struct Config {
// Be wary, this is quickly quite verbose,
// items can end up truncated by the UIs.
bool detailedLabel = false;
};
Completion completion;
struct Xref {
// If true, |Location[]| response will include lexical container.
bool container = false;
// Maximum number of definition/reference/... results.
int maxNum = 300;
};
Xref xref;
// If true, filter and sort completion response. cquery filters and sorts
// completions to try to be nicer to clients that can't handle big numbers
// of completion candidates. This behaviour can be disabled by specifying
// false for the option. This option is the most useful for LSP clients
// that implement their own filtering and sorting logic.
bool filterAndSort = true;
// Regex patterns to match include completion candidates against. They
// receive the absolute file path.
//
// For example, to hide all files in a /CACHE/ folder, use ".*/CACHE/.*"
std::vector<std::string> includeBlacklist;
// Maximum path length to show in completion results. Paths longer than this
// will be elided with ".." put at the front. Set to 0 or a negative number
// to disable eliding.
int includeMaxPathSize = 30;
// Whitelist that file paths will be tested against. If a file path does not
// end in one of these values, it will not be considered for auto-completion.
// An example value is { ".h", ".hpp" }
//
// This is significantly faster than using a regex.
std::vector<std::string> includeSuffixWhitelist = {".h", ".hpp", ".hh"};
std::vector<std::string> includeWhitelist;
} completion;
struct Index {
// 0: none, 1: doxygen, 2: all comments
// Plugin support for clients:
// - https://github.com/emacs-lsp/lsp-ui
// - https://github.com/emacs-lsp/lsp-mode/pull/224
// - https://github.com/autozimu/LanguageClient-neovim/issues/224
int comments = 2;
// Attempt to convert calls of make* functions to constructors based on
// hueristics.
//
@ -185,8 +146,49 @@ struct Config {
// invocations. Specifically, cquery will try to attribute a ctor call
// whenever the function name starts with make (ignoring case).
bool attributeMakeCallsToCtor = true;
};
Index index;
// If a translation unit's absolute path matches any EMCAScript regex in the
// whitelist, or does not match any regex in the blacklist, it will be indexed.
// To only index files in the whitelist, add ".*" to the blacklist.
// `std::regex_search(path, regex, std::regex_constants::match_any)`
//
// Example: `ash/.*\.cc`
std::vector<std::string> blacklist;
// 0: none, 1: Doxygen, 2: all comments
// Plugin support for clients:
// - https://github.com/emacs-lsp/lsp-ui
// - https://github.com/autozimu/LanguageClient-neovim/issues/224
int comments = 2;
// If false, the indexer will be disabled.
bool enabled = true;
// If true, project paths that were skipped by the whitelist/blacklist will
// be logged.
bool logSkippedPaths = false;
// Number of indexer threads. If 0, 80% of cores are used.
int threads = 0;
std::vector<std::string> whitelist;
} index;
struct WorkspaceSymbol {
// Maximum workspace search results.
int maxNum = 1000;
// If true, workspace search results will be dynamically rescored/reordered
// as the search progresses. Some clients do their own ordering and assume
// that the results stay sorted in the same order as the search progresses.
bool sort = true;
} workspaceSymbol;
struct Xref {
// If true, |Location[]| response will include lexical container.
bool container = false;
// Maximum number of definition/reference/... results.
int maxNum = 2000;
} xref;
//// For debugging
@ -194,9 +196,24 @@ struct Config {
std::vector<std::string> dumpAST;
};
MAKE_REFLECT_STRUCT(Config::ClientCapability, snippetSupport);
MAKE_REFLECT_STRUCT(Config::Completion, filterAndSort, detailedLabel);
MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables);
MAKE_REFLECT_STRUCT(Config::Completion,
detailedLabel,
filterAndSort,
includeBlacklist,
includeMaxPathSize,
includeSuffixWhitelist,
includeWhitelist);
MAKE_REFLECT_STRUCT(Config::Index,
attributeMakeCallsToCtor,
blacklist,
comments,
enabled,
logSkippedPaths,
threads,
whitelist);
MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, maxNum, sort);
MAKE_REFLECT_STRUCT(Config::Xref, container, maxNum);
MAKE_REFLECT_STRUCT(Config::Index, comments, attributeMakeCallsToCtor);
MAKE_REFLECT_STRUCT(Config,
compilationDatabaseCommand,
compilationDatabaseDirectory,
@ -206,35 +223,20 @@ MAKE_REFLECT_STRUCT(Config,
extraClangArguments,
indexWhitelist,
indexBlacklist,
logSkippedPathsForIndex,
maxWorkspaceSearchResults,
sortWorkspaceSearchResults,
indexerCount,
enableIndexing,
progressReportFrequencyMs,
includeCompletionMaximumPathLength,
includeCompletionWhitelistLiteralEnding,
includeCompletionWhitelist,
includeCompletionBlacklist,
showDocumentLinksOnIncludes,
diagnosticsOnParse,
diagnosticsOnCodeCompletion,
codeLensOnLocalVariables,
clientVersion,
client,
codeLens,
completion,
xref,
index,
workspaceSymbol,
xref,
dumpAST);

View File

@ -352,7 +352,7 @@ void ParseFile(Config* config,
entry.args, file_contents, &perf);
if (!indexes) {
if (config->enableIndexing &&
if (config->index.enabled &&
!std::holds_alternative<std::monostate>(request.id)) {
Out_Error out;
out.id = request.id;

View File

@ -17,13 +17,13 @@ struct CompletionCandidate {
};
std::string ElideLongPath(Config* config, const std::string& path) {
if (config->includeCompletionMaximumPathLength <= 0)
if (config->completion.includeMaxPathSize <= 0)
return path;
if ((int)path.size() <= config->includeCompletionMaximumPathLength)
if ((int)path.size() <= config->completion.includeMaxPathSize)
return path;
size_t start = path.size() - config->includeCompletionMaximumPathLength;
size_t start = path.size() - config->completion.includeMaxPathSize;
return ".." + path.substr(start + 2);
}
@ -110,10 +110,10 @@ void IncludeComplete::Rescan() {
absolute_path_to_completion_item.clear();
inserted_paths.clear();
if (!match_ && (!config_->includeCompletionWhitelist.empty() ||
!config_->includeCompletionBlacklist.empty()))
match_ = MakeUnique<GroupMatch>(config_->includeCompletionWhitelist,
config_->includeCompletionBlacklist);
if (!match_ && (!config_->completion.includeWhitelist.empty() ||
!config_->completion.includeBlacklist.empty()))
match_ = MakeUnique<GroupMatch>(config_->completion.includeWhitelist,
config_->completion.includeBlacklist);
is_scanning = true;
WorkThread::StartThread("scan_includes", [this]() {
@ -151,7 +151,7 @@ void IncludeComplete::InsertCompletionItem(const std::string& absolute_path,
void IncludeComplete::AddFile(const std::string& absolute_path) {
if (!EndsWithAny(absolute_path,
config_->includeCompletionWhitelistLiteralEnding))
config_->completion.includeSuffixWhitelist))
return;
if (match_ && !match_->IsMatch(absolute_path))
return;
@ -184,7 +184,7 @@ void IncludeComplete::InsertIncludesFromDirectory(std::string directory,
directory, true /*recursive*/, false /*add_folder_to_path*/,
[&](const std::string& path) {
if (!EndsWithAny(path,
config_->includeCompletionWhitelistLiteralEnding))
config_->completion.includeSuffixWhitelist))
return;
if (match_ && !match_->IsMatch(directory + path))
return;

View File

@ -2195,7 +2195,7 @@ optional<std::vector<std::unique_ptr<IndexFile>>> Parse(
PerformanceImportFile* perf,
ClangIndex* index,
bool dump_ast) {
if (!config->enableIndexing)
if (!config->index.enabled)
return nullopt;
file = NormalizePath(file);

View File

@ -70,8 +70,8 @@ const char* IpcIdToString(IpcId id) {
return "$cquery/fileInfo";
case IpcId::CqueryFreshenIndex:
return "$cquery/freshenIndex";
case IpcId::CqueryTypeHierarchyTree:
return "$cquery/typeHierarchyTree";
case IpcId::CqueryInheritanceHierarchy:
return "$cquery/inheritanceHierarchy";
case IpcId::CqueryCallTreeInitial:
return "$cquery/callTreeInitial";
case IpcId::CqueryCallTreeExpand:

View File

@ -48,7 +48,7 @@ enum class IpcId : int {
CqueryFileInfo,
CqueryFreshenIndex,
// Messages used in tree views.
CqueryTypeHierarchyTree,
CqueryInheritanceHierarchy,
CqueryCallTreeInitial,
CqueryCallTreeExpand,
CqueryMemberHierarchyInitial,

View File

@ -3,16 +3,16 @@
#include "queue_manager.h"
namespace {
struct Ipc_CqueryTypeHierarchyTree
: public RequestMessage<Ipc_CqueryTypeHierarchyTree> {
const static IpcId kIpcId = IpcId::CqueryTypeHierarchyTree;
struct Ipc_CqueryInheritanceHierarchy
: public RequestMessage<Ipc_CqueryInheritanceHierarchy> {
const static IpcId kIpcId = IpcId::CqueryInheritanceHierarchy;
lsTextDocumentPositionParams params;
};
MAKE_REFLECT_STRUCT(Ipc_CqueryTypeHierarchyTree, id, params);
REGISTER_IPC_MESSAGE(Ipc_CqueryTypeHierarchyTree);
MAKE_REFLECT_STRUCT(Ipc_CqueryInheritanceHierarchy, id, params);
REGISTER_IPC_MESSAGE(Ipc_CqueryInheritanceHierarchy);
struct Out_CqueryTypeHierarchyTree
: public lsOutMessage<Out_CqueryTypeHierarchyTree> {
struct Out_CqueryInheritanceHierarchy
: public lsOutMessage<Out_CqueryInheritanceHierarchy> {
struct TypeEntry {
std::string_view name;
optional<lsLocation> location;
@ -21,22 +21,22 @@ struct Out_CqueryTypeHierarchyTree
lsRequestId id;
optional<TypeEntry> result;
};
MAKE_REFLECT_STRUCT(Out_CqueryTypeHierarchyTree::TypeEntry,
MAKE_REFLECT_STRUCT(Out_CqueryInheritanceHierarchy::TypeEntry,
name,
location,
children);
MAKE_REFLECT_STRUCT(Out_CqueryTypeHierarchyTree, jsonrpc, id, result);
MAKE_REFLECT_STRUCT(Out_CqueryInheritanceHierarchy, jsonrpc, id, result);
std::vector<Out_CqueryTypeHierarchyTree::TypeEntry>
std::vector<Out_CqueryInheritanceHierarchy::TypeEntry>
BuildParentInheritanceHierarchyForType(QueryDatabase* db,
WorkingFiles* working_files,
QueryType& root_type) {
std::vector<Out_CqueryTypeHierarchyTree::TypeEntry> parent_entries;
std::vector<Out_CqueryInheritanceHierarchy::TypeEntry> parent_entries;
const QueryType::Def* def = root_type.AnyDef();
parent_entries.reserve(def->parents.size());
EachDefinedEntity(db->types, def->parents, [&](QueryType& parent_type) {
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
Out_CqueryInheritanceHierarchy::TypeEntry parent_entry;
const QueryType::Def* def1 = parent_type.AnyDef();
parent_entry.name = def1->detailed_name.c_str();
if (def1->spell)
@ -50,11 +50,11 @@ BuildParentInheritanceHierarchyForType(QueryDatabase* db,
return parent_entries;
}
optional<Out_CqueryTypeHierarchyTree::TypeEntry>
optional<Out_CqueryInheritanceHierarchy::TypeEntry>
BuildInheritanceHierarchyForType(QueryDatabase* db,
WorkingFiles* working_files,
QueryType& root_type) {
Out_CqueryTypeHierarchyTree::TypeEntry entry;
Out_CqueryInheritanceHierarchy::TypeEntry entry;
const QueryType::Def* def = root_type.AnyDef();
// Name and location.
@ -65,7 +65,7 @@ BuildInheritanceHierarchyForType(QueryDatabase* db,
entry.children.reserve(root_type.derived.size());
// Base types.
Out_CqueryTypeHierarchyTree::TypeEntry base;
Out_CqueryInheritanceHierarchy::TypeEntry base;
base.name = "[[Base]]";
base.location = entry.location;
base.children =
@ -84,11 +84,11 @@ BuildInheritanceHierarchyForType(QueryDatabase* db,
return entry;
}
std::vector<Out_CqueryTypeHierarchyTree::TypeEntry>
std::vector<Out_CqueryInheritanceHierarchy::TypeEntry>
BuildParentInheritanceHierarchyForFunc(QueryDatabase* db,
WorkingFiles* working_files,
QueryFuncId root) {
std::vector<Out_CqueryTypeHierarchyTree::TypeEntry> entries;
std::vector<Out_CqueryInheritanceHierarchy::TypeEntry> entries;
QueryFunc& root_func = db->funcs[root.id];
const QueryFunc::Def* def = root_func.AnyDef();
@ -101,7 +101,7 @@ BuildParentInheritanceHierarchyForFunc(QueryDatabase* db,
if (!def1)
continue;
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
Out_CqueryInheritanceHierarchy::TypeEntry parent_entry;
parent_entry.name = def1->detailed_name;
if (def1->spell)
parent_entry.location = GetLsLocation(db, working_files, *def1->spell);
@ -114,7 +114,7 @@ BuildParentInheritanceHierarchyForFunc(QueryDatabase* db,
return entries;
}
optional<Out_CqueryTypeHierarchyTree::TypeEntry>
optional<Out_CqueryInheritanceHierarchy::TypeEntry>
BuildInheritanceHierarchyForFunc(QueryDatabase* db,
WorkingFiles* working_files,
QueryFuncId root_id) {
@ -123,7 +123,7 @@ BuildInheritanceHierarchyForFunc(QueryDatabase* db,
if (!def)
return nullopt;
Out_CqueryTypeHierarchyTree::TypeEntry entry;
Out_CqueryInheritanceHierarchy::TypeEntry entry;
// Name and location.
entry.name = def->detailed_name;
@ -134,7 +134,7 @@ BuildInheritanceHierarchyForFunc(QueryDatabase* db,
entry.children.reserve(root_func.derived.size());
// Base types.
Out_CqueryTypeHierarchyTree::TypeEntry base;
Out_CqueryInheritanceHierarchy::TypeEntry base;
base.name = "[[Base]]";
base.location = entry.location;
base.children =
@ -153,9 +153,9 @@ BuildInheritanceHierarchyForFunc(QueryDatabase* db,
return entry;
}
struct CqueryTypeHierarchyTreeHandler
: BaseMessageHandler<Ipc_CqueryTypeHierarchyTree> {
void Run(Ipc_CqueryTypeHierarchyTree* request) override {
struct CqueryInheritanceHierarchyHandler
: BaseMessageHandler<Ipc_CqueryInheritanceHierarchy> {
void Run(Ipc_CqueryInheritanceHierarchy* request) override {
QueryFile* file;
if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file))
@ -164,7 +164,7 @@ struct CqueryTypeHierarchyTreeHandler
WorkingFile* working_file =
working_files->GetFileByFilename(file->def->path);
Out_CqueryTypeHierarchyTree out;
Out_CqueryInheritanceHierarchy out;
out.id = request->id;
for (const SymbolRef& sym :
@ -183,8 +183,8 @@ struct CqueryTypeHierarchyTreeHandler
}
}
QueueManager::WriteStdout(IpcId::CqueryTypeHierarchyTree, out);
QueueManager::WriteStdout(IpcId::CqueryInheritanceHierarchy, out);
}
};
REGISTER_MESSAGE_HANDLER(CqueryTypeHierarchyTreeHandler);
REGISTER_MESSAGE_HANDLER(CqueryInheritanceHierarchyHandler);
} // namespace

View File

@ -590,17 +590,17 @@ struct InitializeHandler : BaseMessageHandler<Ipc_InitializeRequest> {
// Start indexer threads. Start this after loading the project, as that
// may take a long time. Indexer threads will emit status/progress
// reports.
if (config->indexerCount == 0) {
if (config->index.threads == 0) {
// If the user has not specified how many indexers to run, try to
// guess an appropriate value. Default to 80% utilization.
const float kDefaultTargetUtilization = 0.8f;
config->indexerCount = (int)(std::thread::hardware_concurrency() *
config->index.threads = (int)(std::thread::hardware_concurrency() *
kDefaultTargetUtilization);
if (config->indexerCount <= 0)
config->indexerCount = 1;
if (config->index.threads <= 0)
config->index.threads = 1;
}
LOG_S(INFO) << "Starting " << config->indexerCount << " indexers";
for (int i = 0; i < config->indexerCount; ++i) {
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,

View File

@ -246,7 +246,7 @@ struct TextDocumentCodeLensHandler
case SymbolKind::Var: {
QueryVar& var = db->GetVar(sym);
const QueryVar::Def* def = var.AnyDef();
if (!def || (def->is_local() && !config->codeLensOnLocalVariables))
if (!def || (def->is_local() && !config->codeLens.localVariables))
continue;
bool force_display = true;

View File

@ -76,8 +76,8 @@ struct WorkspaceSymbolHandler : BaseMessageHandler<Ipc_WorkspaceSymbol> {
// db->detailed_names indices of each lsSymbolInformation in out.result
std::vector<int> result_indices;
std::vector<lsSymbolInformation> unsorted_results;
inserted_results.reserve(config->maxWorkspaceSearchResults);
result_indices.reserve(config->maxWorkspaceSearchResults);
inserted_results.reserve(config->workspaceSymbol.maxNum);
result_indices.reserve(config->workspaceSymbol.maxNum);
// We use detailed_names without parameters for matching.
@ -92,14 +92,14 @@ struct WorkspaceSymbolHandler : BaseMessageHandler<Ipc_WorkspaceSymbol> {
if (InsertSymbolIntoResult(db, working_files, db->symbols[i],
&unsorted_results)) {
result_indices.push_back(i);
if (unsorted_results.size() >= config->maxWorkspaceSearchResults)
if (unsorted_results.size() >= config->workspaceSymbol.maxNum)
break;
}
}
}
// Find subsequence matches.
if (unsorted_results.size() < config->maxWorkspaceSearchResults) {
if (unsorted_results.size() < config->workspaceSymbol.maxNum) {
std::string query_without_space;
query_without_space.reserve(query.size());
for (char c : query)
@ -116,14 +116,14 @@ struct WorkspaceSymbolHandler : BaseMessageHandler<Ipc_WorkspaceSymbol> {
if (InsertSymbolIntoResult(db, working_files, db->symbols[i],
&unsorted_results)) {
result_indices.push_back(i);
if (unsorted_results.size() >= config->maxWorkspaceSearchResults)
if (unsorted_results.size() >= config->workspaceSymbol.maxNum)
break;
}
}
}
}
if (config->sortWorkspaceSearchResults) {
if (config->workspaceSymbol.sort) {
// Sort results with a fuzzy matching algorithm.
int longest = 0;
for (int i : result_indices)

View File

@ -598,14 +598,14 @@ Project::Entry Project::FindCompilationEntryForFile(
void Project::ForAllFilteredFiles(
Config* config,
std::function<void(int i, const Entry& entry)> action) {
GroupMatch matcher(config->indexWhitelist, config->indexBlacklist);
GroupMatch matcher(config->index.whitelist, config->index.blacklist);
for (int i = 0; i < entries.size(); ++i) {
const Project::Entry& entry = entries[i];
std::string failure_reason;
if (matcher.IsMatch(entry.filename, &failure_reason))
action(i, entries[i]);
else {
if (config->logSkippedPathsForIndex) {
if (config->index.logSkippedPaths) {
LOG_S(INFO) << "[" << i + 1 << "/" << entries.size() << "]: Failed "
<< failure_reason << "; skipping " << entry.filename;
}