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 @@ -1413,7 +1413,8 @@ void ClangdLSPServer::onAST(const ASTParams &Params, Callback> CB) { - Server->getAST(Params.textDocument.uri.file(), Params.range, std::move(CB)); + Server->getAST(Params.textDocument.uri.file(), Params.range ? *Params.range : Range{}, + std::move(CB)); } ClangdLSPServer::ClangdLSPServer(Transport &Transp, const ThreadsafeFS &TFS, diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -903,7 +903,8 @@ bool Success = SelectionTree::createEach( Inputs->AST.getASTContext(), Inputs->AST.getTokens(), Start, End, [&](SelectionTree T) { - if (const SelectionTree::Node *N = T.commonAncestor()) { + const SelectionTree::Node *N = R.start == R.end ? &T.root() : T.commonAncestor(); + if (N) { CB(dumpAST(N->ASTNode, Inputs->AST.getTokens(), Inputs->AST.getASTContext())); return true; diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -1725,7 +1725,8 @@ /// The position of the node to be dumped. /// The highest-level node that entirely contains the range will be returned. - Range range; + /// If no range is given, the top-level translation unit node will be returned. + llvm::Optional range; }; bool fromJSON(const llvm::json::Value &, ASTParams &, llvm::json::Path); diff --git a/clang-tools-extra/clangd/test/ast-no-range.test b/clang-tools-extra/clangd/test/ast-no-range.test new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/test/ast-no-range.test @@ -0,0 +1,53 @@ +# RUN: clangd -lit-test < %s | FileCheck %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:///simple.cpp","languageId":"cpp","version":1,"text":"int x;"}}} +--- +{"jsonrpc":"2.0","id":1,"method":"textDocument/ast","params":{"textDocument":{"uri":"test:///simple.cpp"}}} +# CHECK: "id": 1, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": { +# CHECK-NEXT: "arcana": "{{TranslationUnitDecl.*}}" +# CHECK-NEXT: "children": [ +# CHECK-NEXT: { +# CHECK: "arcana": "VarDecl {{.*}} x 'int'", +# CHECK-NEXT: "children": [ +# CHECK-NEXT: { +# CHECK-NEXT: "arcana": "QualType {{.*}} 'int' ", +# CHECK-NEXT: "detail": "int", +# CHECK-NEXT: "kind": "Builtin", +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 3, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 0, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: } +# CHECK-NEXT: }, +# CHECK-NEXT: "role": "type" +# CHECK-NEXT: } +# CHECK-NEXT: ], +# CHECK-NEXT: "detail": "x", +# CHECK-NEXT: "kind": "Var", +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 5, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 0, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: } +# CHECK-NEXT: }, +# CHECK-NEXT: "role": "declaration" +# CHECK-NEXT: } +# CHECK-NEXT: ], +# CHECK-NEXT: "kind": "TranslationUnit", +# CHECK-NEXT: "role": "declaration" +# CHECK-NEXT: } +--- +{"jsonrpc":"2.0","id":2,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"}