[clang] [clang-tools-extra] [clangd][HLSL] Separate statement and declaration attributes code complete in [...] (PR #215353)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 14 09:56:17 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tools-extra
Author: Maria Fernanda GuimarĂ£es (mafeguimaraes)
<details>
<summary>Changes</summary>
This PR addresses the issue where code completion inside `[...]` in HLSL mixed statement and declaration attributes.
Previously, `ParseMicrosoftAttributes` called `CodeCompleteAttribute(AS_Microsoft)` without threading the `IsStmt `context, causing statement attributes (like `[unroll]`) and declaration attributes (like `[numthreads]`) to appear together, alongside semantic annotations (like `SV_Target`).
Fixes #<!-- -->214792
---
Full diff: https://github.com/llvm/llvm-project/pull/215353.diff
6 Files Affected:
- (modified) clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp (+49)
- (modified) clang/include/clang/Parse/Parser.h (+5-3)
- (modified) clang/include/clang/Sema/SemaCodeCompletion.h (+5)
- (modified) clang/lib/Parse/ParseDeclCXX.cpp (+13-5)
- (modified) clang/lib/Parse/ParseStmt.cpp (+1-1)
- (modified) clang/lib/Sema/SemaCodeComplete.cpp (+35)
``````````diff
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 4c1cab7b11e60..dca5ab072f537 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -5163,6 +5163,55 @@ TEST(CompletionTest, FuzzyMatchMacro) {
}
}
+static void configureHLSL(TestTU &TU, bool EnableMatrix = false) {
+ TU.Filename = "TestTU.hlsl";
+ TU.ExtraArgs.push_back("-x");
+ TU.ExtraArgs.push_back("hlsl");
+ if (EnableMatrix)
+ TU.ExtraArgs.push_back("-fenable-matrix");
+ TU.ExtraArgs.push_back("--target=dxil-pc-shadermodel6.3-library");
+}
+
+TEST(CompletionTest, HLSLBracketAttributes) {
+ Annotations DeclContext(R"hlsl(
+ [^]
+ void main() {}
+ )hlsl");
+
+ TestTU TUDecl = TestTU::withCode(DeclContext.code());
+ configureHLSL(TUDecl);
+ auto ResultsDecl = completions(TUDecl, DeclContext.point());
+
+ EXPECT_THAT(ResultsDecl.Completions,
+ Contains(Field(&CodeCompletion::Name, "numthreads")));
+ EXPECT_THAT(ResultsDecl.Completions,
+ Contains(Field(&CodeCompletion::Name, "WaveSize")));
+ EXPECT_THAT(ResultsDecl.Completions,
+ Not(Contains(Field(&CodeCompletion::Name, "unroll"))));
+ EXPECT_THAT(ResultsDecl.Completions,
+ Not(Contains(Field(&CodeCompletion::Name, "SV_Target"))));
+
+ Annotations StmtContext(R"hlsl(
+ void main() {
+ [^]
+ for (int i = 0; i < 4; i++) {}
+ }
+ )hlsl");
+
+ TestTU TUStmt = TestTU::withCode(StmtContext.code());
+ configureHLSL(TUStmt);
+ auto ResultsStmt = completions(TUStmt, StmtContext.point());
+
+ EXPECT_THAT(ResultsStmt.Completions,
+ Contains(Field(&CodeCompletion::Name, "unroll")));
+ EXPECT_THAT(ResultsStmt.Completions,
+ Contains(Field(&CodeCompletion::Name, "loop")));
+ EXPECT_THAT(ResultsStmt.Completions,
+ Not(Contains(Field(&CodeCompletion::Name, "numthreads"))));
+ EXPECT_THAT(ResultsStmt.Completions,
+ Not(Contains(Field(&CodeCompletion::Name, "SV_Target"))));
+}
+
} // namespace
} // namespace clangd
} // namespace clang
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 163aa483a84e3..b7a311fd9fc6f 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2337,12 +2337,13 @@ class Parser : public CodeCompletionHandler {
return false;
}
- bool MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs) {
+ bool MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs,
+ bool IsStmtContext = false) {
bool AttrsParsed = false;
if ((getLangOpts().MicrosoftExt || getLangOpts().HLSL) &&
Tok.is(tok::l_square)) {
ParsedAttributes AttrsWithRange(AttrFactory);
- ParseMicrosoftAttributes(AttrsWithRange);
+ ParseMicrosoftAttributes(AttrsWithRange, IsStmtContext);
AttrsParsed = !AttrsWithRange.empty();
Attrs.takeAllAppendingFrom(AttrsWithRange);
}
@@ -3133,7 +3134,8 @@ class Parser : public CodeCompletionHandler {
/// ms-attribute[opt]
/// ms-attribute ms-attribute-seq
/// \endverbatim
- void ParseMicrosoftAttributes(ParsedAttributes &Attrs);
+ void ParseMicrosoftAttributes(ParsedAttributes &Attrs,
+ bool IsStmtContext = false);
void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs);
void ParseNullabilityClassAttributes(ParsedAttributes &attrs);
diff --git a/clang/include/clang/Sema/SemaCodeCompletion.h b/clang/include/clang/Sema/SemaCodeCompletion.h
index 7203b19d58898..b9fe3634992c0 100644
--- a/clang/include/clang/Sema/SemaCodeCompletion.h
+++ b/clang/include/clang/Sema/SemaCodeCompletion.h
@@ -234,6 +234,11 @@ class SemaCodeCompletion : public SemaBase {
void CodeCompleteIncludedFile(llvm::StringRef Dir, bool IsAngled);
void CodeCompleteNaturalLanguage();
void CodeCompleteAvailabilityPlatformName();
+ void CodeCompleteHLSLAttributes(
+ llvm::ArrayRef<AttributeCommonInfo::Syntax> Syntaxes,
+ std::optional<ParsedAttr::Kind> RestrictToKind = std::nullopt,
+ bool RequireStmt = false,
+ std::optional<ParsedAttr::Kind> ExcludeKind = std::nullopt);
void
GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo,
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index a3617c3db49c4..0f01b9aae31f6 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -4921,7 +4921,8 @@ void Parser::ParseHLSLRootSignatureAttributeArgs(ParsedAttributes &Attrs) {
ParsedAttr::Form::Microsoft());
}
-void Parser::ParseMicrosoftAttributes(ParsedAttributes &Attrs) {
+void Parser::ParseMicrosoftAttributes(ParsedAttributes &Attrs,
+ bool IsStmtContext) {
assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list");
SourceLocation StartLoc = Tok.getLocation();
@@ -4937,10 +4938,17 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &Attrs) {
StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
if (Tok.is(tok::code_completion)) {
cutOffParsing();
- Actions.CodeCompletion().CodeCompleteAttribute(
- AttributeCommonInfo::AS_Microsoft,
- SemaCodeCompletion::AttributeCompletion::Attribute,
- /*Scope=*/nullptr);
+ if (getLangOpts().HLSL) {
+ Actions.CodeCompletion().CodeCompleteHLSLAttributes(
+ {AttributeCommonInfo::AS_Microsoft}, /*Kind=*/std::nullopt,
+ /*RequireStmt=*/IsStmtContext,
+ /*ExcludeKind=*/ParsedAttr::AT_HLSLParsedSemantic);
+ } else {
+ Actions.CodeCompletion().CodeCompleteAttribute(
+ AttributeCommonInfo::AS_Microsoft,
+ SemaCodeCompletion::AttributeCompletion::Attribute,
+ /*Scope=*/nullptr);
+ }
break;
}
if (Tok.isNot(tok::identifier)) // ']', but also eof
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 219bcd980e860..b6d587cf96856 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -73,7 +73,7 @@ StmtResult Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
MaybeParseGNUAttributes(GNUOrMSAttrs);
if (getLangOpts().HLSL)
- MaybeParseMicrosoftAttributes(GNUOrMSAttrs);
+ MaybeParseMicrosoftAttributes(GNUOrMSAttrs, /*IsStmtContext=*/true);
StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs, GNUOrMSAttrs,
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index bd239adb0f215..cfca5ca715033 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -10728,6 +10728,41 @@ void SemaCodeCompletion::GatherGlobalCodeCompletions(
Builder.data() + Builder.size());
}
+void SemaCodeCompletion::CodeCompleteHLSLAttributes(
+ llvm::ArrayRef<AttributeCommonInfo::Syntax> Syntaxes,
+ std::optional<ParsedAttr::Kind> RestrictToKind, bool RequireStmt,
+ std::optional<ParsedAttr::Kind> ExcludeKind) {
+ ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(),
+ CodeCompletionContext::CCC_Attribute);
+
+ for (const auto *A : ParsedAttrInfo::getAllBuiltin()) {
+ if (!A->acceptsLangOpts(getLangOpts()))
+ continue;
+ if (RestrictToKind && A->AttrKind != *RestrictToKind)
+ continue;
+ if (ExcludeKind && A->AttrKind == *ExcludeKind)
+ continue;
+ if (A->IsStmt != RequireStmt)
+ continue;
+
+ for (const auto &S : A->Spellings) {
+ if (!llvm::is_contained(Syntaxes, S.Syntax))
+ continue;
+
+ CodeCompletionBuilder CCB(Results.getAllocator(),
+ Results.getCodeCompletionTUInfo());
+ CCB.AddTypedTextChunk(
+ Results.getAllocator().CopyString(S.NormalizedFullName));
+ Results.AddResult(CodeCompletionResult(CCB.TakeString(), CCP_Keyword));
+ }
+ }
+
+ HandleCodeCompleteResults(&SemaRef, CodeCompleter,
+ Results.getCompletionContext(), Results.data(),
+ Results.size());
+}
+
SemaCodeCompletion::SemaCodeCompletion(Sema &S,
CodeCompleteConsumer *CompletionConsumer)
: SemaBase(S), CodeCompleter(CompletionConsumer),
``````````
</details>
https://github.com/llvm/llvm-project/pull/215353
More information about the cfe-commits
mailing list