From 34dc1e93e97dfb046ac996da95fb7b000e1bf97a Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 31 May 2018 20:06:09 -0700 Subject: [PATCH] Remove WithFileContent & lex_utils.{cc,h} --- CMakeLists.txt | 1 - src/indexer.cc | 13 +-- src/indexer.h | 14 --- src/lex_utils.cc | 87 ------------------- src/lex_utils.h | 16 ---- src/main.cc | 6 +- src/message_handler.cc | 1 - src/messages/text_document_completion.cc | 2 - src/messages/text_document_definition.cc | 1 - .../text_document_range_formatting.cc | 72 --------------- src/messages/workspace_symbol.cc | 1 - src/pipeline.cc | 41 +++------ src/pipeline.hh | 5 +- src/query.cc | 6 +- src/query.h | 17 +--- src/utils.cc | 18 ++++ src/utils.h | 4 + src/working_files.cc | 44 +++++++++- src/working_files.h | 5 ++ 19 files changed, 100 insertions(+), 254 deletions(-) delete mode 100644 src/lex_utils.cc delete mode 100644 src/lex_utils.h delete mode 100644 src/messages/text_document_range_formatting.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index d3db90e0..fb5a8e8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,7 +202,6 @@ target_sources(ccls PRIVATE src/indexer.cc src/method.cc src/language.cc - src/lex_utils.cc src/log.cc src/lsp.cc src/match.cc diff --git a/src/indexer.cc b/src/indexer.cc index 48dffa65..760d02a9 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -3,9 +3,11 @@ #include "log.hh" #include "platform.h" #include "serializer.h" -#include "timer.h" #include "type_printer.h" +#include +using namespace llvm; + #include #include #include @@ -2016,7 +2018,8 @@ std::vector> ClangIndexer::Index( file = NormalizePath(file); - Timer timer; + Timer timer("parse", "parse tu"); + timer.startTimer(); std::vector unsaved_files; for (const FileContents& contents : file_contents) { @@ -2034,7 +2037,7 @@ std::vector> ClangIndexer::Index( if (!tu) return {}; - perf->index_parse = timer.ElapsedMicrosecondsAndReset(); + timer.stopTimer(); return ParseWithTu(vfs, perf, tu.get(), &index, file, args, unsaved_files); } @@ -2048,6 +2051,7 @@ std::vector> ParseWithTu( const std::vector& args, const std::vector& file_contents) { Timer timer; + timer.startTimer(); IndexerCallbacks callback = {0}; // Available callbacks: @@ -2085,13 +2089,12 @@ std::vector> ParseWithTu( << " failed with errno=" << index_result; return {}; } - clang_IndexAction_dispose(index_action); ClangCursor(clang_getTranslationUnitCursor(tu->cx_tu)) .VisitChildren(&VisitMacroDefinitionAndExpansions, ¶m); - perf->index_build = timer.ElapsedMicrosecondsAndReset(); + timer.stopTimer(); std::unordered_map inc_to_line; // TODO diff --git a/src/indexer.h b/src/indexer.h index 6921a8dd..6c246582 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -27,8 +27,6 @@ struct IndexFunc; struct IndexVar; struct QueryFile; -using RawId = uint32_t; - struct SymbolIdx { Usr usr; SymbolKind kind; @@ -153,19 +151,9 @@ struct TypeDef : NameMixin { NtString hover; NtString comments; - // While a class/type can technically have a separate declaration/definition, - // it doesn't really happen in practice. The declaration never contains - // comments or insightful information. The user always wants to jump from - // the declaration to the definition - never the other way around like in - // functions and (less often) variables. - // - // It's also difficult to identify a `class Foo;` statement with the clang - // indexer API (it's doable using cursor AST traversal), so we don't bother - // supporting the feature. Maybe spell; Maybe extent; - // Immediate parent types. std::vector bases; // Types, functions, and variables defined in this type. @@ -221,8 +209,6 @@ struct VarDef : NameMixin { std::string detailed_name; NtString hover; NtString comments; - // TODO: definitions should be a list of ranges, since there can be more - // than one - when?? Maybe spell; Maybe extent; diff --git a/src/lex_utils.cc b/src/lex_utils.cc deleted file mode 100644 index 9380f723..00000000 --- a/src/lex_utils.cc +++ /dev/null @@ -1,87 +0,0 @@ -#include "lex_utils.h" - -#include - -#include - -// VSCode (UTF-16) disagrees with Emacs lsp-mode (UTF-8) on how to represent -// text documents. -// We use a UTF-8 iterator to approximate UTF-16 in the specification (weird). -// This is good enough and fails only for UTF-16 surrogate pairs. -int GetOffsetForPosition(lsPosition position, std::string_view content) { - size_t i = 0; - for (; position.line > 0 && i < content.size(); i++) - if (content[i] == '\n') - position.line--; - for (; position.character > 0 && i < content.size(); position.character--) - if (uint8_t(content[i++]) >= 128) { - // Skip 0b10xxxxxx - while (i < content.size() && uint8_t(content[i]) >= 128 && - uint8_t(content[i]) < 192) - i++; - } - return int(i); -} - -std::string_view LexIdentifierAroundPos(lsPosition position, - std::string_view content) { - int start = GetOffsetForPosition(position, content); - int end = start + 1; - char c; - - // We search for :: before the cursor but not after to get the qualifier. - for (; start > 0; start--) { - c = content[start - 1]; - if (isalnum(c) || c == '_') - ; - else if (c == ':' && start > 1 && content[start - 2] == ':') - start--; - else - break; - } - - for (; end < (int)content.size(); end++) - if (c = content[end], !(isalnum(c) || c == '_')) - break; - - return content.substr(start, end - start); -} - -// Find discontinous |search| in |content|. -// Return |found| and the count of skipped chars before found. -int ReverseSubseqMatch(std::string_view pat, - std::string_view text, - int case_sensitivity) { - if (case_sensitivity == 1) - case_sensitivity = std::any_of(pat.begin(), pat.end(), isupper) ? 2 : 0; - int j = pat.size(); - if (!j) - return text.size(); - for (int i = text.size(); i--;) - if ((case_sensitivity ? text[i] == pat[j - 1] - : tolower(text[i]) == tolower(pat[j - 1])) && - !--j) - return i; - return -1; -} - -TEST_SUITE("Offset") { - TEST_CASE("past end") { - std::string content = "foo"; - int offset = GetOffsetForPosition(lsPosition{10, 10}, content); - REQUIRE(offset <= content.size()); - } - - TEST_CASE("in middle of content") { - std::string content = "abcdefghijk"; - for (int i = 0; i < content.size(); ++i) { - int offset = GetOffsetForPosition(lsPosition{0, i}, content); - REQUIRE(i == offset); - } - } - - TEST_CASE("at end of content") { - REQUIRE(GetOffsetForPosition(lsPosition{0, 0}, "") == 0); - REQUIRE(GetOffsetForPosition(lsPosition{0, 1}, "a") == 1); - } -} diff --git a/src/lex_utils.h b/src/lex_utils.h deleted file mode 100644 index 4206a120..00000000 --- a/src/lex_utils.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "lsp.h" - -#include -#include - -// Utility method to map |position| to an offset inside of |content|. -int GetOffsetForPosition(lsPosition position, std::string_view content); - -std::string_view LexIdentifierAroundPos(lsPosition position, - std::string_view content); - -int ReverseSubseqMatch(std::string_view pat, - std::string_view text, - int case_sensitivity); diff --git a/src/main.cc b/src/main.cc index 03936f5c..ebb6b488 100644 --- a/src/main.cc +++ b/src/main.cc @@ -129,12 +129,10 @@ int main(int argc, char** argv) { } } - std::unordered_map request_times; - // The thread that reads from stdin and dispatchs commands to the main thread. - pipeline::LaunchStdin(&request_times); + pipeline::LaunchStdin(); // The thread that writes responses from the main thread to stdout. - pipeline::LaunchStdout(&request_times); + pipeline::LaunchStdout(); // Main thread which also spawns indexer threads upon the "initialize" request. pipeline::MainLoop(); } diff --git a/src/message_handler.cc b/src/message_handler.cc index ab871900..168fa605 100644 --- a/src/message_handler.cc +++ b/src/message_handler.cc @@ -1,6 +1,5 @@ #include "message_handler.h" -#include "lex_utils.h" #include "log.hh" #include "project.h" #include "query_utils.h" diff --git a/src/messages/text_document_completion.cc b/src/messages/text_document_completion.cc index 39998655..488f42b2 100644 --- a/src/messages/text_document_completion.cc +++ b/src/messages/text_document_completion.cc @@ -7,8 +7,6 @@ #include "working_files.h" using namespace ccls; -#include "lex_utils.h" - #include namespace { diff --git a/src/messages/text_document_definition.cc b/src/messages/text_document_definition.cc index b65682a5..93786c3e 100644 --- a/src/messages/text_document_definition.cc +++ b/src/messages/text_document_definition.cc @@ -1,4 +1,3 @@ -#include "lex_utils.h" #include "message_handler.h" #include "pipeline.hh" #include "query_utils.h" diff --git a/src/messages/text_document_range_formatting.cc b/src/messages/text_document_range_formatting.cc deleted file mode 100644 index 8ffe41f8..00000000 --- a/src/messages/text_document_range_formatting.cc +++ /dev/null @@ -1,72 +0,0 @@ -#include "clang_format.h" -#include "lex_utils.h" -#include "message_handler.h" -#include "pipeline.hh" -using namespace ccls; -#include "working_files.h" - -#include - -namespace { -MethodType kMethodType = "textDocument/rangeFormatting"; - -struct lsTextDocumentRangeFormattingParams { - lsTextDocumentIdentifier textDocument; - lsRange range; - lsFormattingOptions options; -}; -MAKE_REFLECT_STRUCT(lsTextDocumentRangeFormattingParams, - textDocument, - range, - options); - -struct In_TextDocumentRangeFormatting : public RequestInMessage { - MethodType GetMethodType() const override { return kMethodType; } - lsTextDocumentRangeFormattingParams params; -}; -MAKE_REFLECT_STRUCT(In_TextDocumentRangeFormatting, id, params); -REGISTER_IN_MESSAGE(In_TextDocumentRangeFormatting); - -struct Out_TextDocumentRangeFormatting - : public lsOutMessage { - lsRequestId id; - std::vector result; -}; -MAKE_REFLECT_STRUCT(Out_TextDocumentRangeFormatting, jsonrpc, id, result); - -struct Handler_TextDocumentRangeFormatting - : BaseMessageHandler { - MethodType GetMethodType() const override { return kMethodType; } - - void Run(In_TextDocumentRangeFormatting* request) override { - Out_TextDocumentRangeFormatting response; - response.id = request->id; -#if USE_CLANG_CXX - QueryFile* file; - if (!FindFileOrFail(db, project, request->id, - request->params.textDocument.uri.GetPath(), &file)) { - return; - } - - WorkingFile* working_file = - working_files->GetFileByFilename(file->def->path); - - int start = GetOffsetForPosition(request->params.range.start, - working_file->buffer_content), - end = GetOffsetForPosition(request->params.range.end, - working_file->buffer_content); - response.result = ConvertClangReplacementsIntoTextEdits( - working_file->buffer_content, - ClangFormatDocument(working_file, start, end, request->params.options)); -#else - LOG_S(WARNING) << "You must compile ccls with --use-clang-cxx to use " - "textDocument/rangeFormatting."; - // TODO: Fallback to execute the clang-format binary? - response.result = {}; -#endif - - pipeline::WriteStdout(kMethodType, response); - } -}; -REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRangeFormatting); -} // namespace diff --git a/src/messages/workspace_symbol.cc b/src/messages/workspace_symbol.cc index 2515b1fc..3b608635 100644 --- a/src/messages/workspace_symbol.cc +++ b/src/messages/workspace_symbol.cc @@ -1,5 +1,4 @@ #include "fuzzy_match.h" -#include "lex_utils.h" #include "message_handler.h" #include "pipeline.hh" #include "query_utils.h" diff --git a/src/pipeline.cc b/src/pipeline.cc index d65b1db5..2a96e522 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -11,10 +11,10 @@ #include "project.h" #include "query_utils.h" #include "pipeline.hh" -#include "timer.h" #include #include +#include using namespace llvm; #include @@ -237,14 +237,15 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine, // Write current index to disk if requested. LOG_S(INFO) << "store index for " << path; - Timer time; { + Timer timer("write", "store index"); + timer.startTimer(); std::string cache_path = GetCachePath(path); WriteToFile(cache_path, curr->file_contents); WriteToFile(AppendSerializationFormat(cache_path), Serialize(g_config->cacheFormat, *curr)); + timer.stopTimer(); } - perf.index_save_to_disk = time.ElapsedMicrosecondsAndReset(); vfs->Reset(path_to_index); if (entry.id >= 0) { @@ -255,7 +256,6 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine, // Build delta update. IndexUpdate update = IndexUpdate::CreateDelta(prev.get(), curr.get()); - perf.index_make_delta = time.ElapsedMicrosecondsAndReset(); LOG_S(INFO) << "built index for " << path << " (is_delta=" << !!prev << ")"; on_indexed->PushBack({std::move(update), perf}, request.is_interactive); @@ -264,15 +264,6 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine, return true; } -// This function returns true if e2e timing should be displayed for the given -// MethodId. -bool ShouldDisplayMethodTiming(MethodType type) { - return - type != kMethodType_TextDocumentPublishDiagnostics && - type != kMethodType_CclsPublishInactiveRegions && - type != kMethodType_Unknown; -} - } // namespace void Init() { @@ -316,20 +307,22 @@ void Main_OnIndexed(DB* db, return; } - Timer time; + Timer timer("apply", "apply index"); + timer.startTimer(); db->ApplyIndexUpdate(&response->update); + timer.stopTimer(); // Update indexed content, inactive lines, and semantic highlighting. if (response->update.files_def_update) { auto& update = *response->update.files_def_update; - time.ResetAndPrint("apply index for " + update.value.path); + LOG_S(INFO) << "apply index for " << update.first.path; if (WorkingFile* working_file = - working_files->GetFileByFilename(update.value.path)) { + working_files->GetFileByFilename(update.first.path)) { // Update indexed content. - working_file->SetIndexContent(update.file_content); + working_file->SetIndexContent(update.second); // Inactive lines. - EmitInactiveLines(working_file, update.value.inactive_regions); + EmitInactiveLines(working_file, update.first.inactive_regions); // Semantic highlighting. int file_id = @@ -340,8 +333,8 @@ void Main_OnIndexed(DB* db, } } -void LaunchStdin(std::unordered_map* request_times) { - std::thread([request_times]() { +void LaunchStdin() { + std::thread([]() { set_thread_name("stdin"); while (true) { std::unique_ptr message; @@ -367,7 +360,6 @@ void LaunchStdin(std::unordered_map* request_times) { // Cache |method_id| so we can access it after moving |message|. MethodType method_type = message->GetMethodType(); - (*request_times)[method_type] = Timer(); on_request->PushBack(std::move(message)); @@ -379,7 +371,7 @@ void LaunchStdin(std::unordered_map* request_times) { }).detach(); } -void LaunchStdout(std::unordered_map* request_times) { +void LaunchStdout() { std::thread([=]() { set_thread_name("stdout"); @@ -391,11 +383,6 @@ void LaunchStdout(std::unordered_map* request_times) { } for (auto& message : messages) { - if (ShouldDisplayMethodTiming(message.method)) { - Timer time = (*request_times)[message.method]; - time.ResetAndPrint("[e2e] Running " + std::string(message.method)); - } - fwrite(message.content.c_str(), message.content.size(), 1, stdout); fflush(stdout); } diff --git a/src/pipeline.hh b/src/pipeline.hh index 760ac190..f21a44c7 100644 --- a/src/pipeline.hh +++ b/src/pipeline.hh @@ -2,7 +2,6 @@ #include "method.h" #include "query.h" -#include "timer.h" #include #include @@ -17,8 +16,8 @@ struct lsBaseOutMessage; namespace ccls::pipeline { void Init(); -void LaunchStdin(std::unordered_map* request_times); -void LaunchStdout(std::unordered_map* request_times); +void LaunchStdin(); +void LaunchStdout(); void Indexer_Main(DiagnosticsEngine* diag_engine, VFS* vfs, Project* project, diff --git a/src/query.cc b/src/query.cc index 77d5c212..85af80c9 100644 --- a/src/query.cc +++ b/src/query.cc @@ -148,7 +148,7 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) { return a.range.start < b.range.start; }); - return QueryFile::DefUpdate(def, indexed.file_contents); + return {std::move(def), std::move(indexed.file_contents)}; } // Returns true if an element with the same file is found. @@ -342,11 +342,11 @@ void DB::ApplyIndexUpdate(IndexUpdate* u) { int DB::Update(QueryFile::DefUpdate&& u) { int id = files.size(); - auto it = name2file_id.try_emplace(LowerPathIfInsensitive(u.value.path), id); + auto it = name2file_id.try_emplace(LowerPathIfInsensitive(u.first.path), id); if (it.second) files.emplace_back().id = id; QueryFile& existing = files[it.first->second]; - existing.def = u.value; + existing.def = u.first; return existing.id; } diff --git a/src/query.h b/src/query.h index 883a82d0..9c5e896d 100644 --- a/src/query.h +++ b/src/query.h @@ -7,21 +7,6 @@ #include #include -struct QueryFile; -struct QueryType; -struct QueryFunc; -struct QueryVar; -struct DB; - -template -struct WithFileContent { - T value; - std::string file_content; - - WithFileContent(const T& value, const std::string& file_content) - : value(value), file_content(file_content) {} -}; - struct QueryFile { struct Def { std::string path; @@ -39,7 +24,7 @@ struct QueryFile { std::vector dependencies; }; - using DefUpdate = WithFileContent; + using DefUpdate = std::pair; int id = -1; std::optional def; diff --git a/src/utils.cc b/src/utils.cc index 68de5189..9c17c129 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -134,6 +134,24 @@ std::optional LastWriteTime(const std::string& filename) { return Status.getLastModificationTime().time_since_epoch().count(); } +// Find discontinous |search| in |content|. +// Return |found| and the count of skipped chars before found. +int ReverseSubseqMatch(std::string_view pat, + std::string_view text, + int case_sensitivity) { + if (case_sensitivity == 1) + case_sensitivity = std::any_of(pat.begin(), pat.end(), isupper) ? 2 : 0; + int j = pat.size(); + if (!j) + return text.size(); + for (int i = text.size(); i--;) + if ((case_sensitivity ? text[i] == pat[j - 1] + : tolower(text[i]) == tolower(pat[j - 1])) && + !--j) + return i; + return -1; +} + std::string GetDefaultResourceDirectory() { return DEFAULT_RESOURCE_DIRECTORY; } diff --git a/src/utils.h b/src/utils.h index b1febec3..3b3bb511 100644 --- a/src/utils.h +++ b/src/utils.h @@ -58,6 +58,10 @@ std::optional ReadContent(const std::string& filename); void WriteToFile(const std::string& filename, const std::string& content); std::optional LastWriteTime(const std::string& filename); +int ReverseSubseqMatch(std::string_view pat, + std::string_view text, + int case_sensitivity); + // http://stackoverflow.com/a/38140932 // // struct SomeHashKey { diff --git a/src/working_files.cc b/src/working_files.cc index cfefda8a..d2448daf 100644 --- a/src/working_files.cc +++ b/src/working_files.cc @@ -1,6 +1,5 @@ #include "working_files.h" -#include "lex_utils.h" #include "log.hh" #include "position.h" @@ -545,3 +544,46 @@ WorkingFiles::Snapshot WorkingFiles::AsSnapshot( } return result; } + +// VSCode (UTF-16) disagrees with Emacs lsp-mode (UTF-8) on how to represent +// text documents. +// We use a UTF-8 iterator to approximate UTF-16 in the specification (weird). +// This is good enough and fails only for UTF-16 surrogate pairs. +int GetOffsetForPosition(lsPosition position, std::string_view content) { + size_t i = 0; + for (; position.line > 0 && i < content.size(); i++) + if (content[i] == '\n') + position.line--; + for (; position.character > 0 && i < content.size(); position.character--) + if (uint8_t(content[i++]) >= 128) { + // Skip 0b10xxxxxx + while (i < content.size() && uint8_t(content[i]) >= 128 && + uint8_t(content[i]) < 192) + i++; + } + return int(i); +} + +std::string_view LexIdentifierAroundPos(lsPosition position, + std::string_view content) { + int start = GetOffsetForPosition(position, content); + int end = start + 1; + char c; + + // We search for :: before the cursor but not after to get the qualifier. + for (; start > 0; start--) { + c = content[start - 1]; + if (isalnum(c) || c == '_') + ; + else if (c == ':' && start > 1 && content[start - 2] == ':') + start--; + else + break; + } + + for (; end < (int)content.size(); end++) + if (c = content[end], !(isalnum(c) || c == '_')) + break; + + return content.substr(start, end - start); +} diff --git a/src/working_files.h b/src/working_files.h index 46e71b99..69014989 100644 --- a/src/working_files.h +++ b/src/working_files.h @@ -117,3 +117,8 @@ struct WorkingFiles { std::vector> files; std::mutex files_mutex; // Protects |files|. }; + +int GetOffsetForPosition(lsPosition position, std::string_view content); + +std::string_view LexIdentifierAroundPos(lsPosition position, + std::string_view content);