https://github.com/hokein updated 
https://github.com/llvm/llvm-project/pull/168177

>From 6b54e09c96ff3c6ec2cd49ea2c4936cf0469c211 Mon Sep 17 00:00:00 2001
From: Haojian Wu <[email protected]>
Date: Fri, 14 Nov 2025 15:48:21 +0100
Subject: [PATCH 1/2] Implement fold range for #pragma region

---
 .../clangd/SemanticSelection.cpp              | 78 ++++++++++++++++++-
 .../unittests/SemanticSelectionTests.cpp      | 15 ++++
 2 files changed, 90 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clangd/SemanticSelection.cpp 
b/clang-tools-extra/clangd/SemanticSelection.cpp
index 3353121a01825..a6a385cd0571d 100644
--- a/clang-tools-extra/clangd/SemanticSelection.cpp
+++ b/clang-tools-extra/clangd/SemanticSelection.cpp
@@ -11,9 +11,13 @@
 #include "Protocol.h"
 #include "Selection.h"
 #include "SourceCode.h"
+#include "support/Bracket.h"
+#include "support/DirectiveTree.h"
+#include "support/Token.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/TokenBufferTokenManager.h"
@@ -22,9 +26,6 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Error.h"
-#include "support/Bracket.h"
-#include "support/DirectiveTree.h"
-#include "support/Token.h"
 #include <optional>
 #include <queue>
 #include <vector>
@@ -163,6 +164,66 @@ llvm::Expected<SelectionRange> getSemanticRanges(ParsedAST 
&AST, Position Pos) {
   return std::move(Head);
 }
 
+class PragmaRegionFinder {
+  // Record the token range of a region:
+  //
+  //   #pragma region [[name
+  //   ...
+  //   ]]#pragma region
+  std::vector<Token::Range> &Ranges;
+  const TokenStream &Code;
+  // Stack of starting token (the name of the region) indices for nested 
#pragma
+  // region.
+  std::vector<unsigned> Stack;
+
+public:
+  PragmaRegionFinder(std::vector<Token::Range> &Ranges, const TokenStream 
&Code)
+      : Ranges(Ranges), Code(Code) {}
+
+  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 &D) {
+    // Get the tokens that make up this directive.
+    auto Tokens = Code.tokens(D.Tokens);
+    if (Tokens.empty())
+      return;
+    const Token &HashToken = Tokens.front();
+    assert(HashToken.Kind == tok::hash);
+    const Token &Pragma = HashToken.nextNC();
+    if (Pragma.text() != "pragma")
+      return;
+    const Token &Value = Pragma.nextNC();
+
+    // Handle "#pragma region name"
+    if (Value.text() == "region") {
+      // Record the name token.
+      if (&Value < Tokens.end())
+        Stack.push_back((&Value + 1)->OriginalIndex);
+      return;
+    }
+
+    // Handle "#pragma endregion"
+    if (Value.text() == "endregion") {
+      if (Stack.empty())
+        return; // unmatched end region; ignore.
+
+      unsigned StartIdx = Stack.back();
+      Stack.pop_back();
+      Ranges.push_back(Token::Range{StartIdx, HashToken.OriginalIndex});
+    }
+  }
+
+  void operator()(const DirectiveTree::Conditional &C) {
+    for (const auto &[_, SubTree] : C.Branches)
+      walk(SubTree);
+  }
+};
+
 // FIXME(kirillbobyrev): Collect comments, PP conditional regions, includes and
 // other code regions (e.g. public/private/protected sections of classes,
 // control flow statement bodies).
@@ -286,6 +347,17 @@ getFoldingRanges(const std::string &Code, bool 
LineFoldingOnly) {
     }
     AddFoldingRange(Start, End, FoldingRange::COMMENT_KIND);
   }
