diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h --- a/clang-tools-extra/clangd/ClangdLSPServer.h +++ b/clang-tools-extra/clangd/ClangdLSPServer.h @@ -52,6 +52,10 @@ /// If set, periodically called to release memory. /// Consider malloc_trim(3) std::function MemoryCleanup = nullptr; + /// If set, include files in #include directives are exposed to the clients + /// as documentLinks. If disabled include files can still be opened with the + /// go to definition feature. + bool IncludesAsLinks = true; /// Per-feature options. Generally ClangdServer lets these vary /// per-request, but LSP allows limited/no customizations. 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 @@ -610,10 +610,6 @@ {"definitionProvider", true}, {"implementationProvider", true}, {"documentHighlightProvider", true}, - {"documentLinkProvider", - llvm::json::Object{ - {"resolveProvider", false}, - }}, {"hoverProvider", true}, {"renameProvider", std::move(RenameProvider)}, {"selectionRangeProvider", true}, @@ -640,6 +636,10 @@ llvm::json::Object{{"scopes", buildHighlightScopeLookupTable()}}}); if (Opts.FoldingRanges) Result.getObject("capabilities")->insert({"foldingRangeProvider", true}); + if (Opts.IncludesAsLinks) + Result.getObject("capabilities") + ->insert({"documentLinkProvider", + llvm::json::Object{{"resolveProvider", false}}}); Reply(std::move(Result)); } @@ -1505,12 +1505,13 @@ MsgHandler->bind("callHierarchy/incomingCalls", &ClangdLSPServer::onCallHierarchyIncomingCalls); MsgHandler->bind("callHierarchy/outgoingCalls", &ClangdLSPServer::onCallHierarchyOutgoingCalls); MsgHandler->bind("textDocument/selectionRange", &ClangdLSPServer::onSelectionRange); - MsgHandler->bind("textDocument/documentLink", &ClangdLSPServer::onDocumentLink); MsgHandler->bind("textDocument/semanticTokens/full", &ClangdLSPServer::onSemanticTokens); MsgHandler->bind("textDocument/semanticTokens/full/delta", &ClangdLSPServer::onSemanticTokensDelta); MsgHandler->bind("$/memoryUsage", &ClangdLSPServer::onMemoryUsage); if (Opts.FoldingRanges) MsgHandler->bind("textDocument/foldingRange", &ClangdLSPServer::onFoldingRange); + if (Opts.IncludesAsLinks) + MsgHandler->bind("textDocument/documentLink", &ClangdLSPServer::onDocumentLink); // clang-format on } diff --git a/clang-tools-extra/clangd/test/xrefs.test b/clang-tools-extra/clangd/test/xrefs.test --- a/clang-tools-extra/clangd/test/xrefs.test +++ b/clang-tools-extra/clangd/test/xrefs.test @@ -1,9 +1,9 @@ # RUN: clangd -lit-test < %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":"extern int x;\nint x = 0;\nint y = x;"}}} +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"#include \nextern int x;\nint x = 0;\nint y = x;"}}} --- -{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":8}}} +{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":3,"character":8}}} # CHECK: "id": 1, # CHECK-NEXT: "jsonrpc": "2.0", # CHECK-NEXT: "result": [ @@ -11,11 +11,11 @@ # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 5, -# CHECK-NEXT: "line": 1 +# CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 4, -# CHECK-NEXT: "line": 1 +# CHECK-NEXT: "line": 2 # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: "uri": "file://{{.*}}/{{([A-Z]:/)?}}main.cpp" @@ -23,7 +23,7 @@ # CHECK-NEXT: ] --- # Toggle: we're on the definition, so jump to the declaration. -{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":1,"character":4}}} +{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":4}}} # CHECK: "id": 1, # CHECK-NEXT: "jsonrpc": "2.0", # CHECK-NEXT: "result": [ @@ -31,18 +31,18 @@ # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 12, -# CHECK-NEXT: "line": 0 +# CHECK-NEXT: "line": 1 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 11, -# CHECK-NEXT: "line": 0 +# CHECK-NEXT: "line": 1 # CHECK-NEXT: } # CHECK-NEXT: }, # CHECK-NEXT: "uri": "file://{{.*}}/{{([A-Z]:/)?}}main.cpp" # CHECK-NEXT: } # CHECK-NEXT: ] --- -{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":8}}} +{"jsonrpc":"2.0","id":1,"method":"textDocument/documentHighlight","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":3,"character":8}}} # CHECK: "id": 1 # CHECK-NEXT: "jsonrpc": "2.0", # CHECK-NEXT: "result": [ @@ -51,11 +51,11 @@ # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 12, -# CHECK-NEXT: "line": 0 +# CHECK-NEXT: "line": 1 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 11, -# CHECK-NEXT: "line": 0 +# CHECK-NEXT: "line": 1 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: }, @@ -64,11 +64,11 @@ # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 5, -# CHECK-NEXT: "line": 1 +# CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 4, -# CHECK-NEXT: "line": 1 +# CHECK-NEXT: "line": 2 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: }, @@ -77,16 +77,36 @@ # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { # CHECK-NEXT: "character": 9, -# CHECK-NEXT: "line": 2 +# CHECK-NEXT: "line": 3 # CHECK-NEXT: }, # CHECK-NEXT: "start": { # CHECK-NEXT: "character": 8, -# CHECK-NEXT: "line": 2 +# CHECK-NEXT: "line": 3 # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: } # CHECK-NEXT: ] --- +# Go to definition on include (necessary when documentLinks are disabled) +{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":15}}} +# CHECK: "id": 1, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": [ +# CHECK-NEXT: { +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 0, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 0, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: } +# CHECK-NEXT: }, +# CHECK-NEXT: "uri": "file://{{.*}}/{{([A-Z]:/)?}}stdint.h" +# CHECK-NEXT: } +# CHECK-NEXT: ] +--- {"jsonrpc":"2.0","id":10000,"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 @@ -339,6 +339,15 @@ Hidden, }; +opt IncludesAsLinks{ + "includes-as-links", + cat(Features), + desc("Provide a document link to the files included with #include " + "directive. If set to false, include files can still be opened with " + "go to definition feature"), + init(true) +}; + opt WorkerThreadsCount{ "j", cat(Misc), @@ -825,6 +834,7 @@ Opts.PreserveRecoveryASTType = RecoveryASTType; Opts.FoldingRanges = FoldingRanges; Opts.MemoryCleanup = getMemoryCleanupFunction(); + Opts.IncludesAsLinks = IncludesAsLinks; Opts.CodeComplete.IncludeIneligibleResults = IncludeIneligibleResults; Opts.CodeComplete.Limit = LimitResults;