Author: Maria Fernanda GuimarĂ£es
Date: 2026-08-14T22:58:24+08:00
New Revision: b79317f9877d805a5091b26dd1f2eb795b5aca05

URL: 
https://github.com/llvm/llvm-project/commit/b79317f9877d805a5091b26dd1f2eb795b5aca05
DIFF: 
https://github.com/llvm/llvm-project/commit/b79317f9877d805a5091b26dd1f2eb795b5aca05.diff

LOG: [clangd] Add hover support for statement attributes (#214318)

Hovering over `[unroll]`, `[loop]`, `[branch]`, or `[flatten]` should
display the attribute name and documentation about its effect on GPU
shader execution.

This patch extends clangd's `SelectionTree` to traverse attributes
attached to `AttributedStmt` nodes before visiting the underlying
statement.

Fixes #214067

Added: 
    

Modified: 
    clang-tools-extra/clangd/Selection.cpp
    clang-tools-extra/clangd/unittests/HoverTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/Selection.cpp 
b/clang-tools-extra/clangd/Selection.cpp
index b79ffc7d5a6e9..41d028cfcf4b5 100644
--- a/clang-tools-extra/clangd/Selection.cpp
+++ b/clang-tools-extra/clangd/Selection.cpp
@@ -666,6 +666,14 @@ class SelectionVisitor : public 
RecursiveASTVisitor<SelectionVisitor> {
   bool TraverseAttr(Attr *X) {
     return traverseNode(X, [&] { return Base::TraverseAttr(X); });
   }
+  bool TraverseAttributedStmt(AttributedStmt *S) {
+    return traverseNode(S, [&] {
+      for (const Attr *A : S->getAttrs())
+        if (!TraverseAttr(const_cast<Attr *>(A)))
+          return false;
+      return TraverseStmt(S->getSubStmt());
+    });
+  }
   bool TraverseConceptReference(ConceptReference *X) {
     return traverseNode(X, [&] { return Base::TraverseConceptReference(X); });
   }

diff  --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp 
b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 02ce48c6dca95..d355118f30761 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -5412,6 +5412,87 @@ TEST(Hover, HLSLInvalidVectorSwizzleNoCrash) {
   EXPECT_FALSE(H);
 }
 
+TEST(Hover, AttributedStmt) {
+  struct {
+    const char *const Code;
+    const char *const ExpectedName;
+    bool IsHLSL;
+    bool ExpectDocumentation;
+  } Cases[] = {
+      {R"hlsl(
+         [numthreads(1, 1, 1)]
+         void main() {
+           [^unroll]
+           for (int i = 0; i < 4; i++) {}
+         }
+       )hlsl",
+       "unroll", /*IsHLSL=*/true, /*ExpectDocumentation=*/true},
+      {R"hlsl(
+         [numthreads(1, 1, 1)]
+         void main() {
+           [l^oop]
+           for (int i = 0; i < 4; i++) {}
+         }
+       )hlsl",
+       "loop", /*IsHLSL=*/true, /*ExpectDocumentation=*/true},
+      {R"hlsl(
+         [numthreads(1, 1, 1)]
+         void main() {
+           [b^ranch]
+           if (true) {}
+         }
+       )hlsl",
+       "branch", /*IsHLSL=*/true, /*ExpectDocumentation=*/false},
+      {R"hlsl(
+         [numthreads(1, 1, 1)]
+         void main() {
+           [f^latten]
+           if (true) {}
+         }
+       )hlsl",
+       "flatten", /*IsHLSL=*/true, /*ExpectDocumentation=*/false},
+      {R"cpp(
+         void foo() {
+           [[^likely]] if (true) {}
+         }
+       )cpp",
+       "likely", /*IsHLSL=*/false, /*ExpectDocumentation=*/false},
+      {R"cpp(
+         void foo() {
+           [[^unlikely]] if (true) {}
+         }
+       )cpp",
+       "unlikely", /*IsHLSL=*/false, /*ExpectDocumentation=*/false},
+      {R"cpp(
+         void foo() {
+           switch (1) {
+           case 1:
+             [[^fallthrough]];
+           case 2:
+             break;
+           }
+         }
+       )cpp",
+       "fallthrough", /*IsHLSL=*/false, /*ExpectDocumentation=*/false},
+  };
+  for (const auto &Case : Cases) {
+    SCOPED_TRACE(Case.Code);
+    Annotations T(Case.Code,
+                  
Annotations::Markers().setRangeBegin("{{").setRangeEnd("}}"));
+    TestTU TU = TestTU::withCode(T.code());
+    if (Case.IsHLSL)
+      configureHLSL(TU);
+    else
+      TU.ExtraArgs.push_back("-std=c++20");
+    auto AST = TU.build();
+    auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
+    ASSERT_TRUE(H);
+    EXPECT_EQ(H->Name, Case.ExpectedName);
+    if (Case.ExpectDocumentation) {
+      EXPECT_FALSE(H->Documentation.empty());
+    }
+  }
+}
 TEST(Hover, HLSLRegisterAttributeRange) {
   Annotations T(R"hlsl(
     Texture2D tex : [[^register]]([[^t1]]);


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

Reply via email to