Index: clangd/ClangdLSPServer.h =================================================================== --- clangd/ClangdLSPServer.h +++ clangd/ClangdLSPServer.h @@ -67,6 +67,7 @@ void onCompletion(TextDocumentPositionParams &Params) override; void onSignatureHelp(TextDocumentPositionParams &Params) override; void onGoToDefinition(TextDocumentPositionParams &Params) override; + void onReference(ReferenceParams &Params) override; void onSwitchSourceHeader(TextDocumentIdentifier &Params) override; void onDocumentHighlight(TextDocumentPositionParams &Params) override; void onFileEvent(DidChangeWatchedFilesParams &Params) override; Index: clangd/ClangdLSPServer.cpp =================================================================== --- clangd/ClangdLSPServer.cpp +++ clangd/ClangdLSPServer.cpp @@ -129,6 +129,7 @@ {"renameProvider", true}, {"documentSymbolProvider", true}, {"workspaceSymbolProvider", true}, + {"referencesProvider", true}, {"executeCommandProvider", json::Object{ {"commands", {ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND}}, @@ -449,6 +450,17 @@ applyConfiguration(Params.settings); } +void ClangdLSPServer::onReference(ReferenceParams &Params) { + Server.findReferences(Params.textDocument.uri.file(), Params.position, + [](llvm::Expected> Locations) { + if (!Locations) + return replyError( + ErrorCode::InternalError, + llvm::toString(Locations.takeError())); + reply(llvm::json::Array(*Locations)); + }); +} + ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, const clangd::CodeCompleteOptions &CCOpts, llvm::Optional CompileCommandsDir, Index: clangd/ClangdServer.h =================================================================== --- clangd/ClangdServer.h +++ clangd/ClangdServer.h @@ -157,6 +157,10 @@ void documentSymbols(StringRef File, Callback> CB); + /// Retrieve locations for symbol references. + void findReferences(PathRef File, Position Pos, + Callback> CB); + /// Run formatting for \p Rng inside \p File with content \p Code. llvm::Expected formatRange(StringRef Code, PathRef File, Range Rng); Index: clangd/ClangdServer.cpp =================================================================== --- clangd/ClangdServer.cpp +++ clangd/ClangdServer.cpp @@ -560,6 +560,18 @@ Bind(Action, std::move(CB))); } +void ClangdServer::findReferences(PathRef File, Position Pos, + Callback> CB) { + auto Action = [Pos, this](Callback> CB, + llvm::Expected InpAST) { + if (!InpAST) + return CB(InpAST.takeError()); + CB(clangd::findReferences(InpAST->AST, Pos, Index)); + }; + + WorkScheduler.runWithAST("References", File, Bind(Action, std::move(CB))); +} + std::vector> ClangdServer::getUsedBytesPerFile() const { return WorkScheduler.getUsedBytesPerFile(); Index: clangd/Protocol.h =================================================================== --- clangd/Protocol.h +++ clangd/Protocol.h @@ -878,6 +878,11 @@ llvm::json::Value toJSON(const DocumentHighlight &DH); llvm::raw_ostream &operator<<(llvm::raw_ostream &, const DocumentHighlight &); +struct ReferenceParams : public TextDocumentPositionParams { + // For now, no options like context.includeDeclaration are supported. +}; +bool fromJSON(const llvm::json::Value &, ReferenceParams &); + struct CancelParams { /// The request id to cancel. /// This can be either a number or string, if it is a number simply print it Index: clangd/Protocol.cpp =================================================================== --- clangd/Protocol.cpp +++ clangd/Protocol.cpp @@ -616,6 +616,11 @@ O.map("compilationDatabaseChanges", CCPC.compilationDatabaseChanges); } +bool fromJSON(const json::Value &Params, ReferenceParams &R) { + TextDocumentPositionParams &Base = R; + return fromJSON(Params, Base); +} + json::Value toJSON(const CancelParams &CP) { return json::Object{{"id", CP.ID}}; } Index: clangd/ProtocolHandlers.h =================================================================== --- clangd/ProtocolHandlers.h +++ clangd/ProtocolHandlers.h @@ -47,6 +47,7 @@ virtual void onCompletion(TextDocumentPositionParams &Params) = 0; virtual void onSignatureHelp(TextDocumentPositionParams &Params) = 0; virtual void onGoToDefinition(TextDocumentPositionParams &Params) = 0; + virtual void onReference(ReferenceParams &Params) = 0; virtual void onSwitchSourceHeader(TextDocumentIdentifier &Params) = 0; virtual void onFileEvent(DidChangeWatchedFilesParams &Params) = 0; virtual void onCommand(ExecuteCommandParams &Params) = 0; Index: clangd/ProtocolHandlers.cpp =================================================================== --- clangd/ProtocolHandlers.cpp +++ clangd/ProtocolHandlers.cpp @@ -63,6 +63,7 @@ Register("textDocument/completion", &ProtocolCallbacks::onCompletion); Register("textDocument/signatureHelp", &ProtocolCallbacks::onSignatureHelp); Register("textDocument/definition", &ProtocolCallbacks::onGoToDefinition); + Register("textDocument/references", &ProtocolCallbacks::onReference); Register("textDocument/switchSourceHeader", &ProtocolCallbacks::onSwitchSourceHeader); Register("textDocument/rename", &ProtocolCallbacks::onRename); Index: clangd/XRefs.cpp =================================================================== --- clangd/XRefs.cpp +++ clangd/XRefs.cpp @@ -17,6 +17,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/USRGeneration.h" #include "llvm/Support/Path.h" + namespace clang { namespace clangd { using namespace llvm; Index: test/clangd/initialize-params-invalid.test =================================================================== --- test/clangd/initialize-params-invalid.test +++ test/clangd/initialize-params-invalid.test @@ -5,41 +5,7 @@ # CHECK-NEXT: "jsonrpc": "2.0", # CHECK-NEXT: "result": { # CHECK-NEXT: "capabilities": { -# CHECK-NEXT: "codeActionProvider": true, -# CHECK-NEXT: "completionProvider": { -# CHECK-NEXT: "resolveProvider": false, -# CHECK-NEXT: "triggerCharacters": [ -# CHECK-NEXT: ".", -# CHECK-NEXT: ">", -# CHECK-NEXT: ":" -# CHECK-NEXT: ] -# CHECK-NEXT: }, -# CHECK-NEXT: "definitionProvider": true, -# CHECK-NEXT: "documentFormattingProvider": true, -# CHECK-NEXT: "documentHighlightProvider": true, -# CHECK-NEXT: "documentOnTypeFormattingProvider": { -# CHECK-NEXT: "firstTriggerCharacter": "}", -# CHECK-NEXT: "moreTriggerCharacter": [] -# CHECK-NEXT: }, -# CHECK-NEXT: "documentRangeFormattingProvider": true, -# CHECK-NEXT: "documentSymbolProvider": true, -# CHECK-NEXT: "executeCommandProvider": { -# CHECK-NEXT: "commands": [ -# CHECK-NEXT: "clangd.applyFix" -# CHECK-NEXT: ] -# CHECK-NEXT: }, -# CHECK-NEXT: "hoverProvider": true, -# CHECK-NEXT: "renameProvider": true, -# CHECK-NEXT: "signatureHelpProvider": { -# CHECK-NEXT: "triggerCharacters": [ -# CHECK-NEXT: "(", -# CHECK-NEXT: "," -# CHECK-NEXT: ] -# CHECK-NEXT: }, -# CHECK-NEXT: "textDocumentSync": 2, -# CHECK-NEXT: "workspaceSymbolProvider": true -# CHECK-NEXT: } -# CHECK-NEXT: } +# ... --- {"jsonrpc":"2.0","id":3,"method":"shutdown"} --- Index: test/clangd/initialize-params.test =================================================================== --- test/clangd/initialize-params.test +++ test/clangd/initialize-params.test @@ -29,6 +29,7 @@ # CHECK-NEXT: ] # CHECK-NEXT: }, # CHECK-NEXT: "hoverProvider": true, +# CHECK-NEXT: "referencesProvider": true, # CHECK-NEXT: "renameProvider": true, # CHECK-NEXT: "signatureHelpProvider": { # CHECK-NEXT: "triggerCharacters": [ Index: test/clangd/references.test =================================================================== --- test/clangd/references.test +++ test/clangd/references.test @@ -0,0 +1,40 @@ +# 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":"int x; int y = x;"}}} +--- +{"jsonrpc":"2.0","id":1,"method":"textDocument/references","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":4}}} +# CHECK: "id": 1 +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": [ +# CHECK-NEXT: { +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 5, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 4, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: } +# CHECK-NEXT: }, +# CHECK-NEXT: "uri": "test:///main.cpp" +# CHECK-NEXT: }, +# CHECK-NEXT: { +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 16, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 15, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: } +# CHECK-NEXT: }, +# CHECK-NEXT: "uri": "test:///main.cpp" +# CHECK-NEXT: }, +# CHECK-NEXT: ] +--- +{"jsonrpc":"2.0","id":3,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"}