diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index 23bd02304a4fd..2290fbd98056d 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -699,6 +699,32 @@ class InlayHintVisitor : public RecursiveASTVisitor { return InstantiatedFunction->getParamDecl(ParamIdx); } + bool VisitCXXParenListInitExpr(CXXParenListInitExpr *E) { + if (!Cfg.InlayHints.Designators) + return true; + + if (const auto *CXXRecord = E->getType()->getAsCXXRecordDecl()) { + const auto &InitExprs = E->getUserSpecifiedInitExprs(); + + if (InitExprs.size() <= CXXRecord->getNumBases()) + return true; + + // Inherited members are first, skip hinting them for now. + // FIXME: '.base=' or 'base:' hint? + const auto &MemberInitExprs = + InitExprs.drop_front(CXXRecord->getNumBases()); + + // Then the fields in this record + for (const auto &[InitExpr, Field] : + llvm::zip(MemberInitExprs, CXXRecord->fields())) { + addDesignatorHint(InitExpr->getSourceRange(), + "." + Field->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 feb4404b3d2bf..d54e36c2f8a3b 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]]}; @@ -1822,6 +1821,63 @@ 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(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(DesignatorHints, BasicParenInitTemplate) { + assertDesignatorHints(R"cpp( + template + struct S1 { + int a; + int b; + T* ptr; + }; + + struct S2 : S1 { + int c; + int d; + S1 mem; + }; + + int main() { + S2 sa ({$a1[[0]], $b1[[0]]}, $c[[0]], $d[[0]], $mem[[S1($a2[[1]], $b2[[2]], $ptr[[nullptr]])]]); + } + )cpp", + ExpectedHint{".a=", "a1"}, ExpectedHint{".b=", "b1"}, + ExpectedHint{".c=", "c"}, ExpectedHint{".d=", "d"}, + ExpectedHint{".mem=", "mem"}, ExpectedHint{".a=", "a2"}, + ExpectedHint{".b=", "b2"}, + ExpectedHint{".ptr=", "ptr"}); +} + TEST(InlayHints, RestrictRange) { Annotations Code(R"cpp( auto a = false;