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

Reply via email to