MForster created this revision. Herald added subscribers: cfe-commits, usaxena95, kadircet, arphaman, jkorous. Herald added a project: clang.
Add "textDocument/documentLink" protocol support Implement "textDocument/documentLink" Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D70872 Files: clang-tools-extra/clangd/ClangdLSPServer.cpp clang-tools-extra/clangd/ClangdLSPServer.h clang-tools-extra/clangd/ClangdServer.cpp clang-tools-extra/clangd/ClangdServer.h clang-tools-extra/clangd/Protocol.cpp clang-tools-extra/clangd/Protocol.h clang-tools-extra/clangd/XRefs.cpp clang-tools-extra/clangd/XRefs.h clang-tools-extra/clangd/test/document-link.test clang-tools-extra/clangd/test/initialize-params.test
Index: clang-tools-extra/clangd/test/initialize-params.test =================================================================== --- clang-tools-extra/clangd/test/initialize-params.test +++ clang-tools-extra/clangd/test/initialize-params.test @@ -18,6 +18,9 @@ # CHECK-NEXT: "definitionProvider": true, # CHECK-NEXT: "documentFormattingProvider": true, # CHECK-NEXT: "documentHighlightProvider": true, +# CHECK-NEXT: "documentLinkProvider": { +# CHECK-NEXT: "resolveProvider": false +# CHECK-NEXT: } # CHECK-NEXT: "documentOnTypeFormattingProvider": { # CHECK-NEXT: "firstTriggerCharacter": "\n", # CHECK-NEXT: "moreTriggerCharacter": [] Index: clang-tools-extra/clangd/test/document-link.test =================================================================== --- /dev/null +++ clang-tools-extra/clangd/test/document-link.test @@ -0,0 +1,42 @@ +# 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":"#include <iostream>\n#include <string>"}}} +--- +{"jsonrpc":"2.0","id":2,"method":"textDocument/documentLink","params":{"textDocument":{"uri":"test:///main.cpp"}}} +# CHECK: "id": 2, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": [ +# CHECK-NEXT: { +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 19, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 9, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: } +# CHECK-NEXT: }, +# CHECK-NEXT: "target": "file://{{.*}}/iostream" +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 17, +# CHECK-NEXT: "line": 1 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 9, +# CHECK-NEXT: "line": 1 +# CHECK-NEXT: } +# CHECK-NEXT: }, +# CHECK-NEXT: "target": "file://{{.*}}/string" +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT:} + +--- +{"jsonrpc":"2.0","id":3,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} Index: clang-tools-extra/clangd/XRefs.h =================================================================== --- clang-tools-extra/clangd/XRefs.h +++ clang-tools-extra/clangd/XRefs.h @@ -49,6 +49,9 @@ std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index = nullptr); +/// Get all document links +std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST); + /// Returns highlights for all usages of a symbol at \p Pos. std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST, Position Pos); Index: clang-tools-extra/clangd/XRefs.cpp =================================================================== --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -166,6 +166,26 @@ } // namespace +std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) { + const auto &SM = AST.getSourceManager(); + auto MainFilePath = + getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM); + if (!MainFilePath) { + elog("Failed to get a path for the main file, so no links"); + return {}; + } + + std::vector<DocumentLink> Result; + for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) { + if (!Inc.Resolved.empty()) { + Result.emplace_back(DocumentLink( + {Inc.R, URIForFile::canonicalize(Inc.Resolved, *MainFilePath)})); + } + } + + return Result; +} + std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos, const SymbolIndex *Index) { const auto &SM = AST.getSourceManager(); Index: clang-tools-extra/clangd/Protocol.h =================================================================== --- clang-tools-extra/clangd/Protocol.h +++ clang-tools-extra/clangd/Protocol.h @@ -1250,6 +1250,33 @@ }; llvm::json::Value toJSON(const SelectionRange &); +/// Parameters for the document link request. +struct DocumentLinkParams { + /// The document to provide document links for. + TextDocumentIdentifier textDocument; +}; +bool fromJSON(const llvm::json::Value &, DocumentLinkParams &); + +/// A range in a text document that links to an internal or external resource, +/// like another text document or a web site. +/// +/// TODO(forster): For now only file URIs are supported. +struct DocumentLink { + /// The range this link applies to. + Range range; + + /// The uri this link points to. If missing a resolve request is sent later. + URIForFile target; + + // TODO(forster): The following optional fields defined by the language + // server protocol are unsupported: + // + // data?: any - A data entry field that is preserved on a document link + // between a DocumentLinkRequest and a + // DocumentLinkResolveRequest. +}; +llvm::json::Value toJSON(const DocumentLink &DocumentLink); + } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/Protocol.cpp =================================================================== --- clang-tools-extra/clangd/Protocol.cpp +++ clang-tools-extra/clangd/Protocol.cpp @@ -1087,5 +1087,18 @@ } return llvm::json::Object{{"range", Out.range}}; } + +bool fromJSON(const llvm::json::Value &Params, DocumentLinkParams &R) { + llvm::json::ObjectMapper O(Params); + return O && O.map("textDocument", R.textDocument); +} + +llvm::json::Value toJSON(const DocumentLink &DocumentLink) { + return llvm::json::Object{ + {"range", DocumentLink.range}, + {"target", DocumentLink.target}, + }; +} + } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/ClangdServer.h =================================================================== --- clang-tools-extra/clangd/ClangdServer.h +++ clang-tools-extra/clangd/ClangdServer.h @@ -287,6 +287,9 @@ void semanticRanges(PathRef File, Position Pos, Callback<std::vector<Range>> CB); + /// Get all document links in a file. + void documentLinks(PathRef File, Callback<std::vector<DocumentLink>> 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 Index: clang-tools-extra/clangd/ClangdServer.cpp =================================================================== --- clang-tools-extra/clangd/ClangdServer.cpp +++ clang-tools-extra/clangd/ClangdServer.cpp @@ -611,6 +611,17 @@ WorkScheduler.runWithAST("SemanticRanges", File, std::move(Action)); } +void ClangdServer::documentLinks(PathRef File, + Callback<std::vector<DocumentLink>> CB) { + auto Action = + [CB = std::move(CB)](llvm::Expected<InputsAndAST> InpAST) mutable { + if (!InpAST) + return CB(InpAST.takeError()); + CB(clangd::getDocumentLinks(InpAST->AST)); + }; + WorkScheduler.runWithAST("DocumentLinks", File, std::move(Action)); +} + std::vector<std::pair<Path, std::size_t>> ClangdServer::getUsedBytesPerFile() const { return WorkScheduler.getUsedBytesPerFile(); Index: clang-tools-extra/clangd/ClangdLSPServer.h =================================================================== --- clang-tools-extra/clangd/ClangdLSPServer.h +++ clang-tools-extra/clangd/ClangdLSPServer.h @@ -111,6 +111,8 @@ Callback<std::vector<SymbolDetails>>); void onSelectionRange(const SelectionRangeParams &, Callback<std::vector<SelectionRange>>); + void onDocumentLink(const DocumentLinkParams &, + Callback<std::vector<DocumentLink>>); std::vector<Fix> getFixes(StringRef File, const clangd::Diagnostic &D); Index: clang-tools-extra/clangd/ClangdLSPServer.cpp =================================================================== --- clang-tools-extra/clangd/ClangdLSPServer.cpp +++ clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -563,6 +563,10 @@ {"declarationProvider", true}, {"definitionProvider", true}, {"documentHighlightProvider", true}, + {"documentLinkProvider", + llvm::json::Object{ + {"resolveProvider", false}, + }}, {"hoverProvider", true}, {"renameProvider", std::move(RenameProvider)}, {"selectionRangeProvider", true}, @@ -1197,6 +1201,20 @@ }); } +void ClangdLSPServer::onDocumentLink( + const DocumentLinkParams &Params, + Callback<std::vector<DocumentLink>> Reply) { + Server->documentLinks( + Params.textDocument.uri.file(), + [Reply = std::move(Reply)]( + llvm::Expected<std::vector<DocumentLink>> Links) mutable { + if (!Links) { + return Reply(Links.takeError()); + } + return Reply(std::move(Links)); + }); +} + ClangdLSPServer::ClangdLSPServer( class Transport &Transp, const FileSystemProvider &FSProvider, const clangd::CodeCompleteOptions &CCOpts, @@ -1240,10 +1258,12 @@ MsgHandler->bind("textDocument/typeHierarchy", &ClangdLSPServer::onTypeHierarchy); MsgHandler->bind("typeHierarchy/resolve", &ClangdLSPServer::onResolveTypeHierarchy); MsgHandler->bind("textDocument/selectionRange", &ClangdLSPServer::onSelectionRange); + MsgHandler->bind("textDocument/documentLink", &ClangdLSPServer::onDocumentLink); // clang-format on } -ClangdLSPServer::~ClangdLSPServer() { IsBeingDestroyed = true; +ClangdLSPServer::~ClangdLSPServer() { + IsBeingDestroyed = true; // Explicitly destroy ClangdServer first, blocking on threads it owns. // This ensures they don't access any other members. Server.reset();
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits