diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d663909..5fe920cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -252,7 +252,6 @@ target_sources(ccls PRIVATE src/messages/ccls_base.cc src/messages/ccls_call_hierarchy.cc src/messages/ccls_callers.cc - src/messages/ccls_derived.cc src/messages/ccls_file_info.cc src/messages/ccls_freshen_index.cc src/messages/ccls_inheritance_hierarchy.cc @@ -272,6 +271,7 @@ target_sources(ccls PRIVATE src/messages/text_document_document_highlight.cc src/messages/text_document_document_symbol.cc src/messages/text_document_hover.cc + src/messages/text_document_implementation.cc src/messages/text_document_references.cc src/messages/text_document_rename.cc src/messages/text_document_signature_help.cc diff --git a/src/clang_complete.cc b/src/clang_complete.cc index 02961826..8ea334a8 100644 --- a/src/clang_complete.cc +++ b/src/clang_complete.cc @@ -275,7 +275,7 @@ void BuildDetailString(CXCompletionString completion_string, int num_chunks = clang_getNumCompletionChunks(completion_string); auto append = [&](const char* text) { detail += text; - if (do_insert) + if (do_insert && include_snippets) insert += text; }; for (int i = 0; i < num_chunks; ++i) { @@ -587,6 +587,8 @@ void DiagnosticQueryMain(ClangCompleteManager* completion_manager) { // Fetching the completion request blocks until we have a request. ClangCompleteManager::DiagnosticRequest request = completion_manager->diagnostic_request_.Dequeue(); + if (!g_config->diagnostics.onType) + continue; std::string path = request.document.uri.GetPath(); std::shared_ptr session = diff --git a/src/clang_cursor.cc b/src/clang_cursor.cc index 369da744..ab880b3d 100644 --- a/src/clang_cursor.cc +++ b/src/clang_cursor.cc @@ -131,6 +131,18 @@ Usr ClangCursor::get_usr_hash() const { return ret; } +std::optional ClangCursor::get_opt_usr_hash() const { + CXString usr = clang_getCursorUSR(cx_cursor); + const char* str = clang_getCString(usr); + if (!str || str[0] == '\0') { + clang_disposeString(usr); + return {}; + } + Usr ret = HashUsr(str); + clang_disposeString(usr); + return ret; +} + bool ClangCursor::is_definition() const { return clang_isCursorDefinition(cx_cursor); } diff --git a/src/clang_cursor.h b/src/clang_cursor.h index d0a1eed6..67acd08b 100644 --- a/src/clang_cursor.h +++ b/src/clang_cursor.h @@ -67,6 +67,7 @@ class ClangCursor { std::string get_display_name() const; std::string get_usr() const; Usr get_usr_hash() const; + std::optional get_opt_usr_hash() const; bool is_definition() const; @@ -108,15 +109,6 @@ class ClangCursor { CXCursor cx_cursor; }; -namespace std { -template <> -struct hash { - size_t operator()(const ClangCursor& x) const { - return clang_hashCursor(x.cx_cursor); - } -}; -} // namespace std - // Simple RAII wrapper about CXIndex. // Note: building a ClangIndex instance acquires a global lock, since libclang // API does not appear to be thread-safe here. diff --git a/src/clang_indexer.cc b/src/clang_indexer.cc index cf36a4c1..405d91b4 100644 --- a/src/clang_indexer.cc +++ b/src/clang_indexer.cc @@ -557,15 +557,10 @@ IndexType* ResolveToDeclarationType(IndexFile* db, ClangCursor declaration = type.get_declaration().template_specialization_to_template_definition(); - CXString cx_usr = clang_getCursorUSR(declaration.cx_cursor); - const char* str_usr = clang_getCString(cx_usr); - if (!str_usr || str_usr[0] == '\0') { - clang_disposeString(cx_usr); + std::optional usr = declaration.get_opt_usr_hash(); + if (!usr) return nullptr; - } - Usr usr = HashUsr(str_usr); - clang_disposeString(cx_usr); - IndexType& typ = db->ToType(usr); + IndexType& typ = db->ToType(*usr); if (typ.def.detailed_name.empty()) { std::string name = declaration.get_spell_name(); SetTypeName(typ, declaration, nullptr, name.c_str(), param); @@ -602,11 +597,12 @@ void SetVarDetail(IndexVar& var, param->ns.QualifiedName(semanticContainer, short_name); if (cursor.get_kind() == CXCursor_EnumConstantDecl && semanticContainer) { - CXType enum_type = clang_getCanonicalType( - clang_getEnumDeclIntegerType(semanticContainer->cursor)); + CXTypeKind k = clang_getCanonicalType( + clang_getEnumDeclIntegerType(semanticContainer->cursor)) + .kind; std::string hover = qualified_name + " = "; - if (enum_type.kind == CXType_UInt || enum_type.kind == CXType_ULong || - enum_type.kind == CXType_ULongLong) + if (k == CXType_Char_U || k == CXType_UChar || k == CXType_UShort || + k == CXType_UInt || k == CXType_ULong || k == CXType_ULongLong) hover += std::to_string( clang_getEnumConstantDeclUnsignedValue(cursor.cx_cursor)); else @@ -896,15 +892,15 @@ void VisitDeclForTypeUsageVisitorHandler(ClangCursor cursor, } } - std::string referenced_usr = + std::optional referenced_usr = cursor.get_referenced() .template_specialization_to_template_definition() - .get_usr(); - // TODO: things in STL cause this to be empty. Figure out why and document it. - if (referenced_usr == "") + .get_opt_usr_hash(); + // In STL this may be empty. + if (!referenced_usr) return; - IndexType& ref_type = db->ToType(HashUsr(referenced_usr)); + IndexType& ref_type = db->ToType(*referenced_usr); if (!param->initial_type) param->initial_type = &ref_type; @@ -1129,12 +1125,10 @@ ClangCursor::VisitResult AddDeclInitializerUsagesVisitor(ClangCursor cursor, // cursor.get_referenced().template_specialization_to_template_definition().get_type().strip_qualifiers().get_usr_hash(); auto ref_usr = cursor.get_referenced() .template_specialization_to_template_definition() - .get_usr(); - // std::string ref_usr = ref.get_usr_hash(); - if (ref_usr.empty()) + .get_opt_usr_hash(); + if (!ref_usr) break; - - IndexVar& ref_var = db->ToVar(HashUsr(ref_usr)); + IndexVar& ref_var = db->ToVar(*ref_usr); AddUseSpell(db, ref_var.uses, cursor); break; } @@ -1347,8 +1341,8 @@ std::tuple NamespaceHelper::QualifiedName( std::string qualifier; while (cursor.get_kind() != CXCursor_TranslationUnit && GetSymbolKind(cursor.get_kind()) == SymbolKind::Type) { - auto it = container_cursor_to_qualified_name.find(cursor); - if (it != container_cursor_to_qualified_name.end()) { + auto it = usr2qualified_name.find(cursor.get_usr_hash()); + if (it != usr2qualified_name.end()) { qualifier = it->second; break; } @@ -1365,7 +1359,7 @@ std::tuple NamespaceHelper::QualifiedName( else qualifier += GetAnonName(namespaces[i].get_kind()); qualifier += "::"; - container_cursor_to_qualified_name[namespaces[i]] = qualifier; + usr2qualified_name[namespaces[i].get_usr_hash()] = qualifier; } int16_t pos = qualifier.size(); qualifier.append(unqualified_name); @@ -2013,13 +2007,12 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) { } } -std::vector> Parse( +std::vector> ClangIndexer::Index( VFS* vfs, std::string file, const std::vector& args, const std::vector& file_contents, - PerformanceImportFile* perf, - ClangIndex* index) { + PerformanceImportFile* perf) { if (!g_config->index.enabled) return {}; @@ -2037,7 +2030,7 @@ std::vector> Parse( } std::unique_ptr tu = ClangTranslationUnit::Create( - index, file, args, unsaved_files, + &index, file, args, unsaved_files, CXTranslationUnit_KeepGoing | CXTranslationUnit_DetailedPreprocessingRecord); if (!tu) @@ -2045,7 +2038,7 @@ std::vector> Parse( perf->index_parse = timer.ElapsedMicrosecondsAndReset(); - return ParseWithTu(vfs, perf, tu.get(), index, file, args, unsaved_files); + return ParseWithTu(vfs, perf, tu.get(), &index, file, args, unsaved_files); } std::vector> ParseWithTu( @@ -2206,58 +2199,3 @@ void Reflect(Writer& visitor, Reference& value) { Reflect(visitor, value.role); } } - -namespace { - -struct TestIndexer : IIndexer { - static std::unique_ptr FromEntries( - const std::vector& entries) { - auto result = std::make_unique(); - - for (const TestEntry& entry : entries) { - std::vector> indexes; - - if (entry.num_indexes > 0) - indexes.push_back(std::make_unique(entry.path, "")); - for (int i = 1; i < entry.num_indexes; ++i) { - indexes.push_back(std::make_unique( - entry.path + "_extra_" + std::to_string(i) + ".h", "")); - } - - result->indexes.insert(std::make_pair(entry.path, std::move(indexes))); - } - - return result; - } - - std::vector> Index( - VFS* vfs, - std::string file, - const std::vector& args, - const std::vector& file_contents, - PerformanceImportFile* perf) override { - auto it = indexes.find(file); - if (it == indexes.end()) { - // Don't return any indexes for unexpected data. - assert(false && "no indexes"); - return {}; - } - - // FIXME: allow user to control how many times we return the index for a - // specific file (atm it is always 1) - auto result = std::move(it->second); - indexes.erase(it); - return result; - } - - std::unordered_map>> - indexes; -}; - -} // namespace - -// static -std::unique_ptr IIndexer::MakeTestIndexer( - std::initializer_list entries) { - return TestIndexer::FromEntries(entries); -} diff --git a/src/config.h b/src/config.h index ba90abbc..58946bac 100644 --- a/src/config.h +++ b/src/config.h @@ -137,6 +137,9 @@ struct Config { // If true, diagnostics from a full document parse will be reported. bool onParse = true; + // If true, diagnostics from typing will be reported. + bool onType = true; + std::vector whitelist; } diagnostics; @@ -211,6 +214,7 @@ MAKE_REFLECT_STRUCT(Config::ClientCapability, snippetSupport); MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables); MAKE_REFLECT_STRUCT(Config::Completion, caseSensitivity, + dropOldRequests, detailedLabel, filterAndSort, includeBlacklist, @@ -221,6 +225,7 @@ MAKE_REFLECT_STRUCT(Config::Diagnostics, blacklist, frequencyMs, onParse, + onType, whitelist) MAKE_REFLECT_STRUCT(Config::Highlight, blacklist, whitelist) MAKE_REFLECT_STRUCT(Config::Index, diff --git a/src/import_pipeline.cc b/src/import_pipeline.cc index f4cd7d5f..a2aef1c1 100644 --- a/src/import_pipeline.cc +++ b/src/import_pipeline.cc @@ -63,7 +63,7 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine, WorkingFiles* working_files, Project* project, VFS* vfs, - IIndexer* indexer) { + ClangIndexer* indexer) { auto* queue = QueueManager::instance(); std::optional opt_request = queue->index_request.TryPopFront(); if (!opt_request) @@ -211,10 +211,10 @@ void Indexer_Main(DiagnosticsEngine* diag_engine, MultiQueueWaiter* waiter) { auto* queue = QueueManager::instance(); // Build one index per-indexer, as building the index acquires a global lock. - auto indexer = std::make_unique(); + ClangIndexer indexer; while (true) - if (!Indexer_Parse(diag_engine, working_files, project, vfs, indexer.get())) + if (!Indexer_Parse(diag_engine, working_files, project, vfs, &indexer)) waiter->Wait(&queue->index_request); } diff --git a/src/indexer.h b/src/indexer.h index fce01508..e27c78e7 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -321,25 +321,13 @@ struct IndexFile { }; struct NamespaceHelper { - std::unordered_map - container_cursor_to_qualified_name; + std::unordered_map usr2qualified_name; std::tuple QualifiedName( const CXIdxContainerInfo* container, std::string_view unqualified_name); }; -// |import_file| is the cc file which is what gets passed to clang. -// |desired_index_file| is the (h or cc) file which has actually changed. -// |dependencies| are the existing dependencies of |import_file| if this is a -// reparse. -std::vector> Parse( - VFS* vfs, - std::string file, - const std::vector& args, - const std::vector& file_contents, - PerformanceImportFile* perf, - ClangIndex* index); std::vector> ParseWithTu( VFS* vfs, PerformanceImportFile* perf, @@ -353,36 +341,13 @@ bool ConcatTypeAndName(std::string& type, const std::string& name); void IndexInit(); -// Abstracts away the actual indexing process. Each IIndexer instance is -// per-thread and constructing an instance may be extremely expensive (ie, -// acquire a lock) and should be done as rarely as possible. -struct IIndexer { - struct TestEntry { - std::string path; - int num_indexes = 0; - }; - - static std::unique_ptr MakeTestIndexer( - std::initializer_list entries); - - virtual ~IIndexer() = default; - virtual std::vector> Index( - VFS* vfs, - std::string file, - const std::vector& args, - const std::vector& file_contents, - PerformanceImportFile* perf) = 0; -}; - -struct ClangIndexer : IIndexer { +struct ClangIndexer { std::vector> Index( VFS* vfs, std::string file, const std::vector& args, const std::vector& file_contents, - PerformanceImportFile* perf) override { - return Parse(vfs, file, args, file_contents, perf, &index); - } + PerformanceImportFile* perf); // Note: constructing this acquires a global lock ClangIndex index; diff --git a/src/messages/ccls_derived.cc b/src/messages/text_document_implementation.cc similarity index 72% rename from src/messages/ccls_derived.cc rename to src/messages/text_document_implementation.cc index 7a0c33eb..6bb5148f 100644 --- a/src/messages/ccls_derived.cc +++ b/src/messages/text_document_implementation.cc @@ -3,18 +3,19 @@ #include "queue_manager.h" namespace { -MethodType kMethodType = "$ccls/derived"; +MethodType kMethodType = "textDocument/implementation"; -struct In_CclsDerived : public RequestInMessage { +struct In_TextDocumentImplementation : public RequestInMessage { MethodType GetMethodType() const override { return kMethodType; } lsTextDocumentPositionParams params; }; -MAKE_REFLECT_STRUCT(In_CclsDerived, id, params); -REGISTER_IN_MESSAGE(In_CclsDerived); +MAKE_REFLECT_STRUCT(In_TextDocumentImplementation, id, params); +REGISTER_IN_MESSAGE(In_TextDocumentImplementation); -struct Handler_CclsDerived : BaseMessageHandler { +struct Handler_TextDocumentImplementation + : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } - void Run(In_CclsDerived* request) override { + void Run(In_TextDocumentImplementation* request) override { QueryFile* file; if (!FindFileOrFail(db, project, request->id, request->params.textDocument.uri.GetPath(), &file)) { @@ -43,5 +44,5 @@ struct Handler_CclsDerived : BaseMessageHandler { QueueManager::WriteStdout(kMethodType, out); } }; -REGISTER_MESSAGE_HANDLER(Handler_CclsDerived); +REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation); } // namespace diff --git a/src/test.cc b/src/test.cc index 74d85bf8..6cd4b2f7 100644 --- a/src/test.cc +++ b/src/test.cc @@ -247,7 +247,7 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) { bool update_all = false; // FIXME: show diagnostics in STL/headers when running tests. At the moment // this can be done by constructing ClangIndex index(1, 1); - ClangIndex index; + ClangIndexer index; GetFilesInFolder( "index_tests", true /*recursive*/, true /*add_folder_to_path*/, [&](const std::string& path) { @@ -294,7 +294,7 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) { g_config = std::make_unique(); VFS vfs; PerformanceImportFile perf; - auto dbs = Parse(&vfs, path, flags, {}, &perf, &index); + auto dbs = index.Index(&vfs, path, flags, {}, &perf); for (const auto& entry : all_expected_output) { const std::string& expected_path = entry.first; diff --git a/src/utils.h b/src/utils.h index 3c49bab8..4258ae49 100644 --- a/src/utils.h +++ b/src/utils.h @@ -49,11 +49,6 @@ std::string StringJoin(const TValues& values, const std::string& sep = ", ") { sep); } -template -bool ContainsValue(const TCollection& collection, const TValue& value) { - return collection.find(value) != collection.end(); -} - // Ensures that |path| ends in a slash. void EnsureEndsInSlash(std::string& path);