[clang-tools-extra] [clangd][HLSL] Add hover support for vector swizzle and matrix element access (PR #212741)
Maria Fernanda GuimarĂ£es via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 29 04:20:46 PDT 2026
https://github.com/mafeguimaraes created https://github.com/llvm/llvm-project/pull/212741
Hovering over a vector swizzle expression (e.g. `.xyz`) or a matrix element access (e.g. `._m00`) previously produced no hover information, since ExtVectorElementExpr and MatrixElementExpr were not handled in getHoverContents(const Expr *E).
Add a dedicated getHLSLHoverContents helper that extracts the accessor name and resolved type for both node kinds.
Fixes #212612
>From aacf82e2bfb0e91b32e6a7fac30a3fddfd35d3ee Mon Sep 17 00:00:00 2001
From: Maria Fernanda Guimaraes <mariafefe201 at gmail.com>
Date: Wed, 29 Jul 2026 11:18:33 +0000
Subject: [PATCH] [clangd][HLSL] Add hover support for vector swizzle and
matrix element access
Hovering over a vector swizzle expression (e.g. `.xyz`) or a matrix
element access (e.g. `._m00`) previously produced no hover information,
since ExtVectorElementExpr and MatrixElementExpr were not handled in
getHoverContents(const Expr *E).
Add a dedicated getHLSLHoverContents helper that extracts the accessor
name and resolved type for both node kinds. No evaluation is needed
since the type is already resolved by Sema.
Fixes #212612
---
clang-tools-extra/clangd/Hover.cpp | 20 ++++
.../clangd/unittests/HoverTests.cpp | 103 ++++++++++++++++++
2 files changed, 123 insertions(+)
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index fab77af3ebcea..f475e2d5e37c6 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -951,6 +951,23 @@ llvm::StringLiteral getNameForExpr(const Expr *E) {
void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI,
const PrintingPolicy &PP);
+static std::optional<HoverInfo> getHLSLHoverContents(const Expr *E,
+ ParsedAST &AST,
+ const PrintingPolicy &PP) {
+ HoverInfo HI;
+ if (const auto *VecExpr = dyn_cast<ExtVectorElementExpr>(E)) {
+ HI.Name = VecExpr->getAccessor().getName().str();
+ HI.Type = printType(VecExpr->getType(), AST.getASTContext(), PP);
+ return HI;
+ }
+ if (const auto *MatExpr = dyn_cast<MatrixElementExpr>(E)) {
+ HI.Name = MatExpr->getAccessor().getName().str();
+ HI.Type = printType(MatExpr->getType(), AST.getASTContext(), PP);
+ return HI;
+ }
+ return std::nullopt;
+}
+
// Generates hover info for `this` and evaluatable expressions.
// FIXME: Support hover for literals (esp user-defined)
std::optional<HoverInfo> getHoverContents(const SelectionTree::Node *N,
@@ -959,6 +976,9 @@ std::optional<HoverInfo> getHoverContents(const SelectionTree::Node *N,
const SymbolIndex *Index) {
std::optional<HoverInfo> HI;
+ if (auto HLSLHI = getHLSLHoverContents(E, AST, PP))
+ return HLSLHI;
+
if (const StringLiteral *SL = dyn_cast<StringLiteral>(E)) {
// Print the type and the size for string literals
HI = getStringLiteralContents(SL, PP);
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index e0773708df0eb..8bcff0f699de9 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -5311,6 +5311,109 @@ TEST(Hover, FunctionParameters) {
}
}
+TEST(Hover, HLSLVectorAndMatrixSwizzle) {
+ struct {
+ const char *const Code;
+ const std::function<void(HoverInfo &)> ExpectedBuilder;
+ } Cases[] = {
+ {
+ R"cpp(
+ typedef float float3 __attribute__((ext_vector_type(3)));
+ void main() {
+ float3 v;
+ float3 s = v.^[[xyz]];
+ }
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "xyz";
+ HI.Type = "float3";
+ }},
+ {
+ R"cpp(
+ typedef float float3 __attribute__((ext_vector_type(3)));
+ typedef float float2 __attribute__((ext_vector_type(2)));
+ void main() {
+ float3 v;
+ float2 s = v.^[[xy]];
+ }
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "xy";
+ HI.Type = "float2";
+ }},
+ {
+ R"cpp(
+ typedef float float4x4 __attribute__((matrix_type(4, 4)));
+ void main() {
+ float4x4 m;
+ float e = m.^[[_m00]];
+ }
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.Name = "_m00";
+ HI.Type = "float";
+ }},
+ };
+
+ for (const auto &Case : Cases) {
+ SCOPED_TRACE(Case.Code);
+ Annotations T(Case.Code);
+ TestTU TU = TestTU::withCode(T.code());
+ TU.Filename = "TestTU.hlsl";
+ TU.ExtraArgs.push_back("-x");
+ TU.ExtraArgs.push_back("hlsl");
+ TU.ExtraArgs.push_back("-fenable-matrix");
+ TU.ExtraArgs.push_back("--target=dxil-pc-shadermodel6.3-library");
+ auto AST = TU.build();
+ auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
+ ASSERT_TRUE(H);
+ HoverInfo Expected;
+ Expected.SymRange = T.range();
+ Case.ExpectedBuilder(Expected);
+ SCOPED_TRACE(H->present(MarkupKind::PlainText));
+ EXPECT_EQ(H->Name, Expected.Name);
+ EXPECT_EQ(H->Type, Expected.Type);
+ EXPECT_EQ(H->SymRange, Expected.SymRange);
+ }
+}
+
+TEST(Hover, HLSLInvalidMatrixSwizzleNoCrash) {
+ Annotations T(R"cpp(
+ typedef float float2x2 __attribute__((matrix_type(2, 2)));
+ void main() {
+ float2x2 m;
+ float bad = m.^[[_m22]]; // out of bounds for a 2x2 matrix /*error-ok*/
+ }
+ )cpp");
+ TestTU TU = TestTU::withCode(T.code());
+ TU.Filename = "TestTU.hlsl";
+ TU.ExtraArgs.push_back("-x");
+ TU.ExtraArgs.push_back("hlsl");
+ TU.ExtraArgs.push_back("-fenable-matrix");
+ TU.ExtraArgs.push_back("--target=dxil-pc-shadermodel6.3-library");
+ auto AST = TU.build();
+ auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
+ EXPECT_FALSE(H);
+}
+
+TEST(Hover, HLSLInvalidVectorSwizzleNoCrash) {
+ Annotations T(R"cpp(
+ typedef float float3 __attribute__((ext_vector_type(3)));
+ void main() {
+ float3 v;
+ float bad = v.^[[w]]; // 'w' is not a valid component for a 3-component vector /*error-ok*/
+ }
+ )cpp");
+ TestTU TU = TestTU::withCode(T.code());
+ TU.Filename = "TestTU.hlsl";
+ TU.ExtraArgs.push_back("-x");
+ TU.ExtraArgs.push_back("hlsl");
+ TU.ExtraArgs.push_back("--target=dxil-pc-shadermodel6.3-library");
+ auto AST = TU.build();
+ auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
+ EXPECT_FALSE(H);
+}
+
} // namespace
} // namespace clangd
} // namespace clang
More information about the cfe-commits
mailing list