kbobyrev updated this revision to Diff 299281.
kbobyrev added a comment.

Add support for compound statements.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D88553/new/

https://reviews.llvm.org/D88553

Files:
  clang-tools-extra/clangd/SemanticSelection.cpp
  clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp

Index: clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
+++ clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
@@ -203,26 +203,87 @@
 TEST(FoldingRanges, All) {
   const char *Tests[] = {
       R"cpp(
-        [[int global_variable]];
+        void func() {[[
+          int Variable = 100;
 
-        [[void func() {
-          int v = 100;
-        }]]
+          if (Variable > 42) {[[
+            Variable = 10;
+            ++Variable;
+          ]]}
+
+
+          if (Variable >= 9000) {[[
+            Variable -= 500;
+          ]]} else {[[
+            Variable = 42;
+          ]]}
+
+          if (42 > 5) {[[
+            Variable += 42;
+          ]]} else if (Variable++) {[[
+            ++Variable;
+          ]]} else {[[
+            Variable--;
+          ]]}
+
+          bool OK = true;
+
+          if (OK) {[[
+            Variable++;
+          ]]} else
+            --Variable;
+
+          switch (Variable) {[[
+          case 1:
+            ++Variable;
+            break;
+          case 2:
+            break;
+          default:
+            break;
+          ]]}
+        ]]}
       )cpp",
       R"cpp(
-        [[class Foo {
+        void foo() {[[
+          // Do not generate FoldingRange for empty CompoundStmts.
+          for (;;) {}
+
+          // However, if there are newlines between {}, we will still generate
+          // one.
+          for (;;) {[[
+
+          ]]}
+
+          unsigned Variable = 42;
+
+          for (int i = 0; i < 42; ++i) {[[
+            Variable += 10;
+          ]]}
+
+          while (Variable) {[[
+            Variable--;
+          ]]}
+
+          do {[[
+
+          ]]} while (Variable);
+        ]]}
+      )cpp",
+      R"cpp(
+        class Foo {
         public:
-          [[Foo() {
+          Foo() {[[
             int X = 1;
-          }]]
+          ]]}
 
         private:
-          [[int getBar() {
+          int getBar() {[[
             return 42;
-          }]]
+          ]]}
 
-          [[void getFooBar() { }]]
-        }]];
+          void getFooBar() { }
+        };
       )cpp",
   };
   for (const char *Test : Tests) {
Index: clang-tools-extra/clangd/SemanticSelection.cpp
===================================================================
--- clang-tools-extra/clangd/SemanticSelection.cpp
+++ clang-tools-extra/clangd/SemanticSelection.cpp
@@ -13,8 +13,15 @@
 #include "SourceCode.h"
 #include "clang/AST/DeclBase.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TokenKinds.h"
+#include "clang/Tooling/Syntax/BuildTree.h"
+#include "clang/Tooling/Syntax/Tree.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/Error.h"
+#include <vector>
 
 namespace clang {
 namespace clangd {
@@ -28,17 +35,39 @@
   }
 }
 
-// Recursively collects FoldingRange from a symbol and its children.
-void collectFoldingRanges(DocumentSymbol Symbol,
-                          std::vector<FoldingRange> &Result) {
+FoldingRange constructFoldingRange(SourceRange SR, const SourceManager &SM) {
   FoldingRange Range;
-  Range.startLine = Symbol.range.start.line;
-  Range.startCharacter = Symbol.range.start.character;
-  Range.endLine = Symbol.range.end.line;
-  Range.endCharacter = Symbol.range.end.character;
-  Result.push_back(Range);
-  for (const auto &Child : Symbol.children)
-    collectFoldingRanges(Child, Result);
+  Range.startCharacter = SM.getSpellingColumnNumber(SR.getBegin()) - 1;
+  Range.startLine = SM.getSpellingLineNumber(SR.getBegin()) - 1;
+  Range.endCharacter = SM.getSpellingColumnNumber(SR.getEnd()) - 1;
+  Range.endLine = SM.getSpellingLineNumber(SR.getEnd()) - 1;
+  return Range;
+}
+
+// Traverse the tree and collect folding ranges along the way.
+void collectRanges(const syntax::Node *Node, const SourceManager &SM,
+                   std::vector<FoldingRange> &Ranges) {
+  if (Node->getKind() == syntax::NodeKind::CompoundStatement) {
+    const auto *Tree = dyn_cast<syntax::Tree>(Node);
+    assert(Tree);
+    const syntax::Token *FirstToken = Tree->findFirstLeaf()->getToken(),
+                        *LastToken = Tree->findLastLeaf()->getToken();
+    assert(FirstToken->kind() == tok::TokenKind::l_brace);
+    assert(LastToken->kind() == tok::TokenKind::r_brace);
+    const SourceRange SR(FirstToken->endLocation(), LastToken->location());
+    FoldingRange Range = constructFoldingRange(SR, SM);
+    // Do not generate folding range for compound statements without any
+    // nodes and newlines.
+    if (Tree->findFirstLeaf()->getNextSibling() != Tree->findLastLeaf() ||
+        Range.startLine != Range.endLine)
+      Ranges.push_back(Range);
+  }
+  if (auto *T = dyn_cast<syntax::Tree>(Node)) {
+    for (const auto *NextNode = T->getFirstChild(); NextNode;
+         NextNode = NextNode->getNextSibling()) {
+      collectRanges(NextNode, SM, Ranges);
+    }
+  }
 }
 
 } // namespace
@@ -100,19 +129,13 @@
 // FIXME(kirillbobyrev): Collect comments, PP conditional regions, includes and
 // other code regions (e.g. public/private/protected sections of classes,
 // control flow statement bodies).
-// Related issue:
-// https://github.com/clangd/clangd/issues/310
+// Related issue: https://github.com/clangd/clangd/issues/310
 llvm::Expected<std::vector<FoldingRange>> getFoldingRanges(ParsedAST &AST) {
-  // FIXME(kirillbobyrev): getDocumentSymbols() is conveniently available but
-  // limited (e.g. doesn't yield blocks inside functions and provides ranges for
-  // nodes themselves instead of their contents which is less useful). Replace
-  // this with a more general RecursiveASTVisitor implementation instead.
-  auto DocumentSymbols = getDocumentSymbols(AST);
-  if (!DocumentSymbols)
-    return DocumentSymbols.takeError();
+  syntax::Arena A(AST.getSourceManager(), AST.getLangOpts(), AST.getTokens());
+  const auto *SyntaxTree =
+      syntax::buildSyntaxTree(A, *AST.getASTContext().getTranslationUnitDecl());
   std::vector<FoldingRange> Result;
-  for (const auto &Symbol : *DocumentSymbols)
-    collectFoldingRanges(Symbol, Result);
+  collectRanges(SyntaxTree, AST.getSourceManager(), Result);
   return Result;
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D88553: [clangd] St... Kirill Bobyrev via Phabricator via cfe-commits

Reply via email to