ckandeler updated this revision to Diff 339995. ckandeler marked 2 inline comments as done. ckandeler added a comment.
"top-level" -> "root" Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D101057/new/ https://reviews.llvm.org/D101057 Files: clang-tools-extra/clangd/ClangdServer.cpp clang-tools-extra/clangd/ClangdServer.h clang-tools-extra/clangd/DumpAST.cpp clang-tools-extra/clangd/Protocol.h clang-tools-extra/clangd/test/ast-no-range.test clang-tools-extra/clangd/unittests/DumpASTTests.cpp
Index: clang-tools-extra/clangd/unittests/DumpASTTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/DumpASTTests.cpp +++ clang-tools-extra/clangd/unittests/DumpASTTests.cpp @@ -16,8 +16,12 @@ namespace clang { namespace clangd { namespace { +using testing::Contains; +using testing::Not; using testing::SizeIs; +MATCHER_P(WithDetail, str, "") { return arg.detail == str; } + TEST(DumpASTTests, BasicInfo) { std::pair</*Code=*/std::string, /*Expected=*/std::string> Cases[] = { {R"cpp( @@ -157,6 +161,20 @@ EXPECT_EQ(Node.children.front().range, Case.range("type")); } +TEST(DumpASTTests, NoRange) { + auto TU = TestTU::withHeaderCode("void funcFromHeader();"); + TU.Code = "int varFromSource;"; + ParsedAST AST = TU.build(); + auto Node = dumpAST( + DynTypedNode::create(*AST.getASTContext().getTranslationUnitDecl()), + AST.getTokens(), AST.getASTContext()); + ASSERT_THAT(Node.children, Contains(WithDetail("varFromSource"))); + ASSERT_THAT(Node.children, Not(Contains(WithDetail("funcFromHeader")))); + EXPECT_THAT(Node.arcana, testing::StartsWith("TranslationUnitDecl ")); + ASSERT_FALSE(Node.range.hasValue()) + << "Expected no range for translation unit"; +} + TEST(DumpASTTests, Arcana) { ParsedAST AST = TestTU::withCode("int x;").build(); auto Node = dumpAST(DynTypedNode::create(findDecl(AST, "x")), AST.getTokens(), Index: clang-tools-extra/clangd/test/ast-no-range.test =================================================================== --- /dev/null +++ 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"} Index: clang-tools-extra/clangd/Protocol.h =================================================================== --- clang-tools-extra/clangd/Protocol.h +++ 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 root translation unit node will be returned. + llvm::Optional<Range> range; }; bool fromJSON(const llvm::json::Value &, ASTParams &, llvm::json::Path); Index: clang-tools-extra/clangd/DumpAST.cpp =================================================================== --- clang-tools-extra/clangd/DumpAST.cpp +++ clang-tools-extra/clangd/DumpAST.cpp @@ -335,6 +335,11 @@ // Override traversal to record the nodes we care about. // Generally, these are nodes with position information (TypeLoc, not Type). + + bool TraverseTUDecl(TranslationUnitDecl *TU) { + return traverseNode("declaration", TU, [&] { + Base::TraverseAST(const_cast<ASTContext &>(Ctx)); }); + } bool TraverseDecl(Decl *D) { return !D || isInjectedClassName(D) || traverseNode("declaration", D, [&] { Base::TraverseDecl(D); }); @@ -397,11 +402,15 @@ } // namespace +// Note: It's safe for N to be a TranslationUnitDecl, as this function +// does not deserialize the preamble. ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens, const ASTContext &Ctx) { DumpVisitor V(Tokens, Ctx); // DynTypedNode only works with const, RecursiveASTVisitor only non-const :-( - if (const auto *D = N.get<Decl>()) + if (const auto *TU = N.get<TranslationUnitDecl>()) + V.TraverseTUDecl(const_cast<TranslationUnitDecl *>(TU)); + else if (const auto *D = N.get<Decl>()) V.TraverseDecl(const_cast<Decl *>(D)); else if (const auto *S = N.get<Stmt>()) V.TraverseStmt(const_cast<Stmt *>(S)); Index: clang-tools-extra/clangd/ClangdServer.h =================================================================== --- clang-tools-extra/clangd/ClangdServer.h +++ clang-tools-extra/clangd/ClangdServer.h @@ -344,7 +344,8 @@ Callback<std::vector<HighlightingToken>>); /// Describe the AST subtree for a piece of code. - void getAST(PathRef File, Range R, Callback<llvm::Optional<ASTNode>> CB); + void getAST(PathRef File, llvm::Optional<Range> R, + Callback<llvm::Optional<ASTNode>> CB); /// Runs an arbitrary action that has access to the AST of the specified file. /// The action will execute on one of ClangdServer's internal threads. Index: clang-tools-extra/clangd/ClangdServer.cpp =================================================================== --- clang-tools-extra/clangd/ClangdServer.cpp +++ clang-tools-extra/clangd/ClangdServer.cpp @@ -884,22 +884,29 @@ Transient); } -void ClangdServer::getAST(PathRef File, Range R, +void ClangdServer::getAST(PathRef File, llvm::Optional<Range> R, Callback<llvm::Optional<ASTNode>> CB) { auto Action = [R, CB(std::move(CB))](llvm::Expected<InputsAndAST> Inputs) mutable { if (!Inputs) return CB(Inputs.takeError()); + if (!R) { + // It's safe to pass in the TU, as dumpAST() does not + // deserialize the preamble. + auto Node = DynTypedNode::create( + *Inputs->AST.getASTContext().getTranslationUnitDecl()); + return CB(dumpAST(Node, Inputs->AST.getTokens(), + Inputs->AST.getASTContext())); + } unsigned Start, End; - if (auto Offset = positionToOffset(Inputs->Inputs.Contents, R.start)) + if (auto Offset = positionToOffset(Inputs->Inputs.Contents, R->start)) Start = *Offset; else return CB(Offset.takeError()); - if (auto Offset = positionToOffset(Inputs->Inputs.Contents, R.end)) + if (auto Offset = positionToOffset(Inputs->Inputs.Contents, R->end)) End = *Offset; else return CB(Offset.takeError()); - bool Success = SelectionTree::createEach( Inputs->AST.getASTContext(), Inputs->AST.getTokens(), Start, End, [&](SelectionTree T) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits