diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -976,7 +976,12 @@ if (!List) return Reply(List.takeError()); CompletionList LSPList; - LSPList.isIncomplete = List->HasMore; + // Set isIncomplete to true regardless of the actual + // results if the corresponding flag was added to + // Clangd invocation. + LSPList.isIncomplete = + ClangdServerOpts.AlwaysIncomplete ? true + : List->HasMore; for (const auto &R : List->Completions) { CompletionItem C = R.render(CCOpts); C.kind = adjustKindToCapability( diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -145,6 +145,9 @@ /// Enable cross-file rename feature. bool CrossFileRename = false; + /// Always set isIncomplete to true when returning CompletionList. + bool AlwaysIncomplete = false; + /// Returns true if the tweak should be enabled. std::function TweakFilter = [](const Tweak &T) { return !T.hidden(); // only enable non-hidden tweaks. @@ -295,7 +298,7 @@ /// Get all document links in a file. void documentLinks(PathRef File, Callback> CB); - + /// Returns estimated memory usage for each of the currently open files. /// The order of results is unspecified. /// Overall memory usage of clangd may be significantly more than reported diff --git a/clang-tools-extra/clangd/test/always-incomplete.test b/clang-tools-extra/clangd/test/always-incomplete.test new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/test/always-incomplete.test @@ -0,0 +1,39 @@ +# RUN: clangd -lit-test --always-incomplete < %s | FileCheck -strict-whitespace %s +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} +--- +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"struct S { int a; };\nint main() {\nS().\n}"}}} +--- +{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":4}}} +# CHECK: "id": 1 +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": { +# CHECK-NEXT: "isIncomplete": true, +# CHECK-NEXT: "items": [ +# CHECK-NEXT: { +# CHECK-NEXT: "detail": "int", +# CHECK-NEXT: "filterText": "a", +# CHECK-NEXT: "insertText": "a", +# CHECK-NEXT: "insertTextFormat": 1, +# CHECK-NEXT: "kind": 5, +# CHECK-NEXT: "label": " a", +# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}}, +# CHECK-NEXT: "sortText": "{{.*}}a" +# CHECK-NEXT: "textEdit": { +# CHECK-NEXT: "newText": "a", +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 4, +# CHECK-NEXT: "line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 4, +# CHECK-NEXT: "line": 2 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: ] +--- +{"jsonrpc":"2.0","id":4,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -402,6 +402,14 @@ init(false), }; +opt AlwaysIncomplete{ + "always-incomplete", + cat(Protocol), + desc("Always sets code completion list's isIncomplete to true"), + init(false), + Hidden, +}; + /// Supports a test URI scheme with relaxed constraints for lit tests. /// The path in a test URI will be combined with a platform-specific fake /// directory to form an absolute path. For example, test:///a.cpp is resolved @@ -629,6 +637,7 @@ Opts.StaticIndex = StaticIdx.get(); Opts.AsyncThreadsCount = WorkerThreadsCount; Opts.CrossFileRename = CrossFileRename; + Opts.AlwaysIncomplete = AlwaysIncomplete; clangd::CodeCompleteOptions CCOpts; CCOpts.IncludeIneligibleResults = IncludeIneligibleResults;