https://github.com/mafeguimaraes updated https://github.com/llvm/llvm-project/pull/212741
From aa8f03238bed919c834416d07d5ff159fcff7e98 Mon Sep 17 00:00:00 2001 From: Maria Fernanda Guimaraes <[email protected]> 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 | 19 ++++ .../clangd/unittests/HoverTests.cpp | 103 ++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index fab77af3ebcea..de73ea0589eaf 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -951,6 +951,22 @@ 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 +975,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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
