diff --git a/src/clang_complete.cc b/src/clang_complete.cc index ab90d6b8..ee6386ed 100644 --- a/src/clang_complete.cc +++ b/src/clang_complete.cc @@ -175,7 +175,9 @@ std::unique_ptr BuildCompilerInstance( CompletionSession &session, std::unique_ptr CI, DiagnosticConsumer &DC, const WorkingFiles::Snapshot &snapshot, std::vector> &Bufs) { - std::string main = ResolveIfRelative(session.file.directory, CI->getFrontendOpts().Inputs[0].getFile()); + std::string main = ResolveIfRelative( + session.file.directory, + sys::path::convert_to_slash(CI->getFrontendOpts().Inputs[0].getFile())); for (auto &file : snapshot.files) { Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(file.content)); if (file.filename == main) diff --git a/src/indexer.cc b/src/indexer.cc index 069f4e41..11fb859d 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -22,7 +22,6 @@ limitations under the License. #include "pipeline.hh" #include "platform.h" #include "serializer.h" -using namespace ccls; #include #include @@ -33,16 +32,15 @@ using namespace ccls; #include #include #include -#include -using namespace clang; -using llvm::Timer; #include #include -#include #include #include +using namespace ccls; +using namespace clang; + namespace { constexpr int kInitializerMaxLines = 3; @@ -509,7 +507,7 @@ public: def.short_name_offset = Str.size() + qualified.size() - short_name.size(); def.short_name_size = short_name.size(); Str += StringRef(qualified.data(), qualified.size()); - def.detailed_name = Intern(Str.str()); + def.detailed_name = Intern(Str); } else { SetName(D, short_name, qualified, def); } diff --git a/src/indexer.h b/src/indexer.h index 553ee640..f74e2f8c 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -30,7 +30,6 @@ limitations under the License. #include #include -#include #include #include #include diff --git a/src/main.cc b/src/main.cc index 55880343..4d2fb679 100644 --- a/src/main.cc +++ b/src/main.cc @@ -20,15 +20,12 @@ limitations under the License. #include "serializers/json.h" #include "test.h" #include "working_files.h" -using namespace ccls; #include #include #include #include #include -using namespace llvm; -using namespace llvm::cl; #include @@ -38,6 +35,10 @@ using namespace llvm::cl; #include #include +using namespace ccls; +using namespace llvm; +using namespace llvm::cl; + std::string g_init_options; namespace { diff --git a/src/message_handler.h b/src/message_handler.h index 1d790432..2e420dc3 100644 --- a/src/message_handler.h +++ b/src/message_handler.h @@ -87,7 +87,6 @@ MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting, jsonrpc, method, struct MessageHandler { DB *db = nullptr; - MultiQueueWaiter *waiter = nullptr; Project *project = nullptr; VFS *vfs = nullptr; SemanticHighlight *highlight = nullptr; diff --git a/src/messages/ccls_call.cc b/src/messages/ccls_call.cc index 98016480..0ec68f8b 100644 --- a/src/messages/ccls_call.cc +++ b/src/messages/ccls_call.cc @@ -17,10 +17,11 @@ limitations under the License. #include "message_handler.h" #include "pipeline.hh" #include "query_utils.h" -using namespace ccls; #include +using namespace ccls; + namespace { MethodType kMethodType = "$ccls/call"; diff --git a/src/messages/ccls_member.cc b/src/messages/ccls_member.cc index e95c7065..f17699e9 100644 --- a/src/messages/ccls_member.cc +++ b/src/messages/ccls_member.cc @@ -17,14 +17,15 @@ limitations under the License. #include "message_handler.h" #include "pipeline.hh" #include "query_utils.h" -using namespace ccls; #include #include -using namespace clang; #include +using namespace ccls; +using namespace clang; + namespace { MethodType kMethodType = "$ccls/member"; diff --git a/src/messages/ccls_reload.cc b/src/messages/ccls_reload.cc index 6a450655..67b97c25 100644 --- a/src/messages/ccls_reload.cc +++ b/src/messages/ccls_reload.cc @@ -17,14 +17,14 @@ limitations under the License. #include "match.h" #include "message_handler.h" #include "pipeline.hh" -#include "platform.h" #include "project.h" #include "working_files.h" -using namespace ccls; #include #include +using namespace ccls; + namespace { MethodType kMethodType = "$ccls/reload"; @@ -34,8 +34,7 @@ struct In_CclsReload : public NotificationInMessage { bool dependencies = true; std::vector whitelist; std::vector blacklist; - }; - Params params; + } params; }; MAKE_REFLECT_STRUCT(In_CclsReload::Params, dependencies, whitelist, blacklist); diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index cb795148..d8039aee 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -23,16 +23,16 @@ limitations under the License. #include "project.h" #include "serializers/json.h" #include "working_files.h" -using namespace ccls; #include #include -using namespace llvm; -#include #include #include +using namespace ccls; +using namespace llvm; + // TODO Cleanup global variables extern std::string g_init_options; diff --git a/src/messages/textDocument_completion.cc b/src/messages/textDocument_completion.cc index 474d1df8..411e4763 100644 --- a/src/messages/textDocument_completion.cc +++ b/src/messages/textDocument_completion.cc @@ -20,16 +20,16 @@ limitations under the License. #include "message_handler.h" #include "pipeline.hh" #include "working_files.h" -using namespace ccls; #include #include -#include -using namespace clang; -using namespace llvm; #include +using namespace ccls; +using namespace clang; +using namespace llvm; + namespace { MethodType kMethodType = "textDocument/completion"; @@ -179,10 +179,6 @@ void FilterAndSortCompletionResponse( const std::string &complete_text, bool has_open_paren) { if (!g_config->completion.filterAndSort) return; - - static Timer timer("FilterAndSortCompletionResponse", ""); - TimeRegion region(timer); - auto &items = complete_response->result.items; auto finalize = [&]() { diff --git a/src/messages/textDocument_definition.cc b/src/messages/textDocument_definition.cc index 7cff442c..df28502d 100644 --- a/src/messages/textDocument_definition.cc +++ b/src/messages/textDocument_definition.cc @@ -16,11 +16,12 @@ limitations under the License. #include "message_handler.h" #include "pipeline.hh" #include "query_utils.h" -using namespace ccls; -#include #include #include +#include + +using namespace ccls; namespace { MethodType kMethodType = "textDocument/definition"; diff --git a/src/messages/textDocument_didClose.cc b/src/messages/textDocument_didClose.cc index c905f154..a7344e5d 100644 --- a/src/messages/textDocument_didClose.cc +++ b/src/messages/textDocument_didClose.cc @@ -26,8 +26,7 @@ struct In_TextDocumentDidClose : public NotificationInMessage { MethodType GetMethodType() const override { return kMethodType; } struct Params { lsTextDocumentIdentifier textDocument; - }; - Params params; + } params; }; MAKE_REFLECT_STRUCT(In_TextDocumentDidClose::Params, textDocument); MAKE_REFLECT_STRUCT(In_TextDocumentDidClose, params); diff --git a/src/messages/textDocument_didOpen.cc b/src/messages/textDocument_didOpen.cc index 27eb8f41..ec1b925a 100644 --- a/src/messages/textDocument_didOpen.cc +++ b/src/messages/textDocument_didOpen.cc @@ -24,7 +24,6 @@ using namespace ccls; namespace { MethodType kMethodType = "textDocument/didOpen"; -// Open, view, change, close file struct In_TextDocumentDidOpen : public NotificationInMessage { MethodType GetMethodType() const override { return kMethodType; } @@ -49,7 +48,7 @@ struct Handler_TextDocumentDidOpen // NOTE: This function blocks code lens. If it starts taking a long time // we will need to find a way to unblock the code lens request. const auto ¶ms = request->params; - std::string path = params.textDocument.uri.GetPath(); + const std::string &path = params.textDocument.uri.GetPath(); WorkingFile *working_file = working_files->OnOpen(params.textDocument); if (std::optional cached_file_contents = diff --git a/src/messages/textDocument_didSave.cc b/src/messages/textDocument_didSave.cc index 87b7e793..f00ecc11 100644 --- a/src/messages/textDocument_didSave.cc +++ b/src/messages/textDocument_didSave.cc @@ -16,7 +16,6 @@ limitations under the License. #include "clang_complete.hh" #include "message_handler.h" #include "pipeline.hh" -#include "project.h" using namespace ccls; namespace { @@ -44,7 +43,7 @@ struct Handler_TextDocumentDidSave void Run(In_TextDocumentDidSave *request) override { const auto ¶ms = request->params; - std::string path = params.textDocument.uri.GetPath(); + const std::string &path = params.textDocument.uri.GetPath(); pipeline::Index(path, {}, IndexMode::Normal); clang_complete->NotifySave(path); } diff --git a/src/messages/textDocument_references.cc b/src/messages/textDocument_references.cc index 0c73a405..f09adfc8 100644 --- a/src/messages/textDocument_references.cc +++ b/src/messages/textDocument_references.cc @@ -16,10 +16,11 @@ limitations under the License. #include "message_handler.h" #include "pipeline.hh" #include "query_utils.h" -using namespace ccls; #include +using namespace ccls; + namespace { MethodType kMethodType = "textDocument/references"; @@ -66,13 +67,17 @@ struct Handler_TextDocumentReferences if (!FindFileOrFail(db, project, request->id, params.textDocument.uri.GetPath(), &file)) return; - - WorkingFile *wfile = working_files->GetFileByFilename(file->def->path); - Out_TextDocumentReferences out; out.id = request->id; + WorkingFile *wfile = working_files->GetFileByFilename(file->def->path); + if (!file) { + pipeline::WriteStdout(kMethodType, out); + return; + } + bool container = g_config->xref.container; std::unordered_set seen_uses; + int line = params.position.line; for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position)) { // Found symbol. Return references. @@ -127,7 +132,7 @@ struct Handler_TextDocumentReferences // = 0, // use the current filename. std::string path; - if (params.position.line == 0) + if (line == 0 || line >= (int)wfile->buffer_lines.size() - 1) path = file->def->path; for (const IndexInclude &include : file->def->includes) if (include.line == params.position.line) { diff --git a/src/messages/textDocument_signatureHelp.cc b/src/messages/textDocument_signatureHelp.cc index 007003db..1635cb35 100644 --- a/src/messages/textDocument_signatureHelp.cc +++ b/src/messages/textDocument_signatureHelp.cc @@ -16,12 +16,11 @@ limitations under the License. #include "clang_complete.hh" #include "message_handler.h" #include "pipeline.hh" -using namespace ccls; #include -using namespace clang; -#include +using namespace ccls; +using namespace clang; namespace { MethodType kMethodType = "textDocument/signatureHelp"; diff --git a/src/messages/workspace_symbol.cc b/src/messages/workspace_symbol.cc index c78e9462..4758b38e 100644 --- a/src/messages/workspace_symbol.cc +++ b/src/messages/workspace_symbol.cc @@ -17,13 +17,14 @@ limitations under the License. #include "message_handler.h" #include "pipeline.hh" #include "query_utils.h" -using namespace ccls; #include #include #include #include +using namespace ccls; + namespace { MethodType kMethodType = "workspace/symbol"; diff --git a/src/pipeline.cc b/src/pipeline.cc index 9864a09b..4810c87c 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -490,7 +490,6 @@ void MainLoop() { // Setup shared references. for (MessageHandler *handler : *MessageHandler::message_handlers) { handler->db = &db; - handler->waiter = indexer_waiter; handler->project = &project; handler->vfs = &vfs; handler->highlight = &highlight; @@ -499,6 +498,7 @@ void MainLoop() { handler->include_complete = &include_complete; } + bool last_indexed = false; while (true) { std::vector> messages = on_request->DequeueAll(); bool did_work = messages.size(); @@ -515,18 +515,22 @@ void MainLoop() { LOG_S(ERROR) << "No handler for " << message->GetMethodType(); } - for (int i = 80; i--;) { + bool indexed = false; + for (int i = 20; i--;) { std::optional update = on_indexed->TryPopFront(); if (!update) break; did_work = true; + indexed = true; Main_OnIndexed(&db, &highlight, &working_files, &*update); } if (!did_work) { - FreeUnusedMemory(); + if (last_indexed) + FreeUnusedMemory(); main_waiter->Wait(on_indexed, on_request); } + last_indexed = indexed; } } diff --git a/src/platform_posix.cc b/src/platform_posix.cc index 4f48896c..1d2d59a9 100644 --- a/src/platform_posix.cc +++ b/src/platform_posix.cc @@ -113,7 +113,7 @@ std::string NormalizePath(const std::string &path) { void FreeUnusedMemory() { #ifdef __GLIBC__ - malloc_trim(0); + malloc_trim(4 * 1024 * 1024); #endif } diff --git a/src/project.cc b/src/project.cc index f4beb6c0..534d08fa 100644 --- a/src/project.cc +++ b/src/project.cc @@ -25,18 +25,14 @@ limitations under the License. #include "serializers/json.h" #include "utils.h" #include "working_files.h" -using namespace ccls; #include #include #include #include -#include #include #include #include -using namespace clang; -using namespace llvm; #include @@ -44,10 +40,14 @@ using namespace llvm; #include #endif -#include +#include #include #include +using namespace ccls; +using namespace clang; +using namespace llvm; + namespace { enum class ProjectMode { CompileCommandsJson, DotCcls, ExternalCommand }; @@ -399,7 +399,7 @@ Project::FindCompilationEntryForFile(const std::string &filename) { // We couldn't find the file. Try to infer it. // TODO: Cache inferred file in a separate array (using a lock or similar) Entry *best_entry = nullptr; - int best_score = std::numeric_limits::min(); + int best_score = INT_MIN; for (Entry &entry : entries) { int score = ComputeGuessScore(filename, entry.filename); if (score > best_score) { diff --git a/src/serializer.cc b/src/serializer.cc index 8faf8ebd..68c80493 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -166,12 +166,11 @@ void Reflect(Reader &vis, DenseMap &v) { if (vis.Format() == SerializeFormat::Json) { auto &vis1 = static_cast(vis); for (auto it = vis1.m().MemberBegin(); it != vis1.m().MemberEnd(); ++it) - v[CachedHashStringRef(Intern(it->name.GetString()))] = - it->value.GetInt64(); + v[InternH(it->name.GetString())] = it->value.GetInt64(); } else { vis.IterArray([&](Reader &entry) { Reflect(entry, name); - Reflect(entry, v[CachedHashStringRef(Intern(name))]); + Reflect(entry, v[InternH(name)]); }); } } @@ -356,18 +355,26 @@ void Reflect(Writer &visitor, SerializeFormat &value) { namespace ccls { static BumpPtrAllocator Alloc; -static DenseSet Strings; +static DenseSet Strings; static std::mutex AllocMutex; -const char *Intern(const std::string &str) { - if (str.empty()) - return ""; - StringRef Str(str.data(), str.size() + 1); +CachedHashStringRef InternH(StringRef S) { + if (S.empty()) + S = ""; + CachedHashString HS(S); std::lock_guard lock(AllocMutex); - auto R = Strings.insert(Str); - if (R.second) - *R.first = Str.copy(Alloc); - return R.first->data(); + auto R = Strings.insert(HS); + if (R.second) { + char *P = Alloc.Allocate(S.size() + 1); + memcpy(P, S.data(), S.size()); + P[S.size()] = '\0'; + *R.first = CachedHashStringRef(StringRef(P, S.size()), HS.hash()); + } + return *R.first; +} + +const char *Intern(StringRef S) { + return InternH(S).val().data(); } std::string Serialize(SerializeFormat format, IndexFile &file) { @@ -482,7 +489,7 @@ Deserialize(SerializeFormat format, const std::string &path, for (auto &it : file->dependencies) { std::string path = it.first.val().str(); DoPathMapping(path); - dependencies[CachedHashStringRef(Intern(path))] = it.second; + dependencies[InternH(path)] = it.second; } file->dependencies = std::move(dependencies); } diff --git a/src/serializer.h b/src/serializer.h index 7e248715..5e05a475 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -30,6 +30,11 @@ limitations under the License. #include #include +namespace llvm { +class CachedHashStringRef; +class StringRef; +} + enum class SerializeFormat { Binary, Json }; struct JsonNull {}; @@ -320,7 +325,8 @@ template void ReflectMember(Writer &vis, const char *name, T &v) { // API namespace ccls { -const char *Intern(const std::string &str); +const char *Intern(llvm::StringRef str); +llvm::CachedHashStringRef InternH(llvm::StringRef str); std::string Serialize(SerializeFormat format, IndexFile &file); std::unique_ptr Deserialize(SerializeFormat format, const std::string &path,