[PATCH] D31328: [clangd] Add code completion support
This revision was automatically updated to reflect the committed changes. Closed by commit rL299421: [clangd] Add code completion support (authored by krasimir). Changed prior to commit: https://reviews.llvm.org/D31328?vs=92948&id=94026#toc Repository: rL LLVM https://reviews.llvm.org/D31328 Files: clang-tools-extra/trunk/clangd/ASTManager.cpp clang-tools-extra/trunk/clangd/ASTManager.h clang-tools-extra/trunk/clangd/ClangDMain.cpp clang-tools-extra/trunk/clangd/Protocol.cpp clang-tools-extra/trunk/clangd/Protocol.h clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp clang-tools-extra/trunk/clangd/ProtocolHandlers.h clang-tools-extra/trunk/test/clangd/completion.test clang-tools-extra/trunk/test/clangd/formatting.test Index: clang-tools-extra/trunk/clangd/Protocol.cpp === --- clang-tools-extra/trunk/clangd/Protocol.cpp +++ clang-tools-extra/trunk/clangd/Protocol.cpp @@ -570,3 +570,75 @@ } return Result; } + +llvm::Optional +TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params) { + TextDocumentPositionParams Result; + for (auto &NextKeyValue : *Params) { +auto *KeyString = dyn_cast(NextKeyValue.getKey()); +if (!KeyString) + return llvm::None; + +llvm::SmallString<10> KeyStorage; +StringRef KeyValue = KeyString->getValue(KeyStorage); +auto *Value = +dyn_cast_or_null(NextKeyValue.getValue()); +if (!Value) + return llvm::None; + +llvm::SmallString<10> Storage; +if (KeyValue == "textDocument") { + auto Parsed = TextDocumentIdentifier::parse(Value); + if (!Parsed) +return llvm::None; + Result.textDocument = std::move(*Parsed); +} else if (KeyValue == "position") { + auto Parsed = Position::parse(Value); + if (!Parsed) +return llvm::None; + Result.position = std::move(*Parsed); +} else { + return llvm::None; +} + } + return Result; +} + +std::string CompletionItem::unparse(const CompletionItem &CI) { + std::string Result = "{"; + llvm::raw_string_ostream Os(Result); + assert(!CI.label.empty() && "completion item label is required"); + Os << R"("label":")" << llvm::yaml::escape(CI.label) << R"(",)"; + if (CI.kind != CompletionItemKind::Missing) +Os << R"("kind":)" << static_cast(CI.kind) << R"(",)"; + if (!CI.detail.empty()) +Os << R"("detail":")" << llvm::yaml::escape(CI.detail) << R"(",)"; + if (!CI.documentation.empty()) +Os << R"("documentation":")" << llvm::yaml::escape(CI.documentation) + << R"(",)"; + if (!CI.sortText.empty()) +Os << R"("sortText":")" << llvm::yaml::escape(CI.sortText) << R"(",)"; + if (!CI.filterText.empty()) +Os << R"("filterText":")" << llvm::yaml::escape(CI.filterText) << R"(",)"; + if (!CI.insertText.empty()) +Os << R"("insertText":")" << llvm::yaml::escape(CI.insertText) << R"(",)"; + if (CI.insertTextFormat != InsertTextFormat::Missing) { +Os << R"("insertTextFormat":")" << static_cast(CI.insertTextFormat) + << R"(",)"; + } + if (CI.textEdit) +Os << R"("textEdit":)" << TextEdit::unparse(*CI.textEdit) << ','; + if (!CI.additionalTextEdits.empty()) { +Os << R"("additionalTextEdits":[)"; +for (const auto &Edit : CI.additionalTextEdits) + Os << TextEdit::unparse(Edit) << ","; +Os.flush(); +// The list additionalTextEdits is guaranteed nonempty at this point. +// Replace the trailing comma with right brace. +Result.back() = ']'; + } + Os.flush(); + // Label is required, so Result is guaranteed to have a trailing comma. + Result.back() = '}'; + return Result; +} Index: clang-tools-extra/trunk/clangd/ClangDMain.cpp === --- clang-tools-extra/trunk/clangd/ClangDMain.cpp +++ clang-tools-extra/trunk/clangd/ClangDMain.cpp @@ -61,6 +61,8 @@ llvm::make_unique(Out, Store)); Dispatcher.registerHandler("textDocument/codeAction", llvm::make_unique(Out, AST)); + Dispatcher.registerHandler("textDocument/completion", + llvm::make_unique(Out, AST)); while (std::cin.good()) { // A Language Server Protocol message starts with a HTTP header, delimited Index: clang-tools-extra/trunk/clangd/ProtocolHandlers.h === --- clang-tools-extra/trunk/clangd/ProtocolHandlers.h +++ clang-tools-extra/trunk/clangd/ProtocolHandlers.h @@ -36,7 +36,8 @@ "documentFormattingProvider": true, "documentRangeFormattingProvider": true, "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, - "codeActionProvider": true + "codeActionProvider": true, + "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]} }}})"); } }; @@ -114,6 +115,16 @@ ASTManager &AST; }; +struct CompletionH
[PATCH] D31328: [clangd] Add code completion support
stanionascu added inline comments. Comment at: clangd/Protocol.cpp:613 + if (CI.kind != CompletionItemKind::Missing) +Os << R"("kind":)" << static_cast(CI.kind) << R"(",)"; + if (!CI.detail.empty()) if kind is actually provided there will be a trailing quote, as in ("kind": 4"). https://reviews.llvm.org/D31328 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D31328: [clangd] Add code completion support
bkramer accepted this revision. bkramer added a comment. lg https://reviews.llvm.org/D31328 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D31328: [clangd] Add code completion support
malaperle-ericsson added a comment. Ideas/Observations: - One thing I has done in my version is to introduce "ASTUnitRunnable", a lambda function type that has an ASTUnit as parameter and is executed by the ASTManager. So the ASTManager takes care of locking the AST but the actual code using the AST is kept in the ProtocolHandlers. I think this can be refactored later if this is seen as a good approach. - I have noticed while testing that there is some wrong escaping happening. I had typed "รน" by mistake (french keyboard layout!) and it threw an error about unexpected \x. I think using yaml::escape is not entirely correct. This can be addressed in a different patch because it affects other protocol handlers as well (diagnostics, etc). - I noticed that "file://" is stripped from file:///path but not "file:" in file:/path, I think it's the Eclipse client that's wrong here. But I don't see any immediate need to change anything in this patch. https://reviews.llvm.org/D31328 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D31328: [clangd] Add code completion support
malaperle-ericsson added inline comments. Comment at: test/clangd/formatting.test:14 +# CHECK: "codeActionProvider": true, +# CHECK: "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]} # CHECK: }}} It would be good eventually to trigger on "::" (static members, etc) https://reviews.llvm.org/D31328 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D31328: [clangd] Add code completion support
krasimir updated this revision to Diff 92948. krasimir added a comment. - Make Items ownership more explicit https://reviews.llvm.org/D31328 Files: clangd/ASTManager.cpp clangd/ASTManager.h clangd/ClangDMain.cpp clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h test/clangd/completion.test test/clangd/formatting.test Index: test/clangd/formatting.test === --- test/clangd/formatting.test +++ test/clangd/formatting.test @@ -4,13 +4,14 @@ Content-Length: 125 {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} -# CHECK: Content-Length: 332 +# CHECK: Content-Length: 424 # CHECK: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{ # CHECK: "textDocumentSync": 1, # CHECK: "documentFormattingProvider": true, # CHECK: "documentRangeFormattingProvider": true, # CHECK: "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, -# CHECK: "codeActionProvider": true +# CHECK: "codeActionProvider": true, +# CHECK: "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]} # CHECK: }}} # Content-Length: 193 Index: test/clangd/completion.test === --- /dev/null +++ test/clangd/completion.test @@ -0,0 +1,69 @@ +# RUN: clangd -run-synchronously < %s | FileCheck %s +# It is absolutely vital that this file has CRLF line endings. +# +Content-Length: 125 + +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} + +Content-Length: 208 + +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"#include \nint main() {\n std::vector v;\n v.\n}\n"}}} + +Content-Length: 148 + +{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":4}}} +# The order of results returned by ASTUnit CodeComplete seems to be +# nondeterministic, so we check regardless of order. +# +# CHECK: {"jsonrpc":"2.0","id":1,"result":[ +# CHECK-DAG: {"label":"_M_allocate"} +# CHECK-DAG: {"label":"_M_allocate_and_copy"} +# CHECK-DAG: {"label":"_M_assign_aux"} +# CHECK-DAG: {"label":"_M_assign_dispatch"} +# CHECK-DAG: {"label":"_M_check_len"} +# CHECK-DAG: {"label":"_M_create_storage" +# CHECK-DAG: {"label":"_M_deallocate"} +# CHECK-DAG: {"label":"_M_erase_at_end"} +# CHECK-DAG: {"label":"_M_fill_assign"} +# CHECK-DAG: {"label":"_M_fill_initialize"} +# CHECK-DAG: {"label":"_M_fill_insert"} +# CHECK-DAG: {"label":"_M_get_Tp_allocator"} +# CHECK-DAG: {"label":"_M_impl"} +# CHECK-DAG: {"label":"_M_initialize_dispatch"} +# CHECK-DAG: {"label":"_M_insert_aux"} +# CHECK-DAG: {"label":"_M_insert_dispatch"} +# CHECK-DAG: {"label":"_M_range_check"} +# CHECK-DAG: {"label":"_M_range_initialize"} +# CHECK-DAG: {"label":"_M_range_insert"} +# CHECK-DAG: {"label":"_Vector_base"} +# CHECK-DAG: {"label":"assign"} +# CHECK-DAG: {"label":"at"} +# CHECK-DAG: {"label":"back"} +# CHECK-DAG: {"label":"begin"} +# CHECK-DAG: {"label":"capacity"} +# CHECK-DAG: {"label":"clear"} +# CHECK-DAG: {"label":"data"} +# CHECK-DAG: {"label":"empty"} +# CHECK-DAG: {"label":"end"} +# CHECK-DAG: {"label":"erase"} +# CHECK-DAG: {"label":"front"} +# CHECK-DAG: {"label":"get_allocator"} +# CHECK-DAG: {"label":"insert"} +# CHECK-DAG: {"label":"max_size"} +# CHECK-DAG: {"label":"operator="} +# CHECK-DAG: {"label":"operator[]"} +# CHECK-DAG: {"label":"pop_back"} +# CHECK-DAG: {"label":"push_back"} +# CHECK-DAG: {"label":"rbegin"} +# CHECK-DAG: {"label":"rend"} +# CHECK-DAG: {"label":"reserve"} +# CHECK-DAG: {"label":"resize"} +# CHECK-DAG: {"label":"size"} +# CHECK-DAG: {"label":"swap"} +# CHECK-DAG: {"label":"vector"} +# CHECK-DAG: {"label":"~_Vector_base"} +# CHECK-DAG: {"label":"~vector"} +# CHECK: ]} +Content-Length: 44 + +{"jsonrpc":"2.0","id":3,"method":"shutdown"} Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -36,7 +36,8 @@ "documentFormattingProvider": true, "documentRangeFormattingProvider": true, "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, - "codeActionProvider": true + "codeActionProvider": true, + "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]} }}})"); } }; @@ -114,6 +115,16 @@ ASTManager &AST; }; +struct CompletionHandler : Handler { + CompletionHandler(JSONOutput &Output, ASTManager &AST) + : Handler(Output), AST(AST) {} + + void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override; + + private: + ASTManager &AST; +}; + }
[PATCH] D31328: [clangd] Add code completion support
malaperle-ericsson added a comment. Urg, I was working on this too :) I'll compare implementations and provide comments if I find anything good to suggest. https://reviews.llvm.org/D31328 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D31328: [clangd] Add code completion support
krasimir updated this revision to Diff 92940. krasimir marked 7 inline comments as done. krasimir added a comment. - Address review comments https://reviews.llvm.org/D31328 Files: clangd/ASTManager.cpp clangd/ASTManager.h clangd/ClangDMain.cpp clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h test/clangd/completion.test test/clangd/formatting.test Index: test/clangd/formatting.test === --- test/clangd/formatting.test +++ test/clangd/formatting.test @@ -4,13 +4,14 @@ Content-Length: 125 {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} -# CHECK: Content-Length: 332 +# CHECK: Content-Length: 424 # CHECK: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{ # CHECK: "textDocumentSync": 1, # CHECK: "documentFormattingProvider": true, # CHECK: "documentRangeFormattingProvider": true, # CHECK: "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, -# CHECK: "codeActionProvider": true +# CHECK: "codeActionProvider": true, +# CHECK: "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]} # CHECK: }}} # Content-Length: 193 Index: test/clangd/completion.test === --- /dev/null +++ test/clangd/completion.test @@ -0,0 +1,69 @@ +# RUN: clangd -run-synchronously < %s | FileCheck %s +# It is absolutely vital that this file has CRLF line endings. +# +Content-Length: 125 + +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} + +Content-Length: 208 + +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"#include \nint main() {\n std::vector v;\n v.\n}\n"}}} + +Content-Length: 148 + +{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":4}}} +# The order of results returned by ASTUnit CodeComplete seems to be +# nondeterministic, so we check regardless of order. +# +# CHECK: {"jsonrpc":"2.0","id":1,"result":[ +# CHECK-DAG: {"label":"_M_allocate"} +# CHECK-DAG: {"label":"_M_allocate_and_copy"} +# CHECK-DAG: {"label":"_M_assign_aux"} +# CHECK-DAG: {"label":"_M_assign_dispatch"} +# CHECK-DAG: {"label":"_M_check_len"} +# CHECK-DAG: {"label":"_M_create_storage" +# CHECK-DAG: {"label":"_M_deallocate"} +# CHECK-DAG: {"label":"_M_erase_at_end"} +# CHECK-DAG: {"label":"_M_fill_assign"} +# CHECK-DAG: {"label":"_M_fill_initialize"} +# CHECK-DAG: {"label":"_M_fill_insert"} +# CHECK-DAG: {"label":"_M_get_Tp_allocator"} +# CHECK-DAG: {"label":"_M_impl"} +# CHECK-DAG: {"label":"_M_initialize_dispatch"} +# CHECK-DAG: {"label":"_M_insert_aux"} +# CHECK-DAG: {"label":"_M_insert_dispatch"} +# CHECK-DAG: {"label":"_M_range_check"} +# CHECK-DAG: {"label":"_M_range_initialize"} +# CHECK-DAG: {"label":"_M_range_insert"} +# CHECK-DAG: {"label":"_Vector_base"} +# CHECK-DAG: {"label":"assign"} +# CHECK-DAG: {"label":"at"} +# CHECK-DAG: {"label":"back"} +# CHECK-DAG: {"label":"begin"} +# CHECK-DAG: {"label":"capacity"} +# CHECK-DAG: {"label":"clear"} +# CHECK-DAG: {"label":"data"} +# CHECK-DAG: {"label":"empty"} +# CHECK-DAG: {"label":"end"} +# CHECK-DAG: {"label":"erase"} +# CHECK-DAG: {"label":"front"} +# CHECK-DAG: {"label":"get_allocator"} +# CHECK-DAG: {"label":"insert"} +# CHECK-DAG: {"label":"max_size"} +# CHECK-DAG: {"label":"operator="} +# CHECK-DAG: {"label":"operator[]"} +# CHECK-DAG: {"label":"pop_back"} +# CHECK-DAG: {"label":"push_back"} +# CHECK-DAG: {"label":"rbegin"} +# CHECK-DAG: {"label":"rend"} +# CHECK-DAG: {"label":"reserve"} +# CHECK-DAG: {"label":"resize"} +# CHECK-DAG: {"label":"size"} +# CHECK-DAG: {"label":"swap"} +# CHECK-DAG: {"label":"vector"} +# CHECK-DAG: {"label":"~_Vector_base"} +# CHECK-DAG: {"label":"~vector"} +# CHECK: ]} +Content-Length: 44 + +{"jsonrpc":"2.0","id":3,"method":"shutdown"} Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -36,7 +36,8 @@ "documentFormattingProvider": true, "documentRangeFormattingProvider": true, "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, - "codeActionProvider": true + "codeActionProvider": true, + "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]} }}})"); } }; @@ -114,6 +115,16 @@ ASTManager &AST; }; +struct CompletionHandler : Handler { + CompletionHandler(JSONOutput &Output, ASTManager &AST) + : Handler(Output), AST(AST) {} + + void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override; + + priva
[PATCH] D31328: [clangd] Add code completion support
krasimir updated this revision to Diff 92939. krasimir added a comment. - Add '.' and '>' as completion trigger characters https://reviews.llvm.org/D31328 Files: clangd/ASTManager.cpp clangd/ASTManager.h clangd/ClangDMain.cpp clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h test/clangd/completion.test test/clangd/formatting.test Index: test/clangd/formatting.test === --- test/clangd/formatting.test +++ test/clangd/formatting.test @@ -4,13 +4,14 @@ Content-Length: 125 {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} -# CHECK: Content-Length: 332 +# CHECK: Content-Length: 424 # CHECK: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{ # CHECK: "textDocumentSync": 1, # CHECK: "documentFormattingProvider": true, # CHECK: "documentRangeFormattingProvider": true, # CHECK: "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, -# CHECK: "codeActionProvider": true +# CHECK: "codeActionProvider": true, +# CHECK: "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]} # CHECK: }}} # Content-Length: 193 Index: test/clangd/completion.test === --- /dev/null +++ test/clangd/completion.test @@ -0,0 +1,69 @@ +# RUN: clangd -run-synchronously < %s | FileCheck %s +# It is absolutely vital that this file has CRLF line endings. +# +Content-Length: 125 + +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} + +Content-Length: 208 + +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"#include \nint main() {\n std::vector v;\n v.\n}\n"}}} + +Content-Length: 148 + +{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":4}}} +# The order of results returned by ASTUnit CodeComplete seems to be +# nondeterministic, so we check regardless of order. +# +# CHECK: {"jsonrpc":"2.0","id":1,"result":[ +# CHECK-DAG: {"label":"_M_allocate"} +# CHECK-DAG: {"label":"_M_allocate_and_copy"} +# CHECK-DAG: {"label":"_M_assign_aux"} +# CHECK-DAG: {"label":"_M_assign_dispatch"} +# CHECK-DAG: {"label":"_M_check_len"} +# CHECK-DAG: {"label":"_M_create_storage" +# CHECK-DAG: {"label":"_M_deallocate"} +# CHECK-DAG: {"label":"_M_erase_at_end"} +# CHECK-DAG: {"label":"_M_fill_assign"} +# CHECK-DAG: {"label":"_M_fill_initialize"} +# CHECK-DAG: {"label":"_M_fill_insert"} +# CHECK-DAG: {"label":"_M_get_Tp_allocator"} +# CHECK-DAG: {"label":"_M_impl"} +# CHECK-DAG: {"label":"_M_initialize_dispatch"} +# CHECK-DAG: {"label":"_M_insert_aux"} +# CHECK-DAG: {"label":"_M_insert_dispatch"} +# CHECK-DAG: {"label":"_M_range_check"} +# CHECK-DAG: {"label":"_M_range_initialize"} +# CHECK-DAG: {"label":"_M_range_insert"} +# CHECK-DAG: {"label":"_Vector_base"} +# CHECK-DAG: {"label":"assign"} +# CHECK-DAG: {"label":"at"} +# CHECK-DAG: {"label":"back"} +# CHECK-DAG: {"label":"begin"} +# CHECK-DAG: {"label":"capacity"} +# CHECK-DAG: {"label":"clear"} +# CHECK-DAG: {"label":"data"} +# CHECK-DAG: {"label":"empty"} +# CHECK-DAG: {"label":"end"} +# CHECK-DAG: {"label":"erase"} +# CHECK-DAG: {"label":"front"} +# CHECK-DAG: {"label":"get_allocator"} +# CHECK-DAG: {"label":"insert"} +# CHECK-DAG: {"label":"max_size"} +# CHECK-DAG: {"label":"operator="} +# CHECK-DAG: {"label":"operator[]"} +# CHECK-DAG: {"label":"pop_back"} +# CHECK-DAG: {"label":"push_back"} +# CHECK-DAG: {"label":"rbegin"} +# CHECK-DAG: {"label":"rend"} +# CHECK-DAG: {"label":"reserve"} +# CHECK-DAG: {"label":"resize"} +# CHECK-DAG: {"label":"size"} +# CHECK-DAG: {"label":"swap"} +# CHECK-DAG: {"label":"vector"} +# CHECK-DAG: {"label":"~_Vector_base"} +# CHECK-DAG: {"label":"~vector"} +# CHECK: ]} +Content-Length: 44 + +{"jsonrpc":"2.0","id":3,"method":"shutdown"} Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -36,7 +36,8 @@ "documentFormattingProvider": true, "documentRangeFormattingProvider": true, "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, - "codeActionProvider": true + "codeActionProvider": true, + "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]} }}})"); } }; @@ -114,6 +115,16 @@ ASTManager &AST; }; +struct CompletionHandler : Handler { + CompletionHandler(JSONOutput &Output, ASTManager &AST) + : Handler(Output), AST(AST) {} + + void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override; + + private: + ASTManager
[PATCH] D31328: [clangd] Add code completion support
bkramer added inline comments. Comment at: clangd/ASTManager.cpp:264 +assert(CCS->getTypedText()); +Item.label = llvm::yaml::escape(CCS->getTypedText()); +if (CCS->getBriefComment()) CompletionItem::unparse should do the escaping. It's weird to have YAML stuff here. Comment at: clangd/ASTManager.cpp:267 + Item.documentation = llvm::yaml::escape(CCS->getBriefComment()); +Items.push_back(Item); + } std::move Comment at: clangd/ASTManager.cpp:276 + + std::vector getItems() const { return Items; } +}; I think returning by reference and moving out of CodeCompletionInfo in codeComplete() is safe. Comment at: clangd/ASTManager.h:78 llvm::StringMap> ASTs; + std::mutex ASTLock; + Some documentation on the lock would be useful. I'm a bit worried about the priorities here, code completion should always have priority over parsing for diagnostics. But we can address that later. Comment at: clangd/Protocol.cpp:635 +// flush the stream to the string. +Os.str(); +// The list additionalTextEdits is guaranteed nonempty at this point. Os.flush(); Comment at: clangd/Protocol.cpp:640 + } + Os.str(); + // Label is required, so Result is guaranteed to have a trailing comma. Os.flush(); Comment at: clangd/Protocol.h:289 +struct CompletionItem { + CompletionItem() + : kind(CompletionItemKind::Missing), Just use C++11 inline initialization, no need to spell out the constructor. https://reviews.llvm.org/D31328 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D31328: [clangd] Add code completion support
krasimir updated this revision to Diff 92931. krasimir added a comment. - Clean-up leftovers https://reviews.llvm.org/D31328 Files: clangd/ASTManager.cpp clangd/ASTManager.h clangd/ClangDMain.cpp clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h test/clangd/completion.test test/clangd/formatting.test Index: test/clangd/formatting.test === --- test/clangd/formatting.test +++ test/clangd/formatting.test @@ -4,13 +4,14 @@ Content-Length: 125 {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} -# CHECK: Content-Length: 332 +# CHECK: Content-Length: 392 # CHECK: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{ # CHECK: "textDocumentSync": 1, # CHECK: "documentFormattingProvider": true, # CHECK: "documentRangeFormattingProvider": true, # CHECK: "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, -# CHECK: "codeActionProvider": true +# CHECK: "codeActionProvider": true, +# CHECK: "completionProvider": {"resolveProvider": false} # CHECK: }}} # Content-Length: 193 Index: test/clangd/completion.test === --- /dev/null +++ test/clangd/completion.test @@ -0,0 +1,69 @@ +# RUN: clangd -run-synchronously < %s | FileCheck %s +# It is absolutely vital that this file has CRLF line endings. +# +Content-Length: 125 + +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} + +Content-Length: 208 + +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"#include \nint main() {\n std::vector v;\n v.\n}\n"}}} + +Content-Length: 148 + +{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":4}}} +# The order of results returned by ASTUnit CodeComplete seems to be +# nondeterministic, so we check regardless of order. +# +# CHECK: {"jsonrpc":"2.0","id":1,"result":[ +# CHECK-DAG: {"label":"_M_allocate"} +# CHECK-DAG: {"label":"_M_allocate_and_copy"} +# CHECK-DAG: {"label":"_M_assign_aux"} +# CHECK-DAG: {"label":"_M_assign_dispatch"} +# CHECK-DAG: {"label":"_M_check_len"} +# CHECK-DAG: {"label":"_M_create_storage" +# CHECK-DAG: {"label":"_M_deallocate"} +# CHECK-DAG: {"label":"_M_erase_at_end"} +# CHECK-DAG: {"label":"_M_fill_assign"} +# CHECK-DAG: {"label":"_M_fill_initialize"} +# CHECK-DAG: {"label":"_M_fill_insert"} +# CHECK-DAG: {"label":"_M_get_Tp_allocator"} +# CHECK-DAG: {"label":"_M_impl"} +# CHECK-DAG: {"label":"_M_initialize_dispatch"} +# CHECK-DAG: {"label":"_M_insert_aux"} +# CHECK-DAG: {"label":"_M_insert_dispatch"} +# CHECK-DAG: {"label":"_M_range_check"} +# CHECK-DAG: {"label":"_M_range_initialize"} +# CHECK-DAG: {"label":"_M_range_insert"} +# CHECK-DAG: {"label":"_Vector_base"} +# CHECK-DAG: {"label":"assign"} +# CHECK-DAG: {"label":"at"} +# CHECK-DAG: {"label":"back"} +# CHECK-DAG: {"label":"begin"} +# CHECK-DAG: {"label":"capacity"} +# CHECK-DAG: {"label":"clear"} +# CHECK-DAG: {"label":"data"} +# CHECK-DAG: {"label":"empty"} +# CHECK-DAG: {"label":"end"} +# CHECK-DAG: {"label":"erase"} +# CHECK-DAG: {"label":"front"} +# CHECK-DAG: {"label":"get_allocator"} +# CHECK-DAG: {"label":"insert"} +# CHECK-DAG: {"label":"max_size"} +# CHECK-DAG: {"label":"operator="} +# CHECK-DAG: {"label":"operator[]"} +# CHECK-DAG: {"label":"pop_back"} +# CHECK-DAG: {"label":"push_back"} +# CHECK-DAG: {"label":"rbegin"} +# CHECK-DAG: {"label":"rend"} +# CHECK-DAG: {"label":"reserve"} +# CHECK-DAG: {"label":"resize"} +# CHECK-DAG: {"label":"size"} +# CHECK-DAG: {"label":"swap"} +# CHECK-DAG: {"label":"vector"} +# CHECK-DAG: {"label":"~_Vector_base"} +# CHECK-DAG: {"label":"~vector"} +# CHECK: ]} +Content-Length: 44 + +{"jsonrpc":"2.0","id":3,"method":"shutdown"} Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -36,7 +36,8 @@ "documentFormattingProvider": true, "documentRangeFormattingProvider": true, "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, - "codeActionProvider": true + "codeActionProvider": true, + "completionProvider": {"resolveProvider": false} }}})"); } }; @@ -114,6 +115,16 @@ ASTManager &AST; }; +struct CompletionHandler : Handler { + CompletionHandler(JSONOutput &Output, ASTManager &AST) + : Handler(Output), AST(AST) {} + + void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override; + + private: + ASTManager &AST; +}; + } // namespace clangd } // namespace clang Index: clangd/ProtocolHandlers.cpp
[PATCH] D31328: [clangd] Add code completion support
krasimir created this revision. Adds code completion support to clangd. https://reviews.llvm.org/D31328 Files: clangd/ASTManager.cpp clangd/ASTManager.h clangd/ClangDMain.cpp clangd/Protocol.cpp clangd/Protocol.h clangd/ProtocolHandlers.cpp clangd/ProtocolHandlers.h test/clangd/completion.test test/clangd/formatting.test Index: test/clangd/formatting.test === --- test/clangd/formatting.test +++ test/clangd/formatting.test @@ -4,13 +4,14 @@ Content-Length: 125 {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} -# CHECK: Content-Length: 332 +# CHECK: Content-Length: 392 # CHECK: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{ # CHECK: "textDocumentSync": 1, # CHECK: "documentFormattingProvider": true, # CHECK: "documentRangeFormattingProvider": true, # CHECK: "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, -# CHECK: "codeActionProvider": true +# CHECK: "codeActionProvider": true, +# CHECK: "completionProvider": {"resolveProvider": false} # CHECK: }}} # Content-Length: 193 Index: test/clangd/completion.test === --- /dev/null +++ test/clangd/completion.test @@ -0,0 +1,69 @@ +# RUN: clangd -run-synchronously < %s | FileCheck %s +# It is absolutely vital that this file has CRLF line endings. +# +Content-Length: 125 + +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} + +Content-Length: 208 + +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"#include \nint main() {\n std::vector v;\n v.\n}\n"}}} + +Content-Length: 148 + +{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":4}}} +# The order of results returned by ASTUnit CodeComplete seems to be +# nondeterministic, so we check regardless of order. +# +# CHECK: {"jsonrpc":"2.0","id":1,"result":[ +# CHECK-DAG: {"label":"_M_allocate"} +# CHECK-DAG: {"label":"_M_allocate_and_copy"} +# CHECK-DAG: {"label":"_M_assign_aux"} +# CHECK-DAG: {"label":"_M_assign_dispatch"} +# CHECK-DAG: {"label":"_M_check_len"} +# CHECK-DAG: {"label":"_M_create_storage" +# CHECK-DAG: {"label":"_M_deallocate"} +# CHECK-DAG: {"label":"_M_erase_at_end"} +# CHECK-DAG: {"label":"_M_fill_assign"} +# CHECK-DAG: {"label":"_M_fill_initialize"} +# CHECK-DAG: {"label":"_M_fill_insert"} +# CHECK-DAG: {"label":"_M_get_Tp_allocator"} +# CHECK-DAG: {"label":"_M_impl"} +# CHECK-DAG: {"label":"_M_initialize_dispatch"} +# CHECK-DAG: {"label":"_M_insert_aux"} +# CHECK-DAG: {"label":"_M_insert_dispatch"} +# CHECK-DAG: {"label":"_M_range_check"} +# CHECK-DAG: {"label":"_M_range_initialize"} +# CHECK-DAG: {"label":"_M_range_insert"} +# CHECK-DAG: {"label":"_Vector_base"} +# CHECK-DAG: {"label":"assign"} +# CHECK-DAG: {"label":"at"} +# CHECK-DAG: {"label":"back"} +# CHECK-DAG: {"label":"begin"} +# CHECK-DAG: {"label":"capacity"} +# CHECK-DAG: {"label":"clear"} +# CHECK-DAG: {"label":"data"} +# CHECK-DAG: {"label":"empty"} +# CHECK-DAG: {"label":"end"} +# CHECK-DAG: {"label":"erase"} +# CHECK-DAG: {"label":"front"} +# CHECK-DAG: {"label":"get_allocator"} +# CHECK-DAG: {"label":"insert"} +# CHECK-DAG: {"label":"max_size"} +# CHECK-DAG: {"label":"operator="} +# CHECK-DAG: {"label":"operator[]"} +# CHECK-DAG: {"label":"pop_back"} +# CHECK-DAG: {"label":"push_back"} +# CHECK-DAG: {"label":"rbegin"} +# CHECK-DAG: {"label":"rend"} +# CHECK-DAG: {"label":"reserve"} +# CHECK-DAG: {"label":"resize"} +# CHECK-DAG: {"label":"size"} +# CHECK-DAG: {"label":"swap"} +# CHECK-DAG: {"label":"vector"} +# CHECK-DAG: {"label":"~_Vector_base"} +# CHECK-DAG: {"label":"~vector"} +# CHECK: ]} +Content-Length: 44 + +{"jsonrpc":"2.0","id":3,"method":"shutdown"} Index: clangd/ProtocolHandlers.h === --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -36,7 +36,8 @@ "documentFormattingProvider": true, "documentRangeFormattingProvider": true, "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, - "codeActionProvider": true + "codeActionProvider": true, + "completionProvider": {"resolveProvider": false} }}})"); } }; @@ -114,6 +115,16 @@ ASTManager &AST; }; +struct CompletionHandler : Handler { + CompletionHandler(JSONOutput &Output, ASTManager &AST) + : Handler(Output), AST(AST) {} + + void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override; + + private: + ASTManager &AST; +}; + } // namespace clangd } // namespace clang Index: clangd/ProtocolHandlers.cpp =