+
+  // #pragma region
+  std::vector<Token::Range> Ranges;
+  PragmaRegionFinder(Ranges, OrigStream).walk(DirectiveStructure);
+  auto Ts = OrigStream.tokens();
+  for (const auto &R : Ranges) {
+    auto End = StartPosition(Ts[R.End]);
+    if (LineFoldingOnly)
+      End.line--;
+    AddFoldingRange(EndPosition(Ts[R.Begin]), End, FoldingRange::REGION_KIND);
+  }
   return Result;
 }
 
diff --git a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp 
b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
index 4efae25dcd077..08cc8a651adc8 100644
--- a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
@@ -410,6 +410,15 @@ TEST(FoldingRanges, PseudoParserWithoutLineFoldings) {
             Variable = 3;
         #
       )cpp",
+      R"cpp(
+        #pragma region R1[[
+        
+        #pragma region R2[[
+         constexpr int a = 2;
+        ]]#pragma endregion
+        
+        ]]#pragma endregion
+      )cpp",
   };
   for (const char *Test : Tests) {
     auto T = Annotations(Test);
@@ -470,6 +479,12 @@ TEST(FoldingRanges, PseudoParserLineFoldingsOnly) {
         //[[ foo
         /* bar */]]
       )cpp",
+      R"cpp(
+        #pragma region abc[[
+        constexpr int a = 2;
+        ]]
+        #pragma endregion
+      )cpp",
       // FIXME: Support folding template arguments.
       // R"cpp(
       // template <[[typename foo, class bar]]> struct baz {};

>From ece8c07c52a6e740b794dad69356bd88ce2c1695 Mon Sep 17 00:00:00 2001
From: Haojian Wu <[email protected]>
Date: Sun, 23 Nov 2025 21:26:30 +0100
Subject: [PATCH 2/2] Address comments, and improve the `#pragma region`
 handling.

---
 clang-tools-extra/clangd/SemanticSelection.cpp      | 13 ++++++++-----
 .../clangd/unittests/SemanticSelectionTests.cpp     |  7 +++++++
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clangd/SemanticSelection.cpp 
b/clang-tools-extra/clangd/SemanticSelection.cpp
index a6a385cd0571d..c2dad53bcec6b 100644
--- a/clang-tools-extra/clangd/SemanticSelection.cpp
+++ b/clang-tools-extra/clangd/SemanticSelection.cpp
@@ -167,9 +167,9 @@ llvm::Expected<SelectionRange> getSemanticRanges(ParsedAST 
&AST, Position Pos) {
 class PragmaRegionFinder {
   // Record the token range of a region:
   //
-  //   #pragma region [[name
+  //   #pragma region name[[
   //   ...
-  //   ]]#pragma region
+  //   ]]#pragma endregion
   std::vector<Token::Range> &Ranges;
   const TokenStream &Code;
   // Stack of starting token (the name of the region) indices for nested 
#pragma
@@ -201,9 +201,12 @@ class PragmaRegionFinder {
 
     // Handle "#pragma region name"
     if (Value.text() == "region") {
-      // Record the name token.
-      if (&Value < Tokens.end())
-        Stack.push_back((&Value + 1)->OriginalIndex);
+      // Find the last token at the same line.
+      const Token *T = &Value.next();
+      while (T < Tokens.end() && T->Line == Pragma.Line)
+        T = &T->next();
+      --T;
+      Stack.push_back(T->OriginalIndex);
       return;
     }
 
diff --git a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp 
b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
index 08cc8a651adc8..2a381d1c8add5 100644
--- a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp
@@ -419,6 +419,13 @@ TEST(FoldingRanges, PseudoParserWithoutLineFoldings) {
         
         ]]#pragma endregion
       )cpp",
+      R"cpp(
+        #pragma region[[
+        ]]#pragma endregion
+
+        #pragma /*comment1*/ region /*comment2*/name[[
+        ]]#pragma endregion
+      )cpp",
   };
   for (const char *Test : Tests) {
     auto T = Annotations(Test);

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to