Remove <regex> from lex_utils.h and separate language_server_api.h

% time clang++ -fsyntax-only -std=c++11 a.cc

<iostream> => 0.35s
<regex> => 0.68s
This commit is contained in:
Fangrui Song 2018-02-23 16:12:39 -08:00
parent 411d49951d
commit c68548a2ca
28 changed files with 182 additions and 174 deletions

View File

@ -2,7 +2,7 @@
#include "config.h" #include "config.h"
#include "indexer.h" #include "indexer.h"
#include "language_server_api.h" #include "lsp.h"
#include "platform.h" #include "platform.h"
#include <loguru/loguru.hpp> #include <loguru/loguru.hpp>

View File

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

View File

@ -2,7 +2,7 @@
#if USE_CLANG_CXX #if USE_CLANG_CXX
#include "language_server_api.h" #include "lsp.h"
#include "working_files.h" #include "working_files.h"
#include <clang/Format/Format.h> #include <clang/Format/Format.h>

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "language_server_api.h" #include "lsp_diagnostic.h"
#include <clang-c/Index.h> #include <clang-c/Index.h>
#if USE_CLANG_CXX #if USE_CLANG_CXX

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "language_server_api_completion.h" #include "lsp_completion.h"
#include <optional.h> #include <optional.h>

View File

@ -7,7 +7,7 @@
#include "import_pipeline.h" #include "import_pipeline.h"
#include "include_complete.h" #include "include_complete.h"
#include "indexer.h" #include "indexer.h"
#include "language_server_api.h" #include "lsp_diagnostic.h"
#include "lex_utils.h" #include "lex_utils.h"
#include "lru_cache.h" #include "lru_cache.h"
#include "match.h" #include "match.h"

View File

@ -4,7 +4,7 @@
#include "config.h" #include "config.h"
#include "iindexer.h" #include "iindexer.h"
#include "import_manager.h" #include "import_manager.h"
#include "language_server_api.h" #include "lsp.h"
#include "message_handler.h" #include "message_handler.h"
#include "platform.h" #include "platform.h"
#include "project.h" #include "project.h"

View File

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

View File

@ -7,7 +7,7 @@
#include "file_consumer.h" #include "file_consumer.h"
#include "file_contents.h" #include "file_contents.h"
#include "language.h" #include "language.h"
#include "language_server_api.h" #include "lsp.h"
#include "maybe.h" #include "maybe.h"
#include "nt_string.h" #include "nt_string.h"
#include "performance.h" #include "performance.h"

View File

@ -46,23 +46,6 @@ lsPosition CharPos(std::string_view search,
return result; return result;
} }
ParseIncludeLineResult ParseIncludeLine(const std::string& line) {
static const std::regex pattern(
"(\\s*)" // [1]: spaces before '#'
"#" //
"(\\s*)" // [2]: spaces after '#'
"([^\\s\"<]*)" // [3]: "include"
"(\\s*)" // [4]: spaces before quote
"([\"<])?" // [5]: the first quote char
"([^\\s\">]*)" // [6]: path of file
"[\">]?" //
"(.*)"); // [7]: suffix after quote char
std::smatch match;
bool ok = std::regex_match(line, match, pattern);
std::string text = match[3].str() + match[6].str();
return {ok, text, match};
}
// TODO: eliminate |line_number| param. // TODO: eliminate |line_number| param.
optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line) { optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line) {
// Find starting and ending quote. // Find starting and ending quote.

View File

@ -1,10 +1,9 @@
#pragma once #pragma once
#include "language_server_api.h" #include "lsp.h"
#include <string_view.h> #include <string_view.h>
#include <regex>
#include <string> #include <string>
#include <tuple> #include <tuple>
@ -15,14 +14,6 @@ lsPosition CharPos(std::string_view search,
char character, char character,
int character_offset = 0); int character_offset = 0);
struct ParseIncludeLineResult {
bool ok;
std::string text; // include the "include" part
std::smatch match;
};
ParseIncludeLineResult ParseIncludeLine(const std::string& line);
// TODO: eliminate |line_number| param. // TODO: eliminate |line_number| param.
optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line); optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line);

View File

