[clang-tools-extra] [clangd] Add designator hints for parenthesis aggregate initialization (PR #170642)
Mythreya Kuricheti via cfe-commits
cfe-commits at lists.llvm.org
Fri Dec 5 23:35:58 PST 2025
https://github.com/MythreyaK updated https://github.com/llvm/llvm-project/pull/170642
>From 64e2e838413b55262ab5cb925b80c69968b3c844 Mon Sep 17 00:00:00 2001
From: Mythreya <git at mythreya.dev>
Date: Wed, 3 Dec 2025 21:41:40 -0800
Subject: [PATCH 1/3] Enable designator hints test
---
.../clangd/unittests/InlayHintTests.cpp | 27 +++++++++----------
1 file changed, 13 insertions(+), 14 deletions(-)
diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index feb4404b3d2bf..204c022851017 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1147,20 +1147,6 @@ TEST(ParameterHints, CopyOrMoveConstructor) {
)cpp");
}
-TEST(ParameterHints, AggregateInit) {
- // FIXME: This is not implemented yet, but it would be a natural
- // extension to show member names as hints here.
- assertParameterHints(R"cpp(
- struct Point {
- int x;
- int y;
- };
- void bar() {
- Point p{41, 42};
- }
- )cpp");
-}
-
TEST(ParameterHints, UserDefinedLiteral) {
// Do not hint call to user-defined literal operator.
assertParameterHints(R"cpp(
@@ -1746,6 +1732,19 @@ TEST(TypeHints, SubstTemplateParameterAliases) {
}
TEST(DesignatorHints, Basic) {
+ assertDesignatorHints(R"cpp(
+ struct Point {
+ int x;
+ int y;
+ };
+ void bar() {
+ Point p{$x[[41]], $y[[42]]};
+ }
+ )cpp",
+ ExpectedHint{".x=", "x"}, ExpectedHint{".y=", "y"});
+}
+
+TEST(DesignatorHints, BasicArray) {
assertDesignatorHints(R"cpp(
struct S { int x, y, z; };
S s {$x[[1]], $y[[2+2]]};
>From 50042b1b71d30f5eb4fca21d87a0ae4164f5c90b Mon Sep 17 00:00:00 2001
From: Mythreya <git at mythreya.dev>
Date: Wed, 3 Dec 2025 23:49:16 -0800
Subject: [PATCH 2/3] [clangd] Add designator hints for parenthesis aggregate
initialization
---
clang-tools-extra/clangd/InlayHints.cpp | 20 +++++++++++++++++++
.../clangd/unittests/InlayHintTests.cpp | 13 ++++++++++++
2 files changed, 33 insertions(+)
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 23bd02304a4fd..edd7b2d38e90c 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -699,6 +699,26 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
return InstantiatedFunction->getParamDecl(ParamIdx);
}
+ bool VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
+ // TODO: Lang check needed?
+ if (!Cfg.InlayHints.Designators &&
+ AST.getLangOpts().LangStd >= LangStandard::Kind::lang_cxx20)
+ return true;
+
+ if (const auto *CXXRecord = E->getType()->getAsCXXRecordDecl()) {
+ const auto &InitExprs = E->getInitExprs();
+ auto RecordFields = CXXRecord->fields().begin();
+
+ for (size_t I = 0; I < InitExprs.size();
+ ++I, RecordFields = std::next(RecordFields)) {
+ // TODO: is prepending "." sufficient?
+ addDesignatorHint(InitExprs[I]->getSourceRange(),
+ "." + RecordFields->getName().str());
+ }
+ }
+ return true;
+ }
+
bool VisitInitListExpr(InitListExpr *Syn) {
// We receive the syntactic form here (shouldVisitImplicitCode() is false).
// This is the one we will ultimately attach designators to.
diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index 204c022851017..72e7be2f3d943 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1821,6 +1821,19 @@ TEST(DesignatorHints, NoCrash) {
ExpectedHint{".b=", "b"});
}
+TEST(DesignatorHints, BasicParenInit) {
+ assertDesignatorHints(R"cpp(
+ struct S {
+ int x;
+ int y;
+ int z;
+ };
+ S s ($x[[1]], $y[[2+2]], $z[[4]]);
+ )cpp",
+ ExpectedHint{".x=", "x"}, ExpectedHint{".y=", "y"},
+ ExpectedHint{".z=", "z"});
+}
+
TEST(InlayHints, RestrictRange) {
Annotations Code(R"cpp(
auto a = false;
>From 44c272043ae470cc4213e18e96e5c38ad31ffb5e Mon Sep 17 00:00:00 2001
From: Mythreya <git at mythreya.dev>
Date: Fri, 5 Dec 2025 23:28:53 -0800
Subject: [PATCH 3/3] code-review
---
clang-tools-extra/clangd/InlayHints.cpp | 24 +++++++++++++------
.../clangd/unittests/InlayHintTests.cpp | 18 ++++++++++++++
2 files changed, 35 insertions(+), 7 deletions(-)
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index edd7b2d38e90c..9476fe9deea57 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -700,22 +700,32 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
}
bool VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
- // TODO: Lang check needed?
- if (!Cfg.InlayHints.Designators &&
- AST.getLangOpts().LangStd >= LangStandard::Kind::lang_cxx20)
+ if (!Cfg.InlayHints.Designators)
return true;
if (const auto *CXXRecord = E->getType()->getAsCXXRecordDecl()) {
const auto &InitExprs = E->getInitExprs();
+ size_t InitInx = 0;
+
+ // Inherited members are first
+ for (const auto &Base : CXXRecord->bases()) {
+ std::ignore = Base;
+ // For a base record, just use its name
+ // Base of base requires its own initialization; ParenListInitExpr or
+ // InitListExpr will be invoked separately for them
+ InitInx++;
+ }
+
+ // Then the members defined in this record
auto RecordFields = CXXRecord->fields().begin();
- for (size_t I = 0; I < InitExprs.size();
- ++I, RecordFields = std::next(RecordFields)) {
- // TODO: is prepending "." sufficient?
- addDesignatorHint(InitExprs[I]->getSourceRange(),
+ for (; InitInx < InitExprs.size();
+ ++InitInx, RecordFields = std::next(RecordFields)) {
+ addDesignatorHint(InitExprs[InitInx]->getSourceRange(),
"." + RecordFields->getName().str());
}
}
+
return true;
}
diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index 72e7be2f3d943..afa67c336b867 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1834,6 +1834,24 @@ TEST(DesignatorHints, BasicParenInit) {
ExpectedHint{".z=", "z"});
}
+TEST(DesignatorHints, BasicParenInitDerived) {
+ assertDesignatorHints(R"cpp(
+ struct S1 {
+ int a;
+ int b;
+ };
+
+ struct S2 : S1 {
+ int c;
+ int d;
+ };
+ S2 s2 ({$a[[0]], $b[[0]]}, $c[[0]], $d[[0]]);
+ )cpp",
+ // ExpectedHint{"S1:", "S1"},
+ ExpectedHint{".a=", "a"}, ExpectedHint{".b=", "b"},
+ ExpectedHint{".c=", "c"}, ExpectedHint{".d=", "d"});
+}
+
TEST(InlayHints, RestrictRange) {
Annotations Code(R"cpp(
auto a = false;
More information about the cfe-commits
mailing list