Reduce structs in language_server_api.h and clarify query_utils.h

This commit is contained in:
Fangrui Song 2018-02-23 15:27:21 -08:00
parent b98c9a4575
commit 411d49951d
22 changed files with 244 additions and 245 deletions

View File

@ -3,7 +3,7 @@
#include "atomic_object.h"
#include "clang_index.h"
#include "clang_translation_unit.h"
#include "language_server_api.h"
#include "language_server_api_completion.h"
#include "lru_cache.h"
#include "project.h"
#include "threaded_queue.h"

View File

@ -1,6 +1,6 @@
#pragma once
#include "language_server_api.h"
#include "language_server_api_completion.h"
#include <optional.h>
@ -19,4 +19,4 @@ struct CodeCompleteCache {
void WithLock(std::function<void()> action);
bool IsCacheValid(lsTextDocumentPositionParams position);
};
};

View File

@ -23,6 +23,27 @@
namespace {
struct Out_Progress : public lsOutMessage<Out_Progress> {
struct Params {
int indexRequestCount = 0;
int doIdMapCount = 0;
int loadPreviousIndexCount = 0;
int onIdMappedCount = 0;
int onIndexedCount = 0;
int activeThreads = 0;
};
std::string method = "$cquery/progress";
Params params;
};
MAKE_REFLECT_STRUCT(Out_Progress::Params,
indexRequestCount,
doIdMapCount,
loadPreviousIndexCount,
onIdMappedCount,
onIndexedCount,
activeThreads);
MAKE_REFLECT_STRUCT(Out_Progress, jsonrpc, method, params);
struct IModificationTimestampFetcher {
virtual ~IModificationTimestampFetcher() = default;
virtual optional<int64_t> GetModificationTime(const std::string& path) = 0;

View File

@ -1,6 +1,6 @@
#pragma once
#include "language_server_api.h"
#include "language_server_api_completion.h"
#include <atomic>
#include <mutex>

View File

@ -322,14 +322,6 @@ bool lsTextEdit::operator==(const lsTextEdit& that) {
return range == that.range && newText == that.newText;
}
const std::string& lsCompletionItem::InsertedContent() const {
if (textEdit)
return textEdit->newText;
if (!insertText.empty())
return insertText;
return label;
}
std::string Out_ShowLogMessage::method() {
if (display_type == DisplayType::Log)
return "window/logMessage";

View File

@ -247,136 +247,6 @@ struct lsTextEdit {
};
MAKE_REFLECT_STRUCT(lsTextEdit, range, newText);
// Defines whether the insert text in a completion item should be interpreted as
// plain text or a snippet.
enum class lsInsertTextFormat {
// The primary text to be inserted is treated as a plain string.
PlainText = 1,
// The primary text to be inserted is treated as a snippet.
//
// A snippet can define tab stops and placeholders with `$1`, `$2`
// and `${3:foo}`. `$0` defines the final tab stop, it defaults to
// the end of the snippet. Placeholders with equal identifiers are linked,
// that is typing in one will update others too.
//
// See also:
// https://github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/common/snippet.md
Snippet = 2
};
MAKE_REFLECT_TYPE_PROXY(lsInsertTextFormat);
// The kind of a completion entry.
enum class lsCompletionItemKind {
Text = 1,
Method = 2,
Function = 3,
Constructor = 4,
Field = 5,
Variable = 6,
Class = 7,
Interface = 8,
Module = 9,
Property = 10,
Unit = 11,
Value = 12,
Enum = 13,
Keyword = 14,
Snippet = 15,
Color = 16,
File = 17,
Reference = 18,
Folder = 19,
EnumMember = 20,
Constant = 21,
Struct = 22,
Event = 23,
Operator = 24,
TypeParameter = 25,
};
MAKE_REFLECT_TYPE_PROXY(lsCompletionItemKind);
struct lsCompletionItem {
// A set of function parameters. Used internally for signature help. Not sent
// to vscode.
std::vector<std::string> parameters_;
// The label of this completion item. By default
// also the text that is inserted when selecting
// this completion.
std::string label;
// The kind of this completion item. Based of the kind
// an icon is chosen by the editor.
lsCompletionItemKind kind = lsCompletionItemKind::Text;
// A human-readable string with additional information
// about this item, like type or symbol information.
std::string detail;
// A human-readable string that represents a doc-comment.
optional<std::string> documentation;
// Internal information to order candidates.
bool found_;
std::string::size_type skip_;
unsigned priority_;
// Use <> or "" by default as include path.
bool use_angle_brackets_ = false;
// A string that shoud be used when comparing this item
// with other items. When `falsy` the label is used.
std::string sortText;
// A string that should be used when filtering a set of
// completion items. When `falsy` the label is used.
optional<std::string> filterText;
// A string that should be inserted a document when selecting
// this completion. When `falsy` the label is used.
std::string insertText;
// The format of the insert text. The format applies to both the `insertText`
// property and the `newText` property of a provided `textEdit`.
lsInsertTextFormat insertTextFormat = lsInsertTextFormat::PlainText;
// An edit which is applied to a document when selecting this completion. When
// an edit is provided the value of `insertText` is ignored.
//
// *Note:* The range of the edit must be a single line range and it must
// contain the position at which completion has been requested.
optional<lsTextEdit> textEdit;
// An optional array of additional text edits that are applied when
// selecting this completion. Edits must not overlap with the main edit
// nor with themselves.
// std::vector<TextEdit> additionalTextEdits;
// An optional command that is executed *after* inserting this completion.
// *Note* that additional modifications to the current document should be
// described with the additionalTextEdits-property. Command command;
// An data entry field that is preserved on a completion item between
// a completion and a completion resolve request.
// data ? : any
// Use this helper to figure out what content the completion item will insert
// into the document, as it could live in either |textEdit|, |insertText|, or
// |label|.
const std::string& InsertedContent() const;
};
MAKE_REFLECT_STRUCT(lsCompletionItem,
label,
kind,
detail,
documentation,
sortText,
insertText,
filterText,
insertTextFormat,
textEdit);
struct lsTextDocumentItem {
// The text document's URI.
lsDocumentUri uri;
@ -589,39 +459,6 @@ void Reflect(TVisitor& visitor, Out_ShowLogMessage& value) {
REFLECT_MEMBER_END();
}
struct Out_Progress : public lsOutMessage<Out_Progress> {
struct Params {
int indexRequestCount = 0;
int doIdMapCount = 0;
int loadPreviousIndexCount = 0;
int onIdMappedCount = 0;
int onIndexedCount = 0;
int activeThreads = 0;
};
std::string method = "$cquery/progress";
Params params;
};
MAKE_REFLECT_STRUCT(Out_Progress::Params,
indexRequestCount,
doIdMapCount,
loadPreviousIndexCount,
onIdMappedCount,
onIndexedCount,
activeThreads);
MAKE_REFLECT_STRUCT(Out_Progress, jsonrpc, method, params);
struct Out_CquerySetInactiveRegion
: public lsOutMessage<Out_CquerySetInactiveRegion> {
struct Params {
lsDocumentUri uri;
std::vector<lsRange> inactiveRegions;
};
std::string method = "$cquery/setInactiveRegions";
Params params;
};
MAKE_REFLECT_STRUCT(Out_CquerySetInactiveRegion::Params, uri, inactiveRegions);
MAKE_REFLECT_STRUCT(Out_CquerySetInactiveRegion, jsonrpc, method, params);
struct Out_LocationList : public lsOutMessage<Out_LocationList> {
lsRequestId id;
std::vector<lsLocationEx> result;

View File

@ -0,0 +1,138 @@
#pragma once
#include "language_server_api.h"
// The kind of a completion entry.
enum class lsCompletionItemKind {
Text = 1,
Method = 2,
Function = 3,
Constructor = 4,
Field = 5,
Variable = 6,
Class = 7,
Interface = 8,
Module = 9,
Property = 10,
Unit = 11,
Value = 12,
Enum = 13,
Keyword = 14,
Snippet = 15,
Color = 16,
File = 17,
Reference = 18,
Folder = 19,
EnumMember = 20,
Constant = 21,
Struct = 22,
Event = 23,
Operator = 24,
TypeParameter = 25,
};
MAKE_REFLECT_TYPE_PROXY(lsCompletionItemKind);
// Defines whether the insert text in a completion item should be interpreted as
// plain text or a snippet.
enum class lsInsertTextFormat {
// The primary text to be inserted is treated as a plain string.
PlainText = 1,
// The primary text to be inserted is treated as a snippet.
//
// A snippet can define tab stops and placeholders with `$1`, `$2`
// and `${3:foo}`. `$0` defines the final tab stop, it defaults to
// the end of the snippet. Placeholders with equal identifiers are linked,
// that is typing in one will update others too.
//
// See also:
// https://github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/common/snippet.md
Snippet = 2
};
MAKE_REFLECT_TYPE_PROXY(lsInsertTextFormat);
struct lsCompletionItem {
// A set of function parameters. Used internally for signature help. Not sent
// to vscode.
std::vector<std::string> parameters_;
// The label of this completion item. By default
// also the text that is inserted when selecting
// this completion.
std::string label;
// The kind of this completion item. Based of the kind
// an icon is chosen by the editor.
lsCompletionItemKind kind = lsCompletionItemKind::Text;
// A human-readable string with additional information
// about this item, like type or symbol information.
std::string detail;
// A human-readable string that represents a doc-comment.
optional<std::string> documentation;
// Internal information to order candidates.
bool found_;
std::string::size_type skip_;
unsigned priority_;
// Use <> or "" by default as include path.
bool use_angle_brackets_ = false;
// A string that shoud be used when comparing this item
// with other items. When `falsy` the label is used.
std::string sortText;
// A string that should be used when filtering a set of
// completion items. When `falsy` the label is used.
optional<std::string> filterText;
// A string that should be inserted a document when selecting
// this completion. When `falsy` the label is used.
std::string insertText;
// The format of the insert text. The format applies to both the `insertText`
// property and the `newText` property of a provided `textEdit`.
lsInsertTextFormat insertTextFormat = lsInsertTextFormat::PlainText;
// An edit which is applied to a document when selecting this completion. When
// an edit is provided the value of `insertText` is ignored.
//
// *Note:* The range of the edit must be a single line range and it must
// contain the position at which completion has been requested.
optional<lsTextEdit> textEdit;
// An optional array of additional text edits that are applied when
// selecting this completion. Edits must not overlap with the main edit
// nor with themselves.
// std::vector<TextEdit> additionalTextEdits;
// An optional command that is executed *after* inserting this completion.
// *Note* that additional modifications to the current document should be
// described with the additionalTextEdits-property. Command command;
// An data entry field that is preserved on a completion item between
// a completion and a completion resolve request.
// data ? : any
// Use this helper to figure out what content the completion item will insert
// into the document, as it could live in either |textEdit|, |insertText|, or
// |label|.
const std::string& InsertedContent() const {
if (textEdit)
return textEdit->newText;
if (!insertText.empty())
return insertText;
return label;
}
};
MAKE_REFLECT_STRUCT(lsCompletionItem,
label,
kind,
detail,
documentation,
sortText,
insertText,
filterText,
insertTextFormat,
textEdit);

View File

@ -63,31 +63,6 @@ ParseIncludeLineResult ParseIncludeLine(const std::string& line) {
return {ok, text, match};
}
void DecorateIncludePaths(const std::smatch& match,
std::vector<lsCompletionItem>* items) {
std::string spaces_after_include = " ";
if (match[3].compare("include") == 0 && match[5].length())
spaces_after_include = match[4].str();
std::string prefix =
match[1].str() + '#' + match[2].str() + "include" + spaces_after_include;
std::string suffix = match[7].str();
for (lsCompletionItem& item : *items) {
char quote0, quote1;
if (match[5].compare("<") == 0 ||
(match[5].length() == 0 && item.use_angle_brackets_))
quote0 = '<', quote1 = '>';
else
quote0 = quote1 = '"';
item.textEdit->newText =
prefix + quote0 + item.textEdit->newText + quote1 + suffix;
item.label = prefix + quote0 + item.label + quote1 + suffix;
item.filterText = nullopt;
}
}
// TODO: eliminate |line_number| param.
optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line) {
// Find starting and ending quote.

View File

@ -23,9 +23,6 @@ struct ParseIncludeLineResult {
ParseIncludeLineResult ParseIncludeLine(const std::string& line);
void DecorateIncludePaths(const std::smatch& match,
std::vector<lsCompletionItem>* items);
// TODO: eliminate |line_number| param.
optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line);

View File

@ -11,6 +11,19 @@
#include <algorithm>
namespace {
struct Out_CquerySetInactiveRegion
: public lsOutMessage<Out_CquerySetInactiveRegion> {
struct Params {
lsDocumentUri uri;
std::vector<lsRange> inactiveRegions;
};
std::string method = "$cquery/setInactiveRegions";
Params params;
};
MAKE_REFLECT_STRUCT(Out_CquerySetInactiveRegion::Params, uri, inactiveRegions);
MAKE_REFLECT_STRUCT(Out_CquerySetInactiveRegion, jsonrpc, method, params);
struct ScanLineEvent {
lsPosition pos;
lsPosition end_pos; // Second key when there is a tie for insertion events.

View File

@ -28,13 +28,13 @@ struct CqueryBaseHandler : BaseMessageHandler<Ipc_CqueryBase> {
if (sym.kind == SymbolKind::Type) {
if (const auto* def = db->GetType(sym).AnyDef())
out.result =
GetLsLocationExs(db, working_files, ToUses(db, def->parents),
GetLsLocationExs(db, working_files, GetDeclarations(db, def->parents),
config->xref.container, config->xref.maxNum);
break;
} else if (sym.kind == SymbolKind::Func) {
if (const auto* def = db->GetFunc(sym).AnyDef())
out.result =
GetLsLocationExs(db, working_files, ToUses(db, def->base),
GetLsLocationExs(db, working_files, GetDeclarations(db, def->base),
config->xref.container, config->xref.maxNum);
break;
}

View File

@ -28,13 +28,13 @@ struct CqueryDerivedHandler : BaseMessageHandler<Ipc_CqueryDerived> {
if (sym.kind == SymbolKind::Type) {
QueryType& type = db->GetType(sym);
out.result =
GetLsLocationExs(db, working_files, ToUses(db, type.derived),
GetLsLocationExs(db, working_files, GetDeclarations(db, type.derived),
config->xref.container, config->xref.maxNum);
break;
} else if (sym.kind == SymbolKind::Func) {
QueryFunc& func = db->GetFunc(sym);
out.result =
GetLsLocationExs(db, working_files, ToUses(db, func.derived),
GetLsLocationExs(db, working_files, GetDeclarations(db, func.derived),
config->xref.container, config->xref.maxNum);
break;
}

View File

@ -38,9 +38,9 @@ struct CqueryVarsHandler : BaseMessageHandler<Ipc_CqueryVars> {
// fallthrough
case SymbolKind::Type: {
QueryType& type = db->types[id.id];
out.result =
GetLsLocationExs(db, working_files, ToUses(db, type.instances),
config->xref.container, config->xref.maxNum);
out.result = GetLsLocationExs(
db, working_files, GetDeclarations(db, type.instances),
config->xref.container, config->xref.maxNum);
break;
}
}

View File

@ -160,9 +160,9 @@ struct TextDocumentCodeLensHandler
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0),
type.uses, true /*force_display*/);
AddCodeLens("derived", "derived", &common, OffsetStartColumn(use, 1),
ToUses(db, type.derived), false /*force_display*/);
GetDeclarations(db, type.derived), false /*force_display*/);
AddCodeLens("var", "vars", &common, OffsetStartColumn(use, 2),
ToUses(db, type.instances), false /*force_display*/);
GetDeclarations(db, type.instances), false /*force_display*/);
break;
}
case SymbolKind::Func: {
@ -210,7 +210,7 @@ struct TextDocumentCodeLensHandler
AddCodeLens("derived", "derived", &common,
OffsetStartColumn(use, offset++),
ToUses(db, func.derived), false /*force_display*/);
GetDeclarations(db, func.derived), false /*force_display*/);
// "Base"
if (def->base.size() == 1) {
@ -237,7 +237,7 @@ struct TextDocumentCodeLensHandler
}
} else {
AddCodeLens("base", "base", &common, OffsetStartColumn(use, 1),
ToUses(db, def->base), false /*force_display*/);
GetDeclarations(db, def->base), false /*force_display*/);
}
break;

View File

@ -81,6 +81,31 @@ bool CompareLsCompletionItem(const lsCompletionItem& lhs,
return *lhs.filterText < *rhs.filterText;
}
void DecorateIncludePaths(const std::smatch& match,
std::vector<lsCompletionItem>* items) {
std::string spaces_after_include = " ";
if (match[3].compare("include") == 0 && match[5].length())
spaces_after_include = match[4].str();
std::string prefix =
match[1].str() + '#' + match[2].str() + "include" + spaces_after_include;
std::string suffix = match[7].str();
for (lsCompletionItem& item : *items) {
char quote0, quote1;
if (match[5].compare("<") == 0 ||
(match[5].length() == 0 && item.use_angle_brackets_))
quote0 = '<', quote1 = '>';
else
quote0 = quote1 = '"';
item.textEdit->newText =
prefix + quote0 + item.textEdit->newText + quote1 + suffix;
item.label = prefix + quote0 + item.label + quote1 + suffix;
item.filterText = nullopt;
}
}
template <typename T>
char* tofixedbase64(T input, char* out) {
const char* digits =

View File

@ -27,7 +27,7 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result);
std::vector<Use> GetGotoDefinitionTargets(QueryDatabase* db, SymbolRef sym) {
switch (sym.kind) {
case SymbolKind::Var: {
std::vector<Use> ret = GetDeclarationsOfSymbolForGotoDefinition(db, sym);
std::vector<Use> ret = GetNonDefDeclarations(db, sym);
// If there is no declaration, jump the its type.
if (ret.empty()) {
for (auto& def : db->GetVar(sym).def)
@ -42,7 +42,7 @@ std::vector<Use> GetGotoDefinitionTargets(QueryDatabase* db, SymbolRef sym) {
return ret;
}
default:
return GetDeclarationsOfSymbolForGotoDefinition(db, sym);
return GetNonDefDeclarations(db, sym);
}
}

View File

@ -39,7 +39,7 @@ struct TextDocumentDocumentHighlightHandler
for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, request->params.position)) {
// Found symbol. Return references to highlight.
EachUse(db, sym, true, [&](Use use) {
EachOccurrence(db, sym, true, [&](Use use) {
if (use.file != file_id)
return;
if (optional<lsLocation> ls_loc =

View File

@ -57,13 +57,13 @@ struct TextDocumentReferencesHandler
for (const SymbolRef& sym :
FindSymbolsAtLocation(working_file, file, request->params.position)) {
// Found symbol. Return references.
EachUse(db, sym, request->params.context.includeDeclaration,
[&](Use use) {
if (use.role & request->params.context.role)
if (optional<lsLocationEx> ls_loc = GetLsLocationEx(
db, working_files, use, config->xref.container))
out.result.push_back(*ls_loc);
});
EachOccurrence(
db, sym, request->params.context.includeDeclaration, [&](Use use) {
if (use.role & request->params.context.role)
if (optional<lsLocationEx> ls_loc = GetLsLocationEx(
db, working_files, use, config->xref.container))
out.result.push_back(*ls_loc);
});
break;
}

View File

@ -10,7 +10,7 @@ lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db,
const std::string& new_text) {
std::unordered_map<QueryFileId, lsTextDocumentEdit> path_to_edit;
EachUse(db, sym, true, [&](Use use) {
EachOccurrence(db, sym, true, [&](Use use) {
optional<lsLocation> ls_location = GetLsLocation(db, working_files, use);
if (!ls_location)
return;

View File

@ -28,7 +28,7 @@ bool InsertSymbolIntoResult(QueryDatabase* db,
if (location)
loc = *location;
else {
auto decls = GetDeclarationsOfSymbolForGotoDefinition(db, symbol);
auto decls = GetNonDefDeclarations(db, symbol);
if (decls.empty())
return false;
loc = decls[0];

View File

@ -19,8 +19,8 @@ int ComputeRangeSize(const Range& range) {
}
template <typename Q>
std::vector<Use> ToUsesHelper(std::vector<Q>& entities,
const std::vector<Id<Q>>& ids) {
std::vector<Use> GetDeclarations(std::vector<Q>& entities,
const std::vector<Id<Q>>& ids) {
std::vector<Use> ret;
ret.reserve(ids.size());
for (auto id : ids) {
@ -87,22 +87,23 @@ Maybe<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
return nullopt;
}
std::vector<Use> ToUses(QueryDatabase* db,
const std::vector<QueryFuncId>& ids) {
return ToUsesHelper(db->funcs, ids);
std::vector<Use> GetDeclarations(QueryDatabase* db,
const std::vector<QueryFuncId>& ids) {
return GetDeclarations(db->funcs, ids);
}
std::vector<Use> ToUses(QueryDatabase* db,
const std::vector<QueryTypeId>& ids) {
return ToUsesHelper(db->types, ids);
std::vector<Use> GetDeclarations(QueryDatabase* db,
const std::vector<QueryTypeId>& ids) {
return GetDeclarations(db->types, ids);
}
std::vector<Use> ToUses(QueryDatabase* db, const std::vector<QueryVarId>& ids) {
return ToUsesHelper(db->vars, ids);
std::vector<Use> GetDeclarations(QueryDatabase* db,
const std::vector<QueryVarId>& ids) {
return GetDeclarations(db->vars, ids);
}
std::vector<Use> GetDeclarationsOfSymbolForGotoDefinition(QueryDatabase* db,
SymbolIdx sym) {
std::vector<Use> GetNonDefDeclarations(QueryDatabase* db,
SymbolIdx sym) {
switch (sym.kind) {
case SymbolKind::Func:
return db->GetFunc(sym).declarations;
@ -334,7 +335,6 @@ optional<lsSymbolInformation> GetSymbolInfo(QueryDatabase* db,
return nullopt;
}
// TODO Sort only by range length, not |kind| or |idx|
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
QueryFile* file,
lsPosition position) {

View File

@ -10,12 +10,13 @@ Maybe<Use> GetDefinitionExtentOfSymbol(QueryDatabase* db, SymbolIdx sym);
Maybe<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
SymbolIdx sym);
std::vector<Use> ToUses(QueryDatabase* db, const std::vector<QueryFuncId>& ids);
std::vector<Use> ToUses(QueryDatabase* db, const std::vector<QueryTypeId>& ids);
std::vector<Use> ToUses(QueryDatabase* db, const std::vector<QueryVarId>& ids);
// Get defining declaration (if exists) or an arbitrary declaration (otherwise) for each id.
std::vector<Use> GetDeclarations(QueryDatabase* db, const std::vector<QueryFuncId>& ids);
std::vector<Use> GetDeclarations(QueryDatabase* db, const std::vector<QueryTypeId>& ids);
std::vector<Use> GetDeclarations(QueryDatabase* db, const std::vector<QueryVarId>& ids);
std::vector<Use> GetDeclarationsOfSymbolForGotoDefinition(QueryDatabase* db,
SymbolIdx sym);
// Get non-defining declarations.
std::vector<Use> GetNonDefDeclarations(QueryDatabase* db, SymbolIdx sym);
bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root);
std::vector<Use> GetCallersForAllBaseFunctions(QueryDatabase* db,
@ -84,7 +85,7 @@ void EachEntityDef(QueryDatabase* db, SymbolIdx sym, Fn&& fn) {
}
template <typename Fn>
void EachUse(QueryDatabase* db, SymbolIdx sym, bool include_decl, Fn&& fn) {
void EachOccurrence(QueryDatabase* db, SymbolIdx sym, bool include_decl, Fn&& fn) {
WithEntity(db, sym, [&](const auto& entity) {
for (Use use : entity.uses)
fn(use);