kbobyrev updated this revision to Diff 299620.
kbobyrev added a comment.
Fix a typo and remove invalid const-ness.
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
clang/include/clang/Tooling/Syntax/Tree.h
Index: clang/include/clang/Tooling/Syntax/Tree.h
===================================================================
--- clang/include/clang/Tooling/Syntax/Tree.h
+++ clang/include/clang/Tooling/Syntax/Tree.h
@@ -169,9 +169,11 @@
return const_cast<Tree *>(this)->findLastLeaf();
}
-protected:
/// Find the first node with a corresponding role.
Node *findChild(NodeRole R);
+ const Node *findChild(NodeRole R) const {
+ return const_cast<syntax::Tree *>(this)->findChild(R);
+ }
private:
/// Prepend \p Child to the list of children and and sets the parent pointer.
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,59 @@
TEST(FoldingRanges, All) {
const char *Tests[] = {
R"cpp(
- [[int global_variable]];
+ void func() {[[
+ int Variable = 100;
- [[void func() {
- int v = 100;
- }]]
+ if (Variable > 5) {[[
+ Variable += 42;
+ ]]} else if (Variable++)
+ ++Variable;
+ else {[[
+ Variable--;
+ ]]}
+
+ // Do not generate FoldingRange for empty CompoundStmts.
+ for (;;) {}
+
+ // If there are newlines between {}, we should generate one.
+ for (;;) {[[
+
+ ]]}
+ ]]}
)cpp",
R"cpp(
- [[class Foo {
+ #define FOO int foo() {}
+
+ // Do not generate folding range for braces within macro expansion.
+ FOO
+
+ // Do not generate folding range within macro arguments.
+ #define FUNCTOR(functor) functor
+ void func() {[[
+ FUNCTOR([](){});
+ ]]}
+
+ // Do not generate folding range with a brace coming from macro.
+ #define LBRACE {
+ void bar() LBRACE
+ int X = 42;
+ }
+ )cpp",
+ R"cpp(
+ class Foo {
public:
- [[Foo() {
+ Foo() {[[
int X = 1;
- }]]
+ ]]}
private:
- [[int getBar() {
+ int getBar() {[[
return 42;
- }]]
+ ]]}
- [[void getFooBar() { }]]
- }]];
+ // Braces are located at the same line: no folding range here.
+ 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
@@ -5,6 +5,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+
#include "SemanticSelection.h"
#include "FindSymbols.h"
#include "ParsedAST.h"
@@ -13,8 +14,16 @@
#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/Nodes.h"
+#include "clang/Tooling/Syntax/Tree.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Error.h"
+#include <queue>
+#include <vector>
namespace clang {
namespace clangd {
@@ -28,17 +37,59 @@
}
}
-// Recursively collects FoldingRange from a symbol and its children.
-void collectFoldingRanges(DocumentSymbol Symbol,
- std::vector<FoldingRange> &Result) {
+llvm::Optional<FoldingRange> toFoldingRange(SourceRange SR,
+ const SourceManager &SM) {
+ // Don't produce folding ranges when SourceRange either of bounds is coming
+ // from macros.
+ if (SR.getBegin().isMacroID() || SR.getEnd().isMacroID())
+ return llvm::None;
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;
+}
+
+llvm::Optional<FoldingRange> extractFoldingRange(const syntax::Node *Node,
+ const SourceManager &SM) {
+ if (const auto *Stmt = dyn_cast<syntax::CompoundStatement>(Node)) {
+ const auto *LBrace = cast_or_null<syntax::Leaf>(
+ Stmt->findChild(syntax::NodeRole::OpenParen)),
+ *RBrace = cast_or_null<syntax::Leaf>(
+ Stmt->findChild(syntax::NodeRole::CloseParen));
+ if (!LBrace || !RBrace)
+ return llvm::None;
+ // Fold the entire range within braces, including whitespace.
+ const SourceRange SR(LBrace->getToken()->endLocation(),
+ RBrace->getToken()->location());
+ auto Range = toFoldingRange(SR, SM);
+ // Do not generate folding range for compound statements without any
+ // nodes and newlines.
+ if (Range && Range->startLine != Range->endLine)
+ return Range;
+ }
+ return llvm::None;
+}
+
+// Traverse the tree and collect folding ranges along the way.
+std::vector<FoldingRange> collectFoldingRanges(const syntax::Node *Root,
+ const SourceManager &SM) {
+ std::queue<const syntax::Node *> Nodes;
+ Nodes.push(Root);
+ std::vector<FoldingRange> Result;
+ while (!Nodes.empty()) {
+ const syntax::Node *Node = Nodes.front();
+ Nodes.pop();
+ const auto Range = extractFoldingRange(Node, SM);
+ if (Range)
+ Result.push_back(*Range);
+ if (const auto *T = dyn_cast<syntax::Tree>(Node))
+ for (const auto *NextNode = T->getFirstChild(); NextNode;
+ NextNode = NextNode->getNextSibling())
+ Nodes.push(NextNode);
+ }
+ return Result;
}
} // namespace
@@ -100,20 +151,12 @@
// 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();
- std::vector<FoldingRange> Result;
- for (const auto &Symbol : *DocumentSymbols)
- collectFoldingRanges(Symbol, Result);
- return Result;
+ syntax::Arena A(AST.getSourceManager(), AST.getLangOpts(), AST.getTokens());
+ const auto *SyntaxTree =
+ syntax::buildSyntaxTree(A, *AST.getASTContext().getTranslationUnitDecl());
+ return collectFoldingRanges(SyntaxTree, AST.getSourceManager());
}
} // namespace clangd
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits