[clang-tools-extra] [clangd] Implement simple folding of preprocessor branches (PR #80592)

via cfe-commits cfe-commits at lists.llvm.org
Sun Feb 4 01:00:42 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangd

Author: Ruihua Dong (144026)

<details>
<summary>Changes</summary>

Extract directive branches information from DirectiveTree, fold branches that don't end with eof.

Fixes https://github.com/clangd/clangd/issues/1661

Examples:

Folded: 
<img width="400" alt="image" src="https://github.com/llvm/llvm-project/assets/44112701/c5b7ab39-7371-47f8-9d0d-29f11dbc9a1f">

Unfolded:
<img width="400" alt="image" src="https://github.com/llvm/llvm-project/assets/44112701/6bfcb325-26b1-4435-9e3d-f2deed8136ef">

Folded (unpaired conditionals):
<img width="400" alt="image" src="https://github.com/llvm/llvm-project/assets/44112701/fdddfcf8-866f-4ab7-b8a7-6848f9bee0de">

Unfolded (unpaired conditionals):
<img width="400" alt="image" src="https://github.com/llvm/llvm-project/assets/44112701/090a9f31-69d7-41de-ba45-54f86196da9f">





---
Full diff: https://github.com/llvm/llvm-project/pull/80592.diff


3 Files Affected:

- (modified) clang-tools-extra/clangd/SemanticSelection.cpp (+18) 
- (modified) clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h (+3) 
- (modified) clang-tools-extra/pseudo/lib/DirectiveTree.cpp (+54) 


``````````diff
diff --git a/clang-tools-extra/clangd/SemanticSelection.cpp b/clang-tools-extra/clangd/SemanticSelection.cpp
index 3d687173b2be9..d2aefb51fd49a 100644
--- a/clang-tools-extra/clangd/SemanticSelection.cpp
+++ b/clang-tools-extra/clangd/SemanticSelection.cpp
@@ -220,6 +220,24 @@ getFoldingRanges(const std::string &Code, bool LineFoldingOnly) {
   auto EndPosition = [&](const pseudo::Token &T) {
     return offsetToPosition(Code, EndOffset(T));
   };
+
+  // Preprocessor directives
+  auto PPRanges = pseudo::pairDirectiveRanges(DirectiveStructure, OrigStream);
+  for (const auto &R : PPRanges) {
+    auto BTok = OrigStream.tokens()[R.Begin];
+    auto ETok = OrigStream.tokens()[R.End];
+    if (ETok.Kind == tok::eof)
+      continue;
+    if (BTok.Line >= ETok.Line)
+      continue;
+
+    Position Start = EndPosition(BTok);
+    Position End = StartPosition(ETok);
+    if (LineFoldingOnly)
+      End.line--;
+    AddFoldingRange(Start, End, FoldingRange::REGION_KIND);
+  }
+
   auto Tokens = ParseableStream.tokens();
   // Brackets.
   for (const auto &Tok : Tokens) {
diff --git a/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h b/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h
index 2b6cb63297915..2e5f007f94a76 100644
--- a/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h
+++ b/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h
@@ -124,6 +124,9 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &,
 /// The choices are stored in Conditional::Taken nodes.
 void chooseConditionalBranches(DirectiveTree &, const TokenStream &Code);
 
+std::vector<Token::Range> pairDirectiveRanges(const DirectiveTree &Tree,
+                                              const TokenStream &Code);
+
 } // namespace pseudo
 } // namespace clang
 
diff --git a/clang-tools-extra/pseudo/lib/DirectiveTree.cpp b/clang-tools-extra/pseudo/lib/DirectiveTree.cpp
index 9e853e46edc23..4882f01890654 100644
--- a/clang-tools-extra/pseudo/lib/DirectiveTree.cpp
+++ b/clang-tools-extra/pseudo/lib/DirectiveTree.cpp
@@ -353,5 +353,59 @@ TokenStream DirectiveTree::stripDirectives(const TokenStream &In) const {
   return Out;
 }
 
+namespace {
+class RangePairer {
+  std::vector<Token::Range> &Ranges;
+
+public:
+  RangePairer(std::vector<Token::Range> &Ranges) : Ranges(Ranges) {}
+
+  void walk(const DirectiveTree &T) {
+    for (const auto &C : T.Chunks)
+      std::visit(*this, C);
+  }
+
+  void operator()(const DirectiveTree::Code &C) {}
+
+  void operator()(const DirectiveTree::Directive &) {}
+
+  void operator()(const DirectiveTree::Conditional &C) {
+    Token::Range Range;
+    Token::Index Last;
+    auto First = true;
+    for (const auto &B : C.Branches) {
+      if (First) {
+        First = false;
+      } else {
+        Range = {Last, B.first.Tokens.Begin};
+        Ranges.push_back(Range);
+      }
+      Last = B.first.Tokens.Begin;
+    }
+    Range = {Last, C.End.Tokens.Begin};
+    Ranges.push_back(Range);
+
+    for (const auto &B : C.Branches)
+      walk(B.second);
+  }
+};
+} // namespace
+
+std::vector<Token::Range> pairDirectiveRanges(const DirectiveTree &Tree,
+                                              const TokenStream &Code) {
+  std::vector<Token::Range> Ranges;
+  RangePairer(Ranges).walk(Tree);
+
+  // Transform paired ranges to start with last token in its logical line
+  for (auto &R : Ranges) {
+    const Token *Tok = &Code.tokens()[R.Begin + 1];
+    while (Tok->Kind != tok::eof && !Tok->flag(LexFlags::StartsPPLine))
+      ++Tok;
+    Tok = Tok - 1;
+    R.Begin = Tok->OriginalIndex;
+  }
+  return std::move(Ranges);
+}
+
 } // namespace pseudo
 } // namespace clang

``````````

</details>


https://github.com/llvm/llvm-project/pull/80592


More information about the cfe-commits mailing list