[clang] [clang-tools-extra] [clangd][HLSL] Separate statement and declaration attributes code complete in [...] (PR #215353)
Maria Fernanda GuimarĂ£es via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 10 10:57:13 PDT 2026
https://github.com/mafeguimaraes updated https://github.com/llvm/llvm-project/pull/215353
>From ac4a386cff88e9e131b4ae3df9f25a7b218be382 Mon Sep 17 00:00:00 2001
From: Maria Fernanda Guimaraes <mariafefe201 at gmail.com>
Date: Mon, 10 Aug 2026 17:18:01 +0000
Subject: [PATCH 1/2] Separate statement and declaration attributes in [...]
---
clang/include/clang/Parse/Parser.h | 6 +--
clang/include/clang/Sema/SemaCodeCompletion.h | 5 +++
clang/lib/Parse/ParseDeclCXX.cpp | 17 ++++++---
clang/lib/Parse/ParseStmt.cpp | 2 +-
clang/lib/Sema/SemaCodeComplete.cpp | 37 +++++++++++++++++++
5 files changed, 58 insertions(+), 9 deletions(-)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 163aa483a84e3..19a1c0a90ad8c 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2337,12 +2337,12 @@ 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 +3133,7 @@ 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..08c5d4998bedc 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -4921,7 +4921,7 @@ 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 +4937,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..3cfbb2b746106 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -10728,6 +10728,43 @@ 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),
>From 76e3e4cb2c85f420207cd583a9e6fb23a9f1709b Mon Sep 17 00:00:00 2001
From: Maria Fernanda Guimaraes <mariafefe201 at gmail.com>
Date: Mon, 10 Aug 2026 17:39:05 +0000
Subject: [PATCH 2/2] Add tests for bracket attribute code completion
---
.../clangd/unittests/CodeCompleteTests.cpp | 49 +++++++++++++++++++
clang/include/clang/Parse/Parser.h | 6 ++-
clang/lib/Parse/ParseDeclCXX.cpp | 11 +++--
clang/lib/Sema/SemaCodeComplete.cpp | 4 +-
4 files changed, 60 insertions(+), 10 deletions(-)
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 19a1c0a90ad8c..b7a311fd9fc6f 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2337,7 +2337,8 @@ class Parser : public CodeCompletionHandler {
return false;
}
- bool MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs, bool IsStmtContext = false) {
+ bool MaybeParseMicrosoftAttributes(ParsedAttributes &Attrs,
+ bool IsStmtContext = false) {
bool AttrsParsed = false;
if ((getLangOpts().MicrosoftExt || getLangOpts().HLSL) &&
Tok.is(tok::l_square)) {
@@ -3133,7 +3134,8 @@ class Parser : public CodeCompletionHandler {
/// ms-attribute[opt]
/// ms-attribute ms-attribute-seq
/// \endverbatim
- void ParseMicrosoftAttributes(ParsedAttributes &Attrs, bool IsStmtContext = false);
+ void ParseMicrosoftAttributes(ParsedAttributes &Attrs,
+ bool IsStmtContext = false);
void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs);
void ParseNullabilityClassAttributes(ParsedAttributes &attrs);
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 08c5d4998bedc..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, bool IsStmtContext) {
+void Parser::ParseMicrosoftAttributes(ParsedAttributes &Attrs,
+ bool IsStmtContext) {
assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list");
SourceLocation StartLoc = Tok.getLocation();
@@ -4943,11 +4944,11 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &Attrs, bool IsStmtContex
/*RequireStmt=*/IsStmtContext,
/*ExcludeKind=*/ParsedAttr::AT_HLSLParsedSemantic);
} else {
- Actions.CodeCompletion().CodeCompleteAttribute(
- AttributeCommonInfo::AS_Microsoft,
- SemaCodeCompletion::AttributeCompletion::Attribute,
+ 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/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 3cfbb2b746106..cfca5ca715033 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -10730,8 +10730,7 @@ void SemaCodeCompletion::GatherGlobalCodeCompletions(
void SemaCodeCompletion::CodeCompleteHLSLAttributes(
llvm::ArrayRef<AttributeCommonInfo::Syntax> Syntaxes,
- std::optional<ParsedAttr::Kind> RestrictToKind,
- bool RequireStmt,
+ std::optional<ParsedAttr::Kind> RestrictToKind, bool RequireStmt,
std::optional<ParsedAttr::Kind> ExcludeKind) {
ResultBuilder Results(SemaRef, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
@@ -10764,7 +10763,6 @@ void SemaCodeCompletion::CodeCompleteHLSLAttributes(
Results.size());
}
-
SemaCodeCompletion::SemaCodeCompletion(Sema &S,
CodeCompleteConsumer *CompletionConsumer)
: SemaBase(S), CodeCompleter(CompletionConsumer),
More information about the cfe-commits
mailing list