@ -1,4 +1,4 @@
#include "language_server_api.h" #include "lsp.h"
#include "recorder.h" #include "recorder.h"
#include "serializers/json.h" #include "serializers/json.h"

View File

@ -292,110 +292,12 @@ struct lsFormattingOptions {
}; };
MAKE_REFLECT_STRUCT(lsFormattingOptions, tabSize, insertSpaces); MAKE_REFLECT_STRUCT(lsFormattingOptions, tabSize, insertSpaces);
enum class lsDiagnosticSeverity {
// Reports an error.
Error = 1,
// Reports a warning.
Warning = 2,
// Reports an information.
Information = 3,
// Reports a hint.
Hint = 4
};
MAKE_REFLECT_TYPE_PROXY(lsDiagnosticSeverity);
struct lsDiagnostic {
// The range at which the message applies.
lsRange range;
// The diagnostic's severity. Can be omitted. If omitted it is up to the
// client to interpret diagnostics as error, warning, info or hint.
optional<lsDiagnosticSeverity> severity;
// The diagnostic's code. Can be omitted.
int code = 0;
// A human-readable string describing the source of this
// diagnostic, e.g. 'typescript' or 'super lint'.
std::string source = "cquery";
// The diagnostic's message.
std::string message;
// Non-serialized set of fixits.
std::vector<lsTextEdit> fixits_;
};
MAKE_REFLECT_STRUCT(lsDiagnostic, range, severity, source, message);
enum class lsErrorCodes {
// Defined by JSON RPC
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
serverErrorStart = -32099,
serverErrorEnd = -32000,
ServerNotInitialized = -32002,
UnknownErrorCode = -32001,
// Defined by the protocol.
RequestCancelled = -32800,
};
MAKE_REFLECT_TYPE_PROXY(lsErrorCodes);
struct Out_Error : public lsOutMessage<Out_Error> {
struct lsResponseError {
// A number indicating the error type that occurred.
lsErrorCodes code;
// A string providing a short description of the error.
std::string message;
// A Primitive or Structured value that contains additional
// information about the error. Can be omitted.
// optional<D> data;
};
lsRequestId id;
// The error object in case a request fails.
lsResponseError error;
};
MAKE_REFLECT_STRUCT(Out_Error::lsResponseError, code, message);
MAKE_REFLECT_STRUCT(Out_Error, jsonrpc, id, error);
// Cancel an existing request. // Cancel an existing request.
struct Ipc_CancelRequest : public RequestMessage<Ipc_CancelRequest> { struct Ipc_CancelRequest : public RequestMessage<Ipc_CancelRequest> {
static const IpcId kIpcId = IpcId::CancelRequest; static const IpcId kIpcId = IpcId::CancelRequest;
}; };
MAKE_REFLECT_STRUCT(Ipc_CancelRequest, id); MAKE_REFLECT_STRUCT(Ipc_CancelRequest, id);
// Diagnostics
struct Out_TextDocumentPublishDiagnostics
: public lsOutMessage<Out_TextDocumentPublishDiagnostics> {
struct Params {
// The URI for which diagnostic information is reported.
lsDocumentUri uri;
// An array of diagnostic information items.
std::vector<lsDiagnostic> diagnostics;
};
Params params;
};
template <typename TVisitor>
void Reflect(TVisitor& visitor, Out_TextDocumentPublishDiagnostics& value) {
std::string method = "textDocument/publishDiagnostics";
REFLECT_MEMBER_START();
REFLECT_MEMBER(jsonrpc);
REFLECT_MEMBER2("method", method);
REFLECT_MEMBER(params);
REFLECT_MEMBER_END();
}
MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params,
uri,
diagnostics);
// MarkedString can be used to render human readable text. It is either a // MarkedString can be used to render human readable text. It is either a
// markdown string or a code-block that provides a language and a code snippet. // markdown string or a code-block that provides a language and a code snippet.
// The language identifier is sematically equal to the optional language // The language identifier is sematically equal to the optional language

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include "language_server_api.h" #include "lsp.h"
// The kind of a completion entry. // The kind of a completion entry.
enum class lsCompletionItemKind { enum class lsCompletionItemKind {

20
src/lsp_diagnostic.cc Normal file
View File

@ -0,0 +1,20 @@
#include "lsp_diagnostic.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;
});
}

106
src/lsp_diagnostic.h Normal file
View File

@ -0,0 +1,106 @@
#pragma once
#include "lsp.h"
enum class lsDiagnosticSeverity {
// Reports an error.
Error = 1,
// Reports a warning.
Warning = 2,
// Reports an information.
Information = 3,
// Reports a hint.
Hint = 4
};
MAKE_REFLECT_TYPE_PROXY(lsDiagnosticSeverity);
struct lsDiagnostic {
// The range at which the message applies.
lsRange range;
// The diagnostic's severity. Can be omitted. If omitted it is up to the
// client to interpret diagnostics as error, warning, info or hint.
optional<lsDiagnosticSeverity> severity;
// The diagnostic's code. Can be omitted.
int code = 0;
// A human-readable string describing the source of this
// diagnostic, e.g. 'typescript' or 'super lint'.
std::string source = "cquery";
// The diagnostic's message.
std::string message;
// Non-serialized set of fixits.
std::vector<lsTextEdit> fixits_;
};
MAKE_REFLECT_STRUCT(lsDiagnostic, range, severity, source, message);
enum class lsErrorCodes {
// Defined by JSON RPC
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
serverErrorStart = -32099,
serverErrorEnd = -32000,
ServerNotInitialized = -32002,
UnknownErrorCode = -32001,
// Defined by the protocol.
RequestCancelled = -32800,
};
MAKE_REFLECT_TYPE_PROXY(lsErrorCodes);
struct Out_Error : public lsOutMessage<Out_Error> {
struct lsResponseError {
// A number indicating the error type that occurred.
lsErrorCodes code;
// A string providing a short description of the error.
std::string message;
// A Primitive or Structured value that contains additional
// information about the error. Can be omitted.
// optional<D> data;
};
lsRequestId id;
// The error object in case a request fails.
lsResponseError error;
};
MAKE_REFLECT_STRUCT(Out_Error::lsResponseError, code, message);
MAKE_REFLECT_STRUCT(Out_Error, jsonrpc, id, error);
// Diagnostics
struct Out_TextDocumentPublishDiagnostics
: public lsOutMessage<Out_TextDocumentPublishDiagnostics> {
struct Params {
// The URI for which diagnostic information is reported.
lsDocumentUri uri;
// An array of diagnostic information items.
std::vector<lsDiagnostic> diagnostics;
};
Params params;
};
template <typename TVisitor>
void Reflect(TVisitor& visitor, Out_TextDocumentPublishDiagnostics& value) {
std::string method = "textDocument/publishDiagnostics";
REFLECT_MEMBER_START();
REFLECT_MEMBER(jsonrpc);
REFLECT_MEMBER2("method", method);
REFLECT_MEMBER(params);
REFLECT_MEMBER_END();
}
MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params,
uri,
diagnostics);
struct WorkingFiles;
void EmitDiagnostics(WorkingFiles* working_files,
std::string path,
std::vector<lsDiagnostic> diagnostics);

View File

@ -1,6 +1,6 @@
#include "match.h" #include "match.h"
#include "language_server_api.h" #include "lsp.h"
#include "queue_manager.h" #include "queue_manager.h"
#include <doctest/doctest.h> #include <doctest/doctest.h>

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "ipc.h" #include "ipc.h"
#include "language_server_api.h" #include "lsp.h"
#include "query.h" #include "query.h"
#include <optional.h> #include <optional.h>

View File

@ -128,7 +128,7 @@ struct CqueryRandomHandler : BaseMessageHandler<Ipc_CqueryRandom> {
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
sum += x[i]; sum += x[i];
if (sum >= roulette) { if (sum >= roulette) {
Maybe<Use> use = GetDefinitionExtentOfSymbol(db, syms[i]); Maybe<Use> use = GetDefinitionExtent(db, syms[i]);
if (!use) if (!use)
continue; continue;
if (auto ls_loc = GetLsLocationEx(db, working_files, *use, if (auto ls_loc = GetLsLocationEx(db, working_files, *use,

View File

@ -498,7 +498,7 @@ struct InitializeHandler : BaseMessageHandler<Ipc_InitializeRequest> {
Reflect(json_reader, *config); Reflect(json_reader, *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 language_server_api.cc // MessageRegistry::Parse in lsp.cc
} }
} }

View File

@ -177,7 +177,7 @@ struct TextDocumentCodeLensHandler
// extent since that is better for outline. This tries to convert the // extent since that is better for outline. This tries to convert the
// extent location to the spelling location. // extent location to the spelling location.
auto try_ensure_spelling = [&](Use use) { auto try_ensure_spelling = [&](Use use) {
Maybe<Use> def = GetDefinitionSpellingOfSymbol(db, use); Maybe<Use> def = GetDefinitionSpell(db, use);
if (!def || def->range.start.line != use.range.start.line) { if (!def || def->range.start.line != use.range.start.line) {
return use; return use;
} }
@ -214,7 +214,7 @@ struct TextDocumentCodeLensHandler
// "Base" // "Base"
if (def->base.size() == 1) { if (def->base.size() == 1) {
Maybe<Use> base_loc = GetDefinitionSpellingOfSymbol( Maybe<Use> base_loc = GetDefinitionSpell(
db, SymbolIdx{def->base[0], SymbolKind::Func}); db, SymbolIdx{def->base[0], SymbolKind::Func});
if (base_loc) { if (base_loc) {
optional<lsLocation> ls_base = optional<lsLocation> ls_base =

View File

@ -10,6 +10,8 @@
#include <loguru.hpp> #include <loguru.hpp>
#include <regex>
namespace { namespace {
// How a completion was triggered // How a completion was triggered
@ -106,6 +108,29 @@ void DecorateIncludePaths(const std::smatch& match,
} }
} }
struct ParseIncludeLineResult {
bool ok;
std::string text; // include the "include" part
std::smatch match;
};
ParseIncludeLineResult ParseIncludeLine(const std::string& line) {
static const std::regex pattern(
"(\\s*)" // [1]: spaces before '#'
"#" //
"(\\s*)" // [2]: spaces after '#'
"([^\\s\"<]*)" // [3]: "include"
"(\\s*)" // [4]: spaces before quote
"([\"<])?" // [5]: the first quote char
"([^\\s\">]*)" // [6]: path of file
"[\">]?" //
"(.*)"); // [7]: suffix after quote char
std::smatch match;
bool ok = std::regex_match(line, match, pattern);
std::string text = match[3].str() + match[6].str();
return {ok, text, match};
}
template <typename T> template <typename T>
char* tofixedbase64(T input, char* out) { char* tofixedbase64(T input, char* out) {
const char* digits = const char* digits =

View File

@ -24,7 +24,7 @@ struct Out_TextDocumentDefinition
}; };
MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result); MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result);
std::vector<Use> GetGotoDefinitionTargets(QueryDatabase* db, SymbolRef sym) { std::vector<Use> GetNonDefDeclarationTargets(QueryDatabase* db, SymbolRef sym) {
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Var: { case SymbolKind::Var: {
std::vector<Use> ret = GetNonDefDeclarations(db, sym); std::vector<Use> ret = GetNonDefDeclarations(db, sym);
@ -32,7 +32,7 @@ std::vector<Use> GetGotoDefinitionTargets(QueryDatabase* db, SymbolRef sym) {
if (ret.empty()) { if (ret.empty()) {
for (auto& def : db->GetVar(sym).def) for (auto& def : db->GetVar(sym).def)
if (def.type) { if (def.type) {
if (Maybe<Use> use = GetDefinitionSpellingOfSymbol( if (Maybe<Use> use = GetDefinitionSpell(
db, SymbolIdx{*def.type, SymbolKind::Type})) { db, SymbolIdx{*def.type, SymbolKind::Type})) {
ret.push_back(*use); ret.push_back(*use);
break; break;
@ -99,7 +99,7 @@ struct TextDocumentDefinitionHandler
if (uses.empty()) { if (uses.empty()) {
// The symbol has no definition or the cursor is on a definition. // The symbol has no definition or the cursor is on a definition.
uses = GetGotoDefinitionTargets(db, sym); uses = GetNonDefDeclarationTargets(db, sym);
// There is no declaration but the cursor is on a definition. // There is no declaration but the cursor is on a definition.
if (uses.empty() && on_def) if (uses.empty() && on_def)
uses.push_back(*on_def); uses.push_back(*on_def);
@ -143,7 +143,7 @@ struct TextDocumentDefinitionHandler
auto pos = name.find(query); auto pos = name.find(query);
if (pos == std::string::npos) if (pos == std::string::npos)
continue; continue;
Maybe<Use> use = GetDefinitionSpellingOfSymbol(db, db->symbols[i]); Maybe<Use> use = GetDefinitionSpell(db, db->symbols[i]);
if (!use) if (!use)
continue; continue;
@ -157,7 +157,7 @@ struct TextDocumentDefinitionHandler
} }
if (best_i != -1) { if (best_i != -1) {
Maybe<Use> use = Maybe<Use> use =
GetDefinitionSpellingOfSymbol(db, db->symbols[best_i]); GetDefinitionSpell(db, db->symbols[best_i]);
assert(use); assert(use);
if (auto ls_loc = GetLsLocationEx(db, working_files, *use, if (auto ls_loc = GetLsLocationEx(db, working_files, *use,
config->xref.container)) config->xref.container))

View File

@ -23,7 +23,7 @@ bool InsertSymbolIntoResult(QueryDatabase* db,
if (!info) if (!info)
return false; return false;
Maybe<Use> location = GetDefinitionExtentOfSymbol(db, symbol); Maybe<Use> location = GetDefinitionExtent(db, symbol);
Use loc; Use loc;
if (location) if (location)
loc = *location; loc = *location;

View File

@ -40,13 +40,13 @@ std::vector<Use> GetDeclarations(std::vector<Q>& entities,
} // namespace } // namespace
Maybe<Use> GetDefinitionSpellingOfSymbol(QueryDatabase* db, SymbolIdx sym) { Maybe<Use> GetDefinitionSpell(QueryDatabase* db, SymbolIdx sym) {
Maybe<Use> ret; Maybe<Use> ret;
EachEntityDef(db, sym, [&](const auto& def) { return !(ret = def.spell); }); EachEntityDef(db, sym, [&](const auto& def) { return !(ret = def.spell); });
return ret; return ret;
} }
Maybe<Use> GetDefinitionExtentOfSymbol(QueryDatabase* db, SymbolIdx sym) { Maybe<Use> GetDefinitionExtent(QueryDatabase* db, SymbolIdx sym) {
// Used to jump to file. // Used to jump to file.
if (sym.kind == SymbolKind::File) if (sym.kind == SymbolKind::File)
return Use(Range(Position(0, 0), Position(0, 0)), sym.id, sym.kind, return Use(Range(Position(0, 0), Position(0, 0)), sym.id, sym.kind,
@ -383,19 +383,3 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
return symbols; return symbols;
} }
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;
});
}

View File

@ -5,8 +5,8 @@
#include <optional.h> #include <optional.h>
Maybe<Use> GetDefinitionSpellingOfSymbol(QueryDatabase* db, SymbolIdx sym); Maybe<Use> GetDefinitionSpell(QueryDatabase* db, SymbolIdx sym);
Maybe<Use> GetDefinitionExtentOfSymbol(QueryDatabase* db, SymbolIdx sym); Maybe<Use> GetDefinitionExtent(QueryDatabase* db, SymbolIdx sym);
Maybe<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db, Maybe<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
SymbolIdx sym); SymbolIdx sym);
@ -53,10 +53,6 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
QueryFile* file, QueryFile* file,
lsPosition position); lsPosition position);
void EmitDiagnostics(WorkingFiles* working_files,
std::string path,
std::vector<lsDiagnostic> diagnostics);
template <typename Fn> template <typename Fn>
void WithEntity(QueryDatabase* db, SymbolIdx sym, Fn&& fn) { void WithEntity(QueryDatabase* db, SymbolIdx sym, Fn&& fn) {
switch (sym.kind) { switch (sym.kind) {

View File

@ -1,7 +1,7 @@
#include "queue_manager.h" #include "queue_manager.h"
#include "cache_manager.h" #include "cache_manager.h"
#include "language_server_api.h" #include "lsp.h"
#include "query.h" #include "query.h"
#include <sstream> #include <sstream>

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "language_server_api.h" #include "lsp_diagnostic.h"
#include "utils.h" #include "utils.h"
#include <clang-c/Index.h> #include <clang-c/Index.h>