[clang] [clang-tools-extra] [clang-tidy] Add new check `modernize-use-designated-initializers` (PR #80541)

Danny Mösch via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 22 00:03:13 PST 2024


https://github.com/SimplyDanny updated https://github.com/llvm/llvm-project/pull/80541

>From e73428a55761223fe8b663e750be5674941bf227 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 13:13:50 +0100
Subject: [PATCH 01/62] Trigger on variable declarations

---
 .../clang-tidy/modernize/CMakeLists.txt       |  1 +
 .../modernize/ModernizeTidyModule.cpp         |  3 +
 .../UseDesignatedInitializersCheck.cpp        | 58 +++++++++++++++++++
 .../UseDesignatedInitializersCheck.h          | 33 +++++++++++
 clang-tools-extra/docs/ReleaseNotes.rst       |  4 ++
 .../docs/clang-tidy/checks/list.rst           |  1 +
 .../modernize/use-designated-initializers.rst |  6 ++
 .../modernize/use-designated-initializers.cpp | 32 ++++++++++
 8 files changed, 138 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 28ca52f46943a8..6852db6c2ee311 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -31,6 +31,7 @@ add_clang_library(clangTidyModernizeModule
   UseBoolLiteralsCheck.cpp
   UseConstraintsCheck.cpp
   UseDefaultMemberInitCheck.cpp
+  UseDesignatedInitializersCheck.cpp
   UseEmplaceCheck.cpp
   UseEqualsDefaultCheck.cpp
   UseEqualsDeleteCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 654f4bd0c6ba47..e96cf274f58cfe 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -32,6 +32,7 @@
 #include "UseBoolLiteralsCheck.h"
 #include "UseConstraintsCheck.h"
 #include "UseDefaultMemberInitCheck.h"
+#include "UseDesignatedInitializersCheck.h"
 #include "UseEmplaceCheck.h"
 #include "UseEqualsDefaultCheck.h"
 #include "UseEqualsDeleteCheck.h"
@@ -68,6 +69,8 @@ class ModernizeModule : public ClangTidyModule {
     CheckFactories.registerCheck<MakeSharedCheck>("modernize-make-shared");
     CheckFactories.registerCheck<MakeUniqueCheck>("modernize-make-unique");
     CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
+    CheckFactories.registerCheck<UseDesignatedInitializersCheck>(
+        "modernize-use-designated-initializers");
     CheckFactories.registerCheck<UseStartsEndsWithCheck>(
         "modernize-use-starts-ends-with");
     CheckFactories.registerCheck<UseStdNumbersCheck>(
diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
new file mode 100644
index 00000000000000..06f0bb0dc06eac
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -0,0 +1,58 @@
+//===--- UseDesignatedInitializersCheck.cpp - clang-tidy ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseDesignatedInitializersCheck.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+static std::vector<Stmt *>
+getAllUndesignatedInits(const InitListExpr *SyntacticInitList) {
+  std::vector<Stmt *> Result;
+  std::copy_if(SyntacticInitList->begin(), SyntacticInitList->end(),
+               std::back_inserter(Result),
+               [](auto S) { return !isa<DesignatedInitExpr>(S); });
+  return Result;
+}
+
+void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(varDecl(allOf(has(initListExpr().bind("init")),
+                                   hasType(recordDecl().bind("type")))),
+                     this);
+}
+
+void UseDesignatedInitializersCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *InitList = Result.Nodes.getNodeAs<InitListExpr>("init");
+  const auto *Type = Result.Nodes.getNodeAs<CXXRecordDecl>("type");
+  if (!Type || !InitList || !Type->isAggregate())
+    return;
+  if (const auto *SyntacticInitList = InitList->getSyntacticForm()) {
+    const auto UndesignatedParts = getAllUndesignatedInits(SyntacticInitList);
+    if (UndesignatedParts.empty())
+      return;
+    if (UndesignatedParts.size() == SyntacticInitList->getNumInits()) {
+      diag(InitList->getLBraceLoc(), "use designated initializer list");
+      return;
+    }
+    for (const auto *InitExpr : UndesignatedParts) {
+      diag(InitExpr->getBeginLoc(), "use designated init expression");
+    }
+  }
+}
+
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
new file mode 100644
index 00000000000000..aeaa3f19deb7e8
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
@@ -0,0 +1,33 @@
+//===--- UseDesignatedInitializersCheck.h - clang-tidy ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEDESIGNATEDINITIALIZERSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEDESIGNATEDINITIALIZERSCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::modernize {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-designated-initializers.html
+class UseDesignatedInitializersCheck : public ClangTidyCheck {
+public:
+  UseDesignatedInitializersCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEDESIGNATEDINITIALIZERSCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a0b9fcfe0d7774..e6104b1979ac07 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -105,6 +105,10 @@ New checks
 
   Replaces certain conditional statements with equivalent calls to
   ``std::min`` or ``std::max``.
+- New :doc:`modernize-use-designated-initializers
+  <clang-tidy/checks/modernize/use-designated-initializers>` check.
+
+  FIXME: add release notes.
 
 New check aliases
 ^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 59ef69f390ee91..5e57bc0ee483fe 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -287,6 +287,7 @@ Clang-Tidy Checks
    :doc:`modernize-use-bool-literals <modernize/use-bool-literals>`, "Yes"
    :doc:`modernize-use-constraints <modernize/use-constraints>`, "Yes"
    :doc:`modernize-use-default-member-init <modernize/use-default-member-init>`, "Yes"
+   :doc:`modernize-use-designated-initializers <modernize/use-designated-initializers>`, "Yes"
    :doc:`modernize-use-emplace <modernize/use-emplace>`, "Yes"
    :doc:`modernize-use-equals-default <modernize/use-equals-default>`, "Yes"
    :doc:`modernize-use-equals-delete <modernize/use-equals-delete>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
new file mode 100644
index 00000000000000..e0487f9b0e843d
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
@@ -0,0 +1,6 @@
+.. title:: clang-tidy - modernize-use-designated-initializers
+
+modernize-use-designated-initializers
+=====================================
+
+FIXME: Describe what patterns does the check detect and why. Give examples.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
new file mode 100644
index 00000000000000..c945454201ee13
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -0,0 +1,32 @@
+// RUN: %check_clang_tidy %s modernize-use-designated-initializers %t
+
+struct S1 {};
+
+S1 s11{};
+S1 s12 = {};
+S1 s13();
+S1 s14;
+
+struct S2 { int i, j; };
+
+S2 s21{.i=1, .j =2};
+
+S2 s22 = {1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+
+S2 s23{1};
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
+
+S2 s24{.i = 1};
+
+S2 s25 = {.i=1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use designated init expression [modernize-use-designated-initializers]
+
+struct S3 {
+    S2 s2;
+    double d;
+};
+
+S3 s31 = {.s2 = 1, 2, 3.1};
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use designated init expression [modernize-use-designated-initializers]

>From 808728e68cda7fa5259ef0b477e6bd7daf929dd0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 13:34:58 +0100
Subject: [PATCH 02/62] Support nested initializer lists

---
 .../modernize/UseDesignatedInitializersCheck.cpp     |  5 ++---
 .../modernize/use-designated-initializers.cpp        | 12 ++++++++++++
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 06f0bb0dc06eac..e0400db473db25 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -30,9 +30,8 @@ getAllUndesignatedInits(const InitListExpr *SyntacticInitList) {
 }
 
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(varDecl(allOf(has(initListExpr().bind("init")),
-                                   hasType(recordDecl().bind("type")))),
-                     this);
+  Finder->addMatcher(
+      initListExpr(hasType(recordDecl().bind("type"))).bind("init"), this);
 }
 
 void UseDesignatedInitializersCheck::check(
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index c945454201ee13..a5eeb5553a9093 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -30,3 +30,15 @@ struct S3 {
 S3 s31 = {.s2 = 1, 2, 3.1};
 // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use designated init expression [modernize-use-designated-initializers]
+
+S3 s32 = {{.i = 1, 2}};
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-2]]:20: warning: use designated init expression [modernize-use-designated-initializers]
+
+struct S4 {
+    double d;
+    private: static int i;
+};
+
+S4 s41 {2.2};
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]

>From 045ea4cd39377b425834866deae7429fb0272513 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 13:35:12 +0100
Subject: [PATCH 03/62] Rename

---
 .../modernize/UseDesignatedInitializersCheck.cpp      | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index e0400db473db25..7cf6dcb21ac1be 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -21,7 +21,7 @@ using namespace clang::ast_matchers;
 namespace clang::tidy::modernize {
 
 static std::vector<Stmt *>
-getAllUndesignatedInits(const InitListExpr *SyntacticInitList) {
+getUndesignatedComponents(const InitListExpr *SyntacticInitList) {
   std::vector<Stmt *> Result;
   std::copy_if(SyntacticInitList->begin(), SyntacticInitList->end(),
                std::back_inserter(Result),
@@ -41,14 +41,15 @@ void UseDesignatedInitializersCheck::check(
   if (!Type || !InitList || !Type->isAggregate())
     return;
   if (const auto *SyntacticInitList = InitList->getSyntacticForm()) {
-    const auto UndesignatedParts = getAllUndesignatedInits(SyntacticInitList);
-    if (UndesignatedParts.empty())
+    const auto UndesignatedComponents =
+        getUndesignatedComponents(SyntacticInitList);
+    if (UndesignatedComponents.empty())
       return;
-    if (UndesignatedParts.size() == SyntacticInitList->getNumInits()) {
+    if (UndesignatedComponents.size() == SyntacticInitList->getNumInits()) {
       diag(InitList->getLBraceLoc(), "use designated initializer list");
       return;
     }
-    for (const auto *InitExpr : UndesignatedParts) {
+    for (const auto *InitExpr : UndesignatedComponents) {
       diag(InitExpr->getBeginLoc(), "use designated init expression");
     }
   }

>From f540d40e49dd27a9142b79040009b3fc98ec6b7b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 13:36:10 +0100
Subject: [PATCH 04/62] Enable for C++20 only

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.h      | 3 +++
 .../checkers/modernize/use-designated-initializers.cpp         | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
index aeaa3f19deb7e8..12a9850ada6a14 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
@@ -26,6 +26,9 @@ class UseDesignatedInitializersCheck : public ClangTidyCheck {
   std::optional<TraversalKind> getCheckTraversalKind() const override {
     return TK_IgnoreUnlessSpelledInSource;
   }
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus20;
+  }
 };
 
 } // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index a5eeb5553a9093..7e41943e884061 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s modernize-use-designated-initializers %t
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-designated-initializers %t
 
 struct S1 {};
 

>From 150c8a7c443dc594a6adba9e6ee6324e570c507e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 13:56:08 +0100
Subject: [PATCH 05/62] Add option to ignore aggregates with single elements

---
 .../UseDesignatedInitializersCheck.cpp        | 19 +++++++++++++++++++
 .../UseDesignatedInitializersCheck.h          |  9 +++++++--
 .../modernize/use-designated-initializers.cpp |  5 ++++-
 3 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 7cf6dcb21ac1be..d269cef13e6aaa 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -20,6 +20,10 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::modernize {
 
+static constexpr auto IgnoreSingleElementAggregatesName =
+    "IgnoreSingleElementAggregates";
+static constexpr auto IgnoreSingleElementAggregatesDefault = true;
+
 static std::vector<Stmt *>
 getUndesignatedComponents(const InitListExpr *SyntacticInitList) {
   std::vector<Stmt *> Result;
@@ -29,6 +33,13 @@ getUndesignatedComponents(const InitListExpr *SyntacticInitList) {
   return Result;
 }
 
+UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      IgnoreSingleElementAggregates(
+          Options.getLocalOrGlobal(IgnoreSingleElementAggregatesName,
+                                   IgnoreSingleElementAggregatesDefault)) {}
+
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
       initListExpr(hasType(recordDecl().bind("type"))).bind("init"), this);
@@ -40,6 +51,8 @@ void UseDesignatedInitializersCheck::check(
   const auto *Type = Result.Nodes.getNodeAs<CXXRecordDecl>("type");
   if (!Type || !InitList || !Type->isAggregate())
     return;
+  if (IgnoreSingleElementAggregates && InitList->getNumInits() == 1)
+    return;
   if (const auto *SyntacticInitList = InitList->getSyntacticForm()) {
     const auto UndesignatedComponents =
         getUndesignatedComponents(SyntacticInitList);
@@ -55,4 +68,10 @@ void UseDesignatedInitializersCheck::check(
   }
 }
 
+void UseDesignatedInitializersCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, IgnoreSingleElementAggregatesName,
+                IgnoreSingleElementAggregates);
+}
+
 } // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
index 12a9850ada6a14..8a60fd7b31c5a4 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
@@ -19,16 +19,21 @@ namespace clang::tidy::modernize {
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-designated-initializers.html
 class UseDesignatedInitializersCheck : public ClangTidyCheck {
 public:
-  UseDesignatedInitializersCheck(StringRef Name, ClangTidyContext *Context)
-      : ClangTidyCheck(Name, Context) {}
+  UseDesignatedInitializersCheck(StringRef Name, ClangTidyContext *Context);
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
   std::optional<TraversalKind> getCheckTraversalKind() const override {
     return TK_IgnoreUnlessSpelledInSource;
   }
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
     return LangOpts.CPlusPlus20;
   }
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+  bool IgnoreSingleElementAggregates;
 };
 
 } // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 7e41943e884061..350ee03d581ae8 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -1,4 +1,7 @@
 // RUN: %check_clang_tidy -std=c++20 %s modernize-use-designated-initializers %t
+// RUN: %check_clang_tidy -check-suffixes=,SINGLE-ELEMENT -std=c++20 %s modernize-use-designated-initializers %t \
+// RUN:     -- -config="{CheckOptions: [{key: modernize-use-designated-initializers.IgnoreSingleElementAggregates, value: false}]}" \
+// RUN:     --
 
 struct S1 {};
 
@@ -41,4 +44,4 @@ struct S4 {
 };
 
 S4 s41 {2.2};
-// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]

>From 02306cec7f0a11b57fb7f4862e99cf519c6cef71 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 14:06:17 +0100
Subject: [PATCH 06/62] Test class

---
 .../checkers/modernize/use-designated-initializers.cpp         | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 350ee03d581ae8..d932e2d5e4863b 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -25,7 +25,8 @@ S2 s24{.i = 1};
 S2 s25 = {.i=1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use designated init expression [modernize-use-designated-initializers]
 
-struct S3 {
+class S3 {
+  public:
     S2 s2;
     double d;
 };

>From 10e9f7e2924a331f8ee1b5cf9d1e22b1a646e3d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 14:22:56 +0100
Subject: [PATCH 07/62] Add documentation and release notes

---
 .../UseDesignatedInitializersCheck.h          |  3 +-
 clang-tools-extra/docs/ReleaseNotes.rst       |  3 +-
 .../modernize/use-designated-initializers.rst | 40 ++++++++++++++++++-
 3 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
index 8a60fd7b31c5a4..34290aba06fab1 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
@@ -13,7 +13,8 @@
 
 namespace clang::tidy::modernize {
 
-/// FIXME: Write a short description.
+/// Triggers on initializer lists for aggregate type that could be
+/// written as designated initializers instead.
 ///
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-designated-initializers.html
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index e6104b1979ac07..6312bcd86d2d7e 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -108,7 +108,8 @@ New checks
 - New :doc:`modernize-use-designated-initializers
   <clang-tidy/checks/modernize/use-designated-initializers>` check.
 
-  FIXME: add release notes.
+  Triggers on initializer lists for aggregate type that could be
+  written as designated initializers instead.
 
 New check aliases
 ^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
index e0487f9b0e843d..1e182218dbd8eb 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
@@ -3,4 +3,42 @@
 modernize-use-designated-initializers
 =====================================
 
-FIXME: Describe what patterns does the check detect and why. Give examples.
+Triggers on initializer lists for aggregate type that could be written as
+designated initializers instead.
+
+With plain initializer lists, it is very easy to introduce bugs when adding
+new fields in the middle of a struct or class type. The same confusion might
+arise when changing the order of fields.
+
+C++ 20 supports the designated initializer syntax for aggregate types.
+By applying it, we can always be sure that aggregates are constructed correctly,
+because the every variable being initialized is referenced by name.
+
+Example:
+
+.. code-block::
+
+    struct S { int i, j; };
+
+is an aggregate type that should be initialized as
+
+.. code-block::
+
+    S s{.i = 1, .j = 2};
+
+instead of
+
+.. code-block::
+
+    S s{1, 2};
+
+which could easily become an issue when ``i`` and ``j`` are swapped in the
+declaration of ``S``.
+
+Options
+-------
+
+.. options:: IgnoreSingleElementAggregates
+
+    The value `false` specifies that even initializers for aggregate types
+    with only a single element should be checked. The default value is `true`.

>From cce574141d53de2949805b22d7ef30336c2220e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 14:31:30 +0100
Subject: [PATCH 08/62] Fix typo

---
 .../clang-tidy/checks/modernize/use-designated-initializers.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
index 1e182218dbd8eb..27474921a53d5e 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
@@ -38,7 +38,7 @@ declaration of ``S``.
 Options
 -------
 
-.. options:: IgnoreSingleElementAggregates
+.. option:: IgnoreSingleElementAggregates
 
     The value `false` specifies that even initializers for aggregate types
     with only a single element should be checked. The default value is `true`.

>From 8711b1b1872c416c17603ffef9a95dd56253ad39 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 17:24:32 +0100
Subject: [PATCH 09/62] Specify explicit type

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index d269cef13e6aaa..7b23a2e8a09308 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -20,9 +20,9 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::modernize {
 
-static constexpr auto IgnoreSingleElementAggregatesName =
+static const char *IgnoreSingleElementAggregatesName =
     "IgnoreSingleElementAggregates";
-static constexpr auto IgnoreSingleElementAggregatesDefault = true;
+static const bool IgnoreSingleElementAggregatesDefault = true;
 
 static std::vector<Stmt *>
 getUndesignatedComponents(const InitListExpr *SyntacticInitList) {

>From e3bf4092adad80287bb5f2613bdd2d7042d47eef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 17:24:44 +0100
Subject: [PATCH 10/62] Get only local option

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 7b23a2e8a09308..0594f3dfb10306 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -37,8 +37,8 @@ UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
     StringRef Name, ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
       IgnoreSingleElementAggregates(
-          Options.getLocalOrGlobal(IgnoreSingleElementAggregatesName,
-                                   IgnoreSingleElementAggregatesDefault)) {}
+          Options.get(IgnoreSingleElementAggregatesName,
+                      IgnoreSingleElementAggregatesDefault)) {}
 
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(

>From 9251fbf1c687d37dc56d25a7a2c4eca3ac877be0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 17:25:03 +0100
Subject: [PATCH 11/62] Improve check description

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.h       | 2 +-
 clang-tools-extra/docs/ReleaseNotes.rst                         | 2 +-
 .../clang-tidy/checks/modernize/use-designated-initializers.rst | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
index 34290aba06fab1..de06250b0d3d06 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
@@ -13,7 +13,7 @@
 
 namespace clang::tidy::modernize {
 
-/// Triggers on initializer lists for aggregate type that could be
+/// Finds initializer lists for aggregate type that could be
 /// written as designated initializers instead.
 ///
 /// For the user-facing documentation see:
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 6312bcd86d2d7e..8779ada257bd37 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -108,7 +108,7 @@ New checks
 - New :doc:`modernize-use-designated-initializers
   <clang-tidy/checks/modernize/use-designated-initializers>` check.
 
-  Triggers on initializer lists for aggregate type that could be
+  Finds initializer lists for aggregate type that could be
   written as designated initializers instead.
 
 New check aliases
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
index 27474921a53d5e..0f313eec2b1990 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
@@ -3,7 +3,7 @@
 modernize-use-designated-initializers
 =====================================
 
-Triggers on initializer lists for aggregate type that could be written as
+Finds initializer lists for aggregate type that could be written as
 designated initializers instead.
 
 With plain initializer lists, it is very easy to introduce bugs when adding

>From 3b5b9dfd0394ff2157a7c1e2572b8fa6c08997c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 18:25:29 +0100
Subject: [PATCH 12/62] Move logic into matcher

---
 .../UseDesignatedInitializersCheck.cpp        | 21 +++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 0594f3dfb10306..28567e6609fdd3 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -12,6 +12,7 @@
 #include "clang/AST/Stmt.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
 #include <algorithm>
 #include <iterator>
 #include <vector>
@@ -40,24 +41,32 @@ UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
           Options.get(IgnoreSingleElementAggregatesName,
                       IgnoreSingleElementAggregatesDefault)) {}
 
+AST_MATCHER(CXXRecordDecl, isAggregate) { return Node.isAggregate(); }
+
+AST_MATCHER(InitListExpr, isFullyDesignated) {
+  return getUndesignatedComponents(&Node).empty();
+}
+
+AST_MATCHER(InitListExpr, hasSingleElement) { return Node.getNumInits() == 1; }
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
-      initListExpr(hasType(recordDecl().bind("type"))).bind("init"), this);
+      initListExpr(hasType(cxxRecordDecl(isAggregate()).bind("type")),
+                   unless(IgnoreSingleElementAggregates ? hasSingleElement()
+                                                        : unless(anything())),
+                   unless(isFullyDesignated()))
+          .bind("init"),
+      this);
 }
 
 void UseDesignatedInitializersCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *InitList = Result.Nodes.getNodeAs<InitListExpr>("init");
   const auto *Type = Result.Nodes.getNodeAs<CXXRecordDecl>("type");
-  if (!Type || !InitList || !Type->isAggregate())
-    return;
-  if (IgnoreSingleElementAggregates && InitList->getNumInits() == 1)
+  if (!Type || !InitList)
     return;
   if (const auto *SyntacticInitList = InitList->getSyntacticForm()) {
     const auto UndesignatedComponents =
         getUndesignatedComponents(SyntacticInitList);
-    if (UndesignatedComponents.empty())
-      return;
     if (UndesignatedComponents.size() == SyntacticInitList->getNumInits()) {
       diag(InitList->getLBraceLoc(), "use designated initializer list");
       return;

>From 5e48047360d2e694544ac57344d665224f764684 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 3 Feb 2024 18:40:45 +0100
Subject: [PATCH 13/62] Add template test

---
 .../modernize/use-designated-initializers.cpp         | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index d932e2d5e4863b..b6f0c3758163d6 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -46,3 +46,14 @@ struct S4 {
 
 S4 s41 {2.2};
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+
+S4 s42 = {{}};
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+
+template<typename S> S template1() { return {10, 11}; }
+
+S2 s26 = template1<S2>();
+
+template<typename S> S template2() { return {}; }
+
+S2 s27 = template2<S2>();

>From ca1efce5056d4a65eb069d24a89a3cb80c99b371 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sun, 4 Feb 2024 11:50:12 +0100
Subject: [PATCH 14/62] Ignore types inheriting fields

---
 .../modernize/UseDesignatedInitializersCheck.cpp  | 15 +++++++++++----
 .../modernize/use-designated-initializers.cpp     |  4 ++++
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 28567e6609fdd3..62f2b59241dd70 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -48,12 +48,19 @@ AST_MATCHER(InitListExpr, isFullyDesignated) {
 }
 
 AST_MATCHER(InitListExpr, hasSingleElement) { return Node.getNumInits() == 1; }
+
+AST_MATCHER_FUNCTION(::internal::Matcher<CXXRecordDecl>, hasBaseWithFields) {
+  return hasAnyBase(hasType(cxxRecordDecl(has(fieldDecl()))));
+}
+
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
-      initListExpr(hasType(cxxRecordDecl(isAggregate()).bind("type")),
-                   unless(IgnoreSingleElementAggregates ? hasSingleElement()
-                                                        : unless(anything())),
-                   unless(isFullyDesignated()))
+      initListExpr(
+          hasType(cxxRecordDecl(isAggregate(), unless(hasBaseWithFields()))
+                      .bind("type")),
+          unless(IgnoreSingleElementAggregates ? hasSingleElement()
+                                               : unless(anything())),
+          unless(isFullyDesignated()))
           .bind("init"),
       this);
 }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index b6f0c3758163d6..0a4a098a7737be 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -57,3 +57,7 @@ S2 s26 = template1<S2>();
 template<typename S> S template2() { return {}; }
 
 S2 s27 = template2<S2>();
+
+struct S5: S2 { int x, y; };
+
+S5 s51 {1, 2, .x = 3, .y = 4};

>From e50e1448066f74cc04120a86ce41f2028adc1fcf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sun, 4 Feb 2024 13:21:26 +0100
Subject: [PATCH 15/62] Ignore types with anonymous fields

---
 .../UseDesignatedInitializersCheck.cpp        | 12 ++++++++++-
 .../modernize/use-designated-initializers.cpp | 20 +++++++++++++++++++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 62f2b59241dd70..84fb59e5a76397 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "UseDesignatedInitializersCheck.h"
+#include "clang/AST/APValue.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/Stmt.h"
@@ -53,10 +54,19 @@ AST_MATCHER_FUNCTION(::internal::Matcher<CXXRecordDecl>, hasBaseWithFields) {
   return hasAnyBase(hasType(cxxRecordDecl(has(fieldDecl()))));
 }
 
+AST_MATCHER(FieldDecl, isAnonymousDecl) {
+  if (const auto *Record =
+          Node.getType().getCanonicalType()->getAsRecordDecl()) {
+    return Record->isAnonymousStructOrUnion() || !Record->getIdentifier();
+  }
+  return false;
+}
+
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
       initListExpr(
-          hasType(cxxRecordDecl(isAggregate(), unless(hasBaseWithFields()))
+          hasType(cxxRecordDecl(isAggregate(), unless(hasBaseWithFields()),
+                                unless(has(fieldDecl(isAnonymousDecl()))))
                       .bind("type")),
           unless(IgnoreSingleElementAggregates ? hasSingleElement()
                                                : unless(anything())),
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 0a4a098a7737be..46859435c588e4 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -61,3 +61,23 @@ S2 s27 = template2<S2>();
 struct S5: S2 { int x, y; };
 
 S5 s51 {1, 2, .x = 3, .y = 4};
+
+struct S6 {
+    int i;
+    struct { int j; } s;
+};
+
+S6 s61 {1, 2};
+
+struct S7 {
+    union {
+        int k;
+        double d;
+    } u;
+};
+
+S7 s71 {1};
+
+struct S8: S7 { int i; };
+
+S8 s81{1, 2};

>From b669414f9c2946fd8c4177fc5783462a15447c54 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sun, 4 Feb 2024 13:29:52 +0100
Subject: [PATCH 16/62] Remove restriction to C++ 20

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.h   | 3 ---
 .../checks/modernize/use-designated-initializers.rst        | 6 +++++-
 .../checkers/modernize/use-designated-initializers.cpp      | 4 ++--
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
index de06250b0d3d06..54dca26c6d735a 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
@@ -28,9 +28,6 @@ class UseDesignatedInitializersCheck : public ClangTidyCheck {
   std::optional<TraversalKind> getCheckTraversalKind() const override {
     return TK_IgnoreUnlessSpelledInSource;
   }
-  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    return LangOpts.CPlusPlus20;
-  }
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
 
 private:
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
index 0f313eec2b1990..105daf2c50ef2e 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
@@ -12,7 +12,11 @@ arise when changing the order of fields.
 
 C++ 20 supports the designated initializer syntax for aggregate types.
 By applying it, we can always be sure that aggregates are constructed correctly,
-because the every variable being initialized is referenced by name.
+because every variable being initialized is referenced by name.
+
+Even when compiling in a language version older than C++ 20, depending on you compiler,
+designated initializers are potentially supported. Therefore, the check is not restricted
+to C++ 20 and older.
 
 Example:
 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 46859435c588e4..9780bf7f0080d0 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -1,5 +1,5 @@
-// RUN: %check_clang_tidy -std=c++20 %s modernize-use-designated-initializers %t
-// RUN: %check_clang_tidy -check-suffixes=,SINGLE-ELEMENT -std=c++20 %s modernize-use-designated-initializers %t \
+// RUN: %check_clang_tidy -std=c++17 %s modernize-use-designated-initializers %t
+// RUN: %check_clang_tidy -check-suffixes=,SINGLE-ELEMENT -std=c++17 %s modernize-use-designated-initializers %t \
 // RUN:     -- -config="{CheckOptions: [{key: modernize-use-designated-initializers.IgnoreSingleElementAggregates, value: false}]}" \
 // RUN:     --
 

>From 64e5fc11b1dfe4516ff43214bb4089a872fc4683 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sun, 4 Feb 2024 14:05:31 +0100
Subject: [PATCH 17/62] Add option to restrict check to POD types

---
 .../UseDesignatedInitializersCheck.cpp         | 18 +++++++++++++-----
 .../modernize/UseDesignatedInitializersCheck.h |  1 +
 .../modernize/use-designated-initializers.rst  |  6 ++++++
 .../modernize/use-designated-initializers.cpp  | 18 ++++++++++++++++++
 4 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 84fb59e5a76397..b1b44289111c7a 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -26,6 +26,9 @@ static const char *IgnoreSingleElementAggregatesName =
     "IgnoreSingleElementAggregates";
 static const bool IgnoreSingleElementAggregatesDefault = true;
 
+static const char *RestrictToPODTypesName = "RestrictToPODTypes";
+static const bool RestrictToPODTypesDefault = false;
+
 static std::vector<Stmt *>
 getUndesignatedComponents(const InitListExpr *SyntacticInitList) {
   std::vector<Stmt *> Result;
@@ -37,13 +40,16 @@ getUndesignatedComponents(const InitListExpr *SyntacticInitList) {
 
 UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
     StringRef Name, ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context),
-      IgnoreSingleElementAggregates(
-          Options.get(IgnoreSingleElementAggregatesName,
-                      IgnoreSingleElementAggregatesDefault)) {}
+    : ClangTidyCheck(Name, Context), IgnoreSingleElementAggregates(Options.get(
+                                         IgnoreSingleElementAggregatesName,
+                                         IgnoreSingleElementAggregatesDefault)),
+      RestrictToPODTypes(
+          Options.get(RestrictToPODTypesName, RestrictToPODTypesDefault)) {}
 
 AST_MATCHER(CXXRecordDecl, isAggregate) { return Node.isAggregate(); }
 
+AST_MATCHER(CXXRecordDecl, isPOD) { return Node.isPOD(); }
+
 AST_MATCHER(InitListExpr, isFullyDesignated) {
   return getUndesignatedComponents(&Node).empty();
 }
@@ -65,7 +71,8 @@ AST_MATCHER(FieldDecl, isAnonymousDecl) {
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
       initListExpr(
-          hasType(cxxRecordDecl(isAggregate(), unless(hasBaseWithFields()),
+          hasType(cxxRecordDecl(RestrictToPODTypes ? isPOD() : isAggregate(),
+                                unless(hasBaseWithFields()),
                                 unless(has(fieldDecl(isAnonymousDecl()))))
                       .bind("type")),
           unless(IgnoreSingleElementAggregates ? hasSingleElement()
@@ -98,6 +105,7 @@ void UseDesignatedInitializersCheck::storeOptions(
     ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, IgnoreSingleElementAggregatesName,
                 IgnoreSingleElementAggregates);
+  Options.store(Opts, RestrictToPODTypesName, RestrictToPODTypes);
 }
 
 } // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
index 54dca26c6d735a..9aa216d30ef6b6 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
@@ -32,6 +32,7 @@ class UseDesignatedInitializersCheck : public ClangTidyCheck {
 
 private:
   bool IgnoreSingleElementAggregates;
+  bool RestrictToPODTypes;
 };
 
 } // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
index 105daf2c50ef2e..a306e784c33562 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
@@ -46,3 +46,9 @@ Options
 
     The value `false` specifies that even initializers for aggregate types
     with only a single element should be checked. The default value is `true`.
+
+.. option:: RestrictToPODTypes
+
+    The value `true` specifies that only Plain Old Data (POD) types shall be
+    checked. This makes the check applicable to even older C++ standards.
+    The default value is `false`.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 9780bf7f0080d0..e0b722ec091671 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -2,6 +2,9 @@
 // RUN: %check_clang_tidy -check-suffixes=,SINGLE-ELEMENT -std=c++17 %s modernize-use-designated-initializers %t \
 // RUN:     -- -config="{CheckOptions: [{key: modernize-use-designated-initializers.IgnoreSingleElementAggregates, value: false}]}" \
 // RUN:     --
+// RUN: %check_clang_tidy -check-suffixes=POD -std=c++17 %s modernize-use-designated-initializers %t \
+// RUN:     -- -config="{CheckOptions: [{key: modernize-use-designated-initializers.RestrictToPODTypes, value: true}]}" \
+// RUN:     --
 
 struct S1 {};
 
@@ -16,14 +19,17 @@ S2 s21{.i=1, .j =2};
 
 S2 s22 = {1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-2]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
 
 S2 s23{1};
 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-2]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
 
 S2 s24{.i = 1};
 
 S2 s25 = {.i=1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-2]]:17: warning: use designated init expression [modernize-use-designated-initializers]
 
 class S3 {
   public:
@@ -34,10 +40,14 @@ class S3 {
 S3 s31 = {.s2 = 1, 2, 3.1};
 // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:20: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-4]]:23: warning: use designated init expression [modernize-use-designated-initializers]
 
 S3 s32 = {{.i = 1, 2}};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-2]]:20: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-4]]:20: warning: use designated init expression [modernize-use-designated-initializers]
 
 struct S4 {
     double d;
@@ -81,3 +91,11 @@ S7 s71 {1};
 struct S8: S7 { int i; };
 
 S8 s81{1, 2};
+
+struct S9 {
+    int i, j;
+    S9 &operator=(S9);
+};
+
+S9 s91{1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]

>From b6505e0ca6d5a436c9757dac464cf074508cc56d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sun, 11 Feb 2024 11:52:29 +0100
Subject: [PATCH 18/62] Add fix-its

---
 .../modernize/UseDesignatedInitializersCheck.cpp  | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index b1b44289111c7a..081286081b4cbf 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -95,8 +95,19 @@ void UseDesignatedInitializersCheck::check(
       diag(InitList->getLBraceLoc(), "use designated initializer list");
       return;
     }
-    for (const auto *InitExpr : UndesignatedComponents) {
-      diag(InitExpr->getBeginLoc(), "use designated init expression");
+    const auto FieldIterator = Type->fields().begin();
+    for (const auto *InitExpr : *SyntacticInitList) {
+      const auto Field = std::next(FieldIterator);
+      if (std::find(UndesignatedComponents.begin(),
+                    UndesignatedComponents.end(),
+                    InitExpr) == UndesignatedComponents.end())
+        continue;
+      if (const auto *FieldID = Field->getIdentifier()) {
+        const auto FieldName = FieldID->getName();
+        diag(InitExpr->getBeginLoc(), "use designated init expression")
+            << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
+                                          "." + FieldName.str() + "=");
+      }
     }
   }
 }

>From 8487f23d908691b442e4f1779168872ed1afd7aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sun, 11 Feb 2024 14:36:19 +0100
Subject: [PATCH 19/62] Move computation of designated initializers to common
 place

---
 clang-tools-extra/clangd/InlayHints.cpp       | 167 +--------------
 .../clang/Tooling/DesignatedInitializers.h    |  43 ++++
 clang/lib/Tooling/CMakeLists.txt              |   1 +
 clang/lib/Tooling/DesignatedInitializers.cpp  | 195 ++++++++++++++++++
 4 files changed, 241 insertions(+), 165 deletions(-)
 create mode 100644 clang/include/clang/Tooling/DesignatedInitializers.h
 create mode 100644 clang/lib/Tooling/DesignatedInitializers.cpp

diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 671a9c30ffa959..09f5dba5697b10 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -23,8 +23,8 @@
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/OperatorKinds.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/DesignatedInitializers.h"
 #include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
@@ -42,169 +42,6 @@ namespace {
 // For now, inlay hints are always anchored at the left or right of their range.
 enum class HintSide { Left, Right };
 
-// Helper class to iterate over the designator names of an aggregate type.
-//
-// For an array type, yields [0], [1], [2]...
-// For aggregate classes, yields null for each base, then .field1, .field2, ...
-class AggregateDesignatorNames {
-public:
-  AggregateDesignatorNames(QualType T) {
-    if (!T.isNull()) {
-      T = T.getCanonicalType();
-      if (T->isArrayType()) {
-        IsArray = true;
-        Valid = true;
-        return;
-      }
-      if (const RecordDecl *RD = T->getAsRecordDecl()) {
-        Valid = true;
-        FieldsIt = RD->field_begin();
-        FieldsEnd = RD->field_end();
-        if (const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(RD)) {
-          BasesIt = CRD->bases_begin();
-          BasesEnd = CRD->bases_end();
-          Valid = CRD->isAggregate();
-        }
-        OneField = Valid && BasesIt == BasesEnd && FieldsIt != FieldsEnd &&
-                   std::next(FieldsIt) == FieldsEnd;
-      }
-    }
-  }
-  // Returns false if the type was not an aggregate.
-  operator bool() { return Valid; }
-  // Advance to the next element in the aggregate.
-  void next() {
-    if (IsArray)
-      ++Index;
-    else if (BasesIt != BasesEnd)
-      ++BasesIt;
-    else if (FieldsIt != FieldsEnd)
-      ++FieldsIt;
-  }
-  // Print the designator to Out.
-  // Returns false if we could not produce a designator for this element.
-  bool append(std::string &Out, bool ForSubobject) {
-    if (IsArray) {
-      Out.push_back('[');
-      Out.append(std::to_string(Index));
-      Out.push_back(']');
-      return true;
-    }
-    if (BasesIt != BasesEnd)
-      return false; // Bases can't be designated. Should we make one up?
-    if (FieldsIt != FieldsEnd) {
-      llvm::StringRef FieldName;
-      if (const IdentifierInfo *II = FieldsIt->getIdentifier())
-        FieldName = II->getName();
-
-      // For certain objects, their subobjects may be named directly.
-      if (ForSubobject &&
-          (FieldsIt->isAnonymousStructOrUnion() ||
-           // std::array<int,3> x = {1,2,3}. Designators not strictly valid!
-           (OneField && isReservedName(FieldName))))
-        return true;
-
-      if (!FieldName.empty() && !isReservedName(FieldName)) {
-        Out.push_back('.');
-        Out.append(FieldName.begin(), FieldName.end());
-        return true;
-      }
-      return false;
-    }
-    return false;
-  }
-
-private:
-  bool Valid = false;
-  bool IsArray = false;
-  bool OneField = false; // e.g. std::array { T __elements[N]; }
-  unsigned Index = 0;
-  CXXRecordDecl::base_class_const_iterator BasesIt;
-  CXXRecordDecl::base_class_const_iterator BasesEnd;
-  RecordDecl::field_iterator FieldsIt;
-  RecordDecl::field_iterator FieldsEnd;
-};
-
-// Collect designator labels describing the elements of an init list.
-//
-// This function contributes the designators of some (sub)object, which is
-// represented by the semantic InitListExpr Sem.
-// This includes any nested subobjects, but *only* if they are part of the same
-// original syntactic init list (due to brace elision).
-// In other words, it may descend into subobjects but not written init-lists.
-//
-// For example: struct Outer { Inner a,b; }; struct Inner { int x, y; }
-//              Outer o{{1, 2}, 3};
-// This function will be called with Sem = { {1, 2}, {3, ImplicitValue} }
-// It should generate designators '.a:' and '.b.x:'.
-// '.a:' is produced directly without recursing into the written sublist.
-// (The written sublist will have a separate collectDesignators() call later).
-// Recursion with Prefix='.b' and Sem = {3, ImplicitValue} produces '.b.x:'.
-void collectDesignators(const InitListExpr *Sem,
-                        llvm::DenseMap<SourceLocation, std::string> &Out,
-                        const llvm::DenseSet<SourceLocation> &NestedBraces,
-                        std::string &Prefix) {
-  if (!Sem || Sem->isTransparent())
-    return;
-  assert(Sem->isSemanticForm());
-
-  // The elements of the semantic form all correspond to direct subobjects of
-  // the aggregate type. `Fields` iterates over these subobject names.
-  AggregateDesignatorNames Fields(Sem->getType());
-  if (!Fields)
-    return;
-  for (const Expr *Init : Sem->inits()) {
-    auto Next = llvm::make_scope_exit([&, Size(Prefix.size())] {
-      Fields.next();       // Always advance to the next subobject name.
-      Prefix.resize(Size); // Erase any designator we appended.
-    });
-    // Skip for a broken initializer or if it is a "hole" in a subobject that
-    // was not explicitly initialized.
-    if (!Init || llvm::isa<ImplicitValueInitExpr>(Init))
-      continue;
-
-    const auto *BraceElidedSubobject = llvm::dyn_cast<InitListExpr>(Init);
-    if (BraceElidedSubobject &&
-        NestedBraces.contains(BraceElidedSubobject->getLBraceLoc()))
-      BraceElidedSubobject = nullptr; // there were braces!
-
-    if (!Fields.append(Prefix, BraceElidedSubobject != nullptr))
-      continue; // no designator available for this subobject
-    if (BraceElidedSubobject) {
-      // If the braces were elided, this aggregate subobject is initialized
-      // inline in the same syntactic list.
-      // Descend into the semantic list describing the subobject.
-      // (NestedBraces are still correct, they're from the same syntactic list).
-      collectDesignators(BraceElidedSubobject, Out, NestedBraces, Prefix);
-      continue;
-    }
-    Out.try_emplace(Init->getBeginLoc(), Prefix);
-  }
-}
-
-// Get designators describing the elements of a (syntactic) init list.
-// This does not produce designators for any explicitly-written nested lists.
-llvm::DenseMap<SourceLocation, std::string>
-getDesignators(const InitListExpr *Syn) {
-  assert(Syn->isSyntacticForm());
-
-  // collectDesignators needs to know which InitListExprs in the semantic tree
-  // were actually written, but InitListExpr::isExplicit() lies.
-  // Instead, record where braces of sub-init-lists occur in the syntactic form.
-  llvm::DenseSet<SourceLocation> NestedBraces;
-  for (const Expr *Init : Syn->inits())
-    if (auto *Nested = llvm::dyn_cast<InitListExpr>(Init))
-      NestedBraces.insert(Nested->getLBraceLoc());
-
-  // Traverse the semantic form to find the designators.
-  // We use their SourceLocation to correlate with the syntactic form later.
-  llvm::DenseMap<SourceLocation, std::string> Designators;
-  std::string EmptyPrefix;
-  collectDesignators(Syn->isSemanticForm() ? Syn : Syn->getSemanticForm(),
-                     Designators, NestedBraces, EmptyPrefix);
-  return Designators;
-}
-
 void stripLeadingUnderscores(StringRef &Name) { Name = Name.ltrim('_'); }
 
 // getDeclForType() returns the decl responsible for Type's spelling.
@@ -854,7 +691,7 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
     if (Syn->isIdiomaticZeroInitializer(AST.getLangOpts()))
       return true;
     llvm::DenseMap<SourceLocation, std::string> Designators =
-        getDesignators(Syn);
+        clang::tooling::getDesignators(Syn);
     for (const Expr *Init : Syn->inits()) {
       if (llvm::isa<DesignatedInitExpr>(Init))
         continue;
diff --git a/clang/include/clang/Tooling/DesignatedInitializers.h b/clang/include/clang/Tooling/DesignatedInitializers.h
new file mode 100644
index 00000000000000..e978dfe639f0c0
--- /dev/null
+++ b/clang/include/clang/Tooling/DesignatedInitializers.h
@@ -0,0 +1,43 @@
+//===--- DesignatedInitializers.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file provides utilities for designated initializers.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Expr.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang::tooling {
+
+/// Get designators describing the elements of a (syntactic) init list.
+///
+/// Given for example the type
+///
+///     struct S { int i, j; };
+///
+/// and the definition
+///
+///     S s{1, 2};
+///
+/// calling `getDesignators` for the initializer list expression `{1, 2}`
+/// would produce the map `{loc(1): ".i", loc(2): ".j"}`.
+///
+/// It does not produce designators for any explicitly-written nested lists,
+/// e.g. `{1, .j=2}` would only return `{loc(1): ".i"}`.
+///
+/// It also considers structs with fields of record types like
+/// `struct T { S s; };`. In this case, there would be designators of the
+/// form
+/// `.s.i` and `.s.j` in the returned map.
+llvm::DenseMap<clang::SourceLocation, std::string>
+getDesignators(const clang::InitListExpr *Syn);
+
+} // namespace clang::tooling
diff --git a/clang/lib/Tooling/CMakeLists.txt b/clang/lib/Tooling/CMakeLists.txt
index aff39e4de13c0b..8b0853d9150bb3 100644
--- a/clang/lib/Tooling/CMakeLists.txt
+++ b/clang/lib/Tooling/CMakeLists.txt
@@ -106,6 +106,7 @@ add_clang_library(clangTooling
   ArgumentsAdjusters.cpp
   CommonOptionsParser.cpp
   CompilationDatabase.cpp
+  DesignatedInitializers.cpp
   Execution.cpp
   ExpandResponseFilesCompilationDatabase.cpp
   FileMatchTrie.cpp
diff --git a/clang/lib/Tooling/DesignatedInitializers.cpp b/clang/lib/Tooling/DesignatedInitializers.cpp
new file mode 100644
index 00000000000000..8671625bd19ea3
--- /dev/null
+++ b/clang/lib/Tooling/DesignatedInitializers.cpp
@@ -0,0 +1,195 @@
+//===--- DesignatedInitializers.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file provides utilities for designated initializers.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/DesignatedInitializers.h"
+#include "clang/AST/DeclCXX.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/ScopeExit.h"
+
+namespace clang::tooling {
+
+namespace {
+
+/// Returns true if Name is reserved, like _Foo or __Vector_base.
+static inline bool isReservedName(llvm::StringRef Name) {
+  // This doesn't catch all cases, but the most common.
+  return Name.size() >= 2 && Name[0] == '_' &&
+         (isUppercase(Name[1]) || Name[1] == '_');
+}
+
+// Helper class to iterate over the designator names of an aggregate type.
+//
+// For an array type, yields [0], [1], [2]...
+// For aggregate classes, yields null for each base, then .field1, .field2,
+// ...
+class AggregateDesignatorNames {
+public:
+  AggregateDesignatorNames(QualType T) {
+    if (!T.isNull()) {
+      T = T.getCanonicalType();
+      if (T->isArrayType()) {
+        IsArray = true;
+        Valid = true;
+        return;
+      }
+      if (const RecordDecl *RD = T->getAsRecordDecl()) {
+        Valid = true;
+        FieldsIt = RD->field_begin();
+        FieldsEnd = RD->field_end();
+        if (const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(RD)) {
+          BasesIt = CRD->bases_begin();
+          BasesEnd = CRD->bases_end();
+          Valid = CRD->isAggregate();
+        }
+        OneField = Valid && BasesIt == BasesEnd && FieldsIt != FieldsEnd &&
+                   std::next(FieldsIt) == FieldsEnd;
+      }
+    }
+  }
+  // Returns false if the type was not an aggregate.
+  operator bool() { return Valid; }
+  // Advance to the next element in the aggregate.
+  void next() {
+    if (IsArray)
+      ++Index;
+    else if (BasesIt != BasesEnd)
+      ++BasesIt;
+    else if (FieldsIt != FieldsEnd)
+      ++FieldsIt;
+  }
+  // Print the designator to Out.
+  // Returns false if we could not produce a designator for this element.
+  bool append(std::string &Out, bool ForSubobject) {
+    if (IsArray) {
+      Out.push_back('[');
+      Out.append(std::to_string(Index));
+      Out.push_back(']');
+      return true;
+    }
+    if (BasesIt != BasesEnd)
+      return false; // Bases can't be designated. Should we make one up?
+    if (FieldsIt != FieldsEnd) {
+      llvm::StringRef FieldName;
+      if (const IdentifierInfo *II = FieldsIt->getIdentifier())
+        FieldName = II->getName();
+
+      // For certain objects, their subobjects may be named directly.
+      if (ForSubobject &&
+          (FieldsIt->isAnonymousStructOrUnion() ||
+           // std::array<int,3> x = {1,2,3}. Designators not strictly valid!
+           (OneField && isReservedName(FieldName))))
+        return true;
+
+      if (!FieldName.empty() && !isReservedName(FieldName)) {
+        Out.push_back('.');
+        Out.append(FieldName.begin(), FieldName.end());
+        return true;
+      }
+      return false;
+    }
+    return false;
+  }
+
+private:
+  bool Valid = false;
+  bool IsArray = false;
+  bool OneField = false; // e.g. std::array { T __elements[N]; }
+  unsigned Index = 0;
+  CXXRecordDecl::base_class_const_iterator BasesIt;
+  CXXRecordDecl::base_class_const_iterator BasesEnd;
+  RecordDecl::field_iterator FieldsIt;
+  RecordDecl::field_iterator FieldsEnd;
+};
+
+// Collect designator labels describing the elements of an init list.
+//
+// This function contributes the designators of some (sub)object, which is
+// represented by the semantic InitListExpr Sem.
+// This includes any nested subobjects, but *only* if they are part of the
+// same original syntactic init list (due to brace elision). In other words,
+// it may descend into subobjects but not written init-lists.
+//
+// For example: struct Outer { Inner a,b; }; struct Inner { int x, y; }
+//              Outer o{{1, 2}, 3};
+// This function will be called with Sem = { {1, 2}, {3, ImplicitValue} }
+// It should generate designators '.a:' and '.b.x:'.
+// '.a:' is produced directly without recursing into the written sublist.
+// (The written sublist will have a separate collectDesignators() call later).
+// Recursion with Prefix='.b' and Sem = {3, ImplicitValue} produces '.b.x:'.
+void collectDesignators(const InitListExpr *Sem,
+                        llvm::DenseMap<SourceLocation, std::string> &Out,
+                        const llvm::DenseSet<SourceLocation> &NestedBraces,
+                        std::string &Prefix) {
+  if (!Sem || Sem->isTransparent())
+    return;
+  assert(Sem->isSemanticForm());
+
+  // The elements of the semantic form all correspond to direct subobjects of
+  // the aggregate type. `Fields` iterates over these subobject names.
+  AggregateDesignatorNames Fields(Sem->getType());
+  if (!Fields)
+    return;
+  for (const Expr *Init : Sem->inits()) {
+    auto Next = llvm::make_scope_exit([&, Size(Prefix.size())] {
+      Fields.next();       // Always advance to the next subobject name.
+      Prefix.resize(Size); // Erase any designator we appended.
+    });
+    // Skip for a broken initializer or if it is a "hole" in a subobject that
+    // was not explicitly initialized.
+    if (!Init || llvm::isa<ImplicitValueInitExpr>(Init))
+      continue;
+
+    const auto *BraceElidedSubobject = llvm::dyn_cast<InitListExpr>(Init);
+    if (BraceElidedSubobject &&
+        NestedBraces.contains(BraceElidedSubobject->getLBraceLoc()))
+      BraceElidedSubobject = nullptr; // there were braces!
+
+    if (!Fields.append(Prefix, BraceElidedSubobject != nullptr))
+      continue; // no designator available for this subobject
+    if (BraceElidedSubobject) {
+      // If the braces were elided, this aggregate subobject is initialized
+      // inline in the same syntactic list.
+      // Descend into the semantic list describing the subobject.
+      // (NestedBraces are still correct, they're from the same syntactic
+      // list).
+      collectDesignators(BraceElidedSubobject, Out, NestedBraces, Prefix);
+      continue;
+    }
+    Out.try_emplace(Init->getBeginLoc(), Prefix);
+  }
+}
+
+} // namespace
+
+llvm::DenseMap<SourceLocation, std::string>
+getDesignators(const InitListExpr *Syn) {
+  assert(Syn->isSyntacticForm());
+
+  // collectDesignators needs to know which InitListExprs in the semantic tree
+  // were actually written, but InitListExpr::isExplicit() lies.
+  // Instead, record where braces of sub-init-lists occur in the syntactic form.
+  llvm::DenseSet<SourceLocation> NestedBraces;
+  for (const Expr *Init : Syn->inits())
+    if (auto *Nested = llvm::dyn_cast<InitListExpr>(Init))
+      NestedBraces.insert(Nested->getLBraceLoc());
+
+  // Traverse the semantic form to find the designators.
+  // We use their SourceLocation to correlate with the syntactic form later.
+  llvm::DenseMap<SourceLocation, std::string> Designators;
+  std::string EmptyPrefix;
+  collectDesignators(Syn->isSemanticForm() ? Syn : Syn->getSemanticForm(),
+                     Designators, NestedBraces, EmptyPrefix);
+  return Designators;
+}
+
+} // namespace clang::tooling

>From 87f263fa71fc52214822ecc415e2e5662f4f30ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sun, 11 Feb 2024 14:37:45 +0100
Subject: [PATCH 20/62] Fully implement fix-its reusing designated initializer
 computation from Clangd

---
 .../UseDesignatedInitializersCheck.cpp        | 67 ++++++++++---------
 .../modernize/use-designated-initializers.cpp |  8 +++
 2 files changed, 44 insertions(+), 31 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 081286081b4cbf..9e90df711df66a 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -14,9 +14,9 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/ASTMatchers/ASTMatchersMacros.h"
-#include <algorithm>
-#include <iterator>
-#include <vector>
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/DesignatedInitializers.h"
 
 using namespace clang::ast_matchers;
 
@@ -29,15 +29,6 @@ static const bool IgnoreSingleElementAggregatesDefault = true;
 static const char *RestrictToPODTypesName = "RestrictToPODTypes";
 static const bool RestrictToPODTypesDefault = false;
 
-static std::vector<Stmt *>
-getUndesignatedComponents(const InitListExpr *SyntacticInitList) {
-  std::vector<Stmt *> Result;
-  std::copy_if(SyntacticInitList->begin(), SyntacticInitList->end(),
-               std::back_inserter(Result),
-               [](auto S) { return !isa<DesignatedInitExpr>(S); });
-  return Result;
-}
-
 UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
     StringRef Name, ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context), IgnoreSingleElementAggregates(Options.get(
@@ -51,7 +42,9 @@ AST_MATCHER(CXXRecordDecl, isAggregate) { return Node.isAggregate(); }
 AST_MATCHER(CXXRecordDecl, isPOD) { return Node.isPOD(); }
 
 AST_MATCHER(InitListExpr, isFullyDesignated) {
-  return getUndesignatedComponents(&Node).empty();
+  return std::all_of(Node.begin(), Node.end(), [](auto *InitExpr) {
+    return isa<DesignatedInitExpr>(InitExpr);
+  });
 }
 
 AST_MATCHER(InitListExpr, hasSingleElement) { return Node.getNumInits() == 1; }
@@ -82,6 +75,12 @@ void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
       this);
 }
 
+static bool isFullyUndesignated(const InitListExpr *SyntacticInitList) {
+  return std::all_of(
+      SyntacticInitList->begin(), SyntacticInitList->end(),
+      [](auto *InitExpr) { return !isa<DesignatedInitExpr>(InitExpr); });
+}
+
 void UseDesignatedInitializersCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *InitList = Result.Nodes.getNodeAs<InitListExpr>("init");
@@ -89,24 +88,30 @@ void UseDesignatedInitializersCheck::check(
   if (!Type || !InitList)
     return;
   if (const auto *SyntacticInitList = InitList->getSyntacticForm()) {
-    const auto UndesignatedComponents =
-        getUndesignatedComponents(SyntacticInitList);
-    if (UndesignatedComponents.size() == SyntacticInitList->getNumInits()) {
-      diag(InitList->getLBraceLoc(), "use designated initializer list");
-      return;
-    }
-    const auto FieldIterator = Type->fields().begin();
-    for (const auto *InitExpr : *SyntacticInitList) {
-      const auto Field = std::next(FieldIterator);
-      if (std::find(UndesignatedComponents.begin(),
-                    UndesignatedComponents.end(),
-                    InitExpr) == UndesignatedComponents.end())
-        continue;
-      if (const auto *FieldID = Field->getIdentifier()) {
-        const auto FieldName = FieldID->getName();
-        diag(InitExpr->getBeginLoc(), "use designated init expression")
-            << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
-                                          "." + FieldName.str() + "=");
+    const llvm::DenseMap<clang::SourceLocation, std::string> Designators =
+        clang::tooling::getDesignators(SyntacticInitList);
+    if (isFullyUndesignated(SyntacticInitList)) {
+      std::string NewList = "{";
+      for (const Stmt *InitExpr : *SyntacticInitList) {
+        if (InitExpr != *SyntacticInitList->begin())
+          NewList += ", ";
+        NewList += Designators.at(InitExpr->getBeginLoc());
+        NewList += "=";
+        NewList += Lexer::getSourceText(
+            CharSourceRange::getTokenRange(InitExpr->getSourceRange()),
+            *Result.SourceManager, getLangOpts());
+      }
+      NewList += "}";
+      diag(InitList->getLBraceLoc(), "use designated initializer list")
+          << FixItHint::CreateReplacement(InitList->getSourceRange(), NewList);
+    } else {
+      for (const auto *InitExpr : *SyntacticInitList) {
+        if (!isa<DesignatedInitExpr>(InitExpr)) {
+          diag(InitExpr->getBeginLoc(), "use designated init expression")
+              << FixItHint::CreateInsertion(
+                     InitExpr->getBeginLoc(),
+                     Designators.at(InitExpr->getBeginLoc()) + "=");
+        }
       }
     }
   }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index e0b722ec091671..7d8c2ee63b4aef 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -20,16 +20,19 @@ S2 s21{.i=1, .j =2};
 S2 s22 = {1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-2]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-FIXES: S2 s22 = {.i=1, .j=2};
 
 S2 s23{1};
 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-2]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-FIXES: S2 s23{.i=1};
 
 S2 s24{.i = 1};
 
 S2 s25 = {.i=1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-2]]:17: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-FIXES: S2 s25 = {.i=1, .j=2};
 
 class S3 {
   public:
@@ -42,12 +45,14 @@ S3 s31 = {.s2 = 1, 2, 3.1};
 // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-3]]:20: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-4]]:23: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-FIXES: S3 s31 = {.s2 = 1, .s2.j=2, .d=3.1};
 
 S3 s32 = {{.i = 1, 2}};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-2]]:20: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-4]]:20: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-FIXES: S3 s32 = {.s2={.i = 1, 2}};
 
 struct S4 {
     double d;
@@ -56,9 +61,11 @@ struct S4 {
 
 S4 s41 {2.2};
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-FIXES-SINGLE-ELEMENT: S4 s41 {.d=2.2};
 
 S4 s42 = {{}};
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-FIXES-SINGLE-ELEMENT: S4 s42 = {.d={}};
 
 template<typename S> S template1() { return {10, 11}; }
 
@@ -99,3 +106,4 @@ struct S9 {
 
 S9 s91{1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-FIXES: S9 s91{.i=1, .j=2};

>From 887adda17fedf40f031413197fdf30ba65be8294 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sun, 11 Feb 2024 14:46:21 +0100
Subject: [PATCH 21/62] Separate by empty line

---
 clang-tools-extra/docs/ReleaseNotes.rst | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 8779ada257bd37..c2c7c0db56a68b 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -105,6 +105,7 @@ New checks
 
   Replaces certain conditional statements with equivalent calls to
   ``std::min`` or ``std::max``.
+
 - New :doc:`modernize-use-designated-initializers
   <clang-tidy/checks/modernize/use-designated-initializers>` check.
 

>From 07de060351d19dfbee91780739d85115e263bdc5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sun, 11 Feb 2024 15:00:18 +0100
Subject: [PATCH 22/62] Add test for default-initialized fields

---
 .../checkers/modernize/use-designated-initializers.cpp      | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 7d8c2ee63b4aef..5eada72e225411 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -107,3 +107,9 @@ struct S9 {
 S9 s91{1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
 // CHECK-FIXES: S9 s91{.i=1, .j=2};
+
+struct S10 { int i = 1, j = 2; };
+
+S10 s101 {1, .j=2};
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-FIXES: S10 s101 {.i=1, .j=2};

>From 87cbd9fa18a271782b6fce380b4fbfd48e5da67b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sun, 11 Feb 2024 17:13:37 +0100
Subject: [PATCH 23/62] Fix C++20 style

---
 .../checks/modernize/use-designated-initializers.rst        | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
index a306e784c33562..c17aea84b73941 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
@@ -10,13 +10,13 @@ With plain initializer lists, it is very easy to introduce bugs when adding
 new fields in the middle of a struct or class type. The same confusion might
 arise when changing the order of fields.
 
-C++ 20 supports the designated initializer syntax for aggregate types.
+C++20 supports the designated initializer syntax for aggregate types.
 By applying it, we can always be sure that aggregates are constructed correctly,
 because every variable being initialized is referenced by name.
 
-Even when compiling in a language version older than C++ 20, depending on you compiler,
+Even when compiling in a language version older than C++20, depending on you compiler,
 designated initializers are potentially supported. Therefore, the check is not restricted
-to C++ 20 and older.
+to C++20 and older.
 
 Example:
 

>From aaa49a1587828d53ccae03fe01d707b2f836bafd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Mon, 12 Feb 2024 19:24:31 +0100
Subject: [PATCH 24/62] Have custom AST matchers in anonymous namespace

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp   | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 9e90df711df66a..e780002b6a02ed 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -37,6 +37,8 @@ UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
       RestrictToPODTypes(
           Options.get(RestrictToPODTypesName, RestrictToPODTypesDefault)) {}
 
+namespace {
+
 AST_MATCHER(CXXRecordDecl, isAggregate) { return Node.isAggregate(); }
 
 AST_MATCHER(CXXRecordDecl, isPOD) { return Node.isPOD(); }
@@ -61,6 +63,8 @@ AST_MATCHER(FieldDecl, isAnonymousDecl) {
   return false;
 }
 
+} // namespace
+
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
       initListExpr(

>From bf2083e05ae2509707ce39e48fd919995b629842 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Mon, 12 Feb 2024 19:36:39 +0100
Subject: [PATCH 25/62] Keep public methods public

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.h      | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
index 9aa216d30ef6b6..8c947a1027d957 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
@@ -23,12 +23,11 @@ class UseDesignatedInitializersCheck : public ClangTidyCheck {
   UseDesignatedInitializersCheck(StringRef Name, ClangTidyContext *Context);
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
 
-private:
   std::optional<TraversalKind> getCheckTraversalKind() const override {
     return TK_IgnoreUnlessSpelledInSource;
   }
-  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
 
 private:
   bool IgnoreSingleElementAggregates;

>From bf93bd5e6d751bccbc84a65f9847fda8c26c007f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Mon, 12 Feb 2024 19:43:37 +0100
Subject: [PATCH 26/62] Rename method

---
 .../UseDesignatedInitializersCheck.cpp        |  2 +-
 clang-tools-extra/clangd/InlayHints.cpp       |  5 +++--
 .../clang/Tooling/DesignatedInitializers.h    | 21 +++++++++----------
 clang/lib/Tooling/DesignatedInitializers.cpp  |  2 +-
 4 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index e780002b6a02ed..84b63f8562f480 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -93,7 +93,7 @@ void UseDesignatedInitializersCheck::check(
     return;
   if (const auto *SyntacticInitList = InitList->getSyntacticForm()) {
     const llvm::DenseMap<clang::SourceLocation, std::string> Designators =
-        clang::tooling::getDesignators(SyntacticInitList);
+        clang::tooling::getUnwrittenDesignators(SyntacticInitList);
     if (isFullyUndesignated(SyntacticInitList)) {
       std::string NewList = "{";
       for (const Stmt *InitExpr : *SyntacticInitList) {
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 09f5dba5697b10..c8d3a94affee9d 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -684,14 +684,15 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
     // This is the one we will ultimately attach designators to.
     // It may have subobject initializers inlined without braces. The *semantic*
     // form of the init-list has nested init-lists for these.
-    // getDesignators will look at the semantic form to determine the labels.
+    // getUnwrittenDesignators will look at the semantic form to determine the
+    // labels.
     assert(Syn->isSyntacticForm() && "RAV should not visit implicit code!");
     if (!Cfg.InlayHints.Designators)
       return true;
     if (Syn->isIdiomaticZeroInitializer(AST.getLangOpts()))
       return true;
     llvm::DenseMap<SourceLocation, std::string> Designators =
-        clang::tooling::getDesignators(Syn);
+        clang::tooling::getUnwrittenDesignators(Syn);
     for (const Expr *Init : Syn->inits()) {
       if (llvm::isa<DesignatedInitExpr>(Init))
         continue;
diff --git a/clang/include/clang/Tooling/DesignatedInitializers.h b/clang/include/clang/Tooling/DesignatedInitializers.h
index e978dfe639f0c0..fa1deeae0791fc 100644
--- a/clang/include/clang/Tooling/DesignatedInitializers.h
+++ b/clang/include/clang/Tooling/DesignatedInitializers.h
@@ -20,24 +20,23 @@ namespace clang::tooling {
 /// Get designators describing the elements of a (syntactic) init list.
 ///
 /// Given for example the type
-///
-///     struct S { int i, j; };
-///
+/// \code
+/// struct S { int i, j; };
+/// \endcode
 /// and the definition
-///
-///     S s{1, 2};
-///
-/// calling `getDesignators` for the initializer list expression `{1, 2}`
-/// would produce the map `{loc(1): ".i", loc(2): ".j"}`.
+/// \code
+///  S s{1, 2};
+/// \endcode
+/// calling `getUnwrittenDesignators` for the initializer list expression
+/// `{1, 2}` would produce the map `{loc(1): ".i", loc(2): ".j"}`.
 ///
 /// It does not produce designators for any explicitly-written nested lists,
 /// e.g. `{1, .j=2}` would only return `{loc(1): ".i"}`.
 ///
 /// It also considers structs with fields of record types like
 /// `struct T { S s; };`. In this case, there would be designators of the
-/// form
-/// `.s.i` and `.s.j` in the returned map.
+/// form `.s.i` and `.s.j` in the returned map.
 llvm::DenseMap<clang::SourceLocation, std::string>
-getDesignators(const clang::InitListExpr *Syn);
+getUnwrittenDesignators(const clang::InitListExpr *Syn);
 
 } // namespace clang::tooling
diff --git a/clang/lib/Tooling/DesignatedInitializers.cpp b/clang/lib/Tooling/DesignatedInitializers.cpp
index 8671625bd19ea3..9d8d0a5f4795a7 100644
--- a/clang/lib/Tooling/DesignatedInitializers.cpp
+++ b/clang/lib/Tooling/DesignatedInitializers.cpp
@@ -172,7 +172,7 @@ void collectDesignators(const InitListExpr *Sem,
 } // namespace
 
 llvm::DenseMap<SourceLocation, std::string>
-getDesignators(const InitListExpr *Syn) {
+getUnwrittenDesignators(const InitListExpr *Syn) {
   assert(Syn->isSyntacticForm());
 
   // collectDesignators needs to know which InitListExprs in the semantic tree

>From 3dd384813141e6c9fa639d740ff3139a2c085925 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Mon, 12 Feb 2024 22:22:37 +0100
Subject: [PATCH 27/62] Analyze syntactic form only

---
 .../modernize/UseDesignatedInitializersCheck.cpp  |  8 +++++---
 .../modernize/use-designated-initializers.cpp     | 15 +++++++++++++++
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 84b63f8562f480..d4cade4a604ae2 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -44,9 +44,11 @@ AST_MATCHER(CXXRecordDecl, isAggregate) { return Node.isAggregate(); }
 AST_MATCHER(CXXRecordDecl, isPOD) { return Node.isPOD(); }
 
 AST_MATCHER(InitListExpr, isFullyDesignated) {
-  return std::all_of(Node.begin(), Node.end(), [](auto *InitExpr) {
-    return isa<DesignatedInitExpr>(InitExpr);
-  });
+  const InitListExpr *SyntacticForm =
+      Node.isSyntacticForm() ? &Node : Node.getSyntacticForm();
+  return std::all_of(
+      SyntacticForm->begin(), SyntacticForm->end(),
+      [](auto *InitExpr) { return isa<DesignatedInitExpr>(InitExpr); });
 }
 
 AST_MATCHER(InitListExpr, hasSingleElement) { return Node.getNumInits() == 1; }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 5eada72e225411..f65afa1def9a22 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -113,3 +113,18 @@ struct S10 { int i = 1, j = 2; };
 S10 s101 {1, .j=2};
 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-FIXES: S10 s101 {.i=1, .j=2};
+
+struct S11 { int i; S10 s10; };
+
+S11 s111 { .i = 1 };
+S11 s112 { 1 };
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-FIXES: S11 s112 {.i=1};
+
+S11 s113 { .i=1, {}};
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-FIXES: S11 s113 { .i=1, .s10={}};
+
+S11 s114 { .i=1, .s10={1, .j=2}};
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-FIXES: S11 s114 { .i=1, .s10={.i=1, .j=2}};

>From 363f5e63830e59c9a8db4c28bbd101df1e44288c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Tue, 13 Feb 2024 21:17:18 +0100
Subject: [PATCH 28/62] Have separate fixes

---
 .../modernize/UseDesignatedInitializersCheck.cpp | 16 +++++-----------
 .../modernize/use-designated-initializers.cpp    |  4 ++--
 2 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index d4cade4a604ae2..67327c306e2755 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -97,19 +97,13 @@ void UseDesignatedInitializersCheck::check(
     const llvm::DenseMap<clang::SourceLocation, std::string> Designators =
         clang::tooling::getUnwrittenDesignators(SyntacticInitList);
     if (isFullyUndesignated(SyntacticInitList)) {
-      std::string NewList = "{";
+      DiagnosticBuilder Diag =
+          diag(InitList->getLBraceLoc(), "use designated initializer list");
       for (const Stmt *InitExpr : *SyntacticInitList) {
-        if (InitExpr != *SyntacticInitList->begin())
-          NewList += ", ";
-        NewList += Designators.at(InitExpr->getBeginLoc());
-        NewList += "=";
-        NewList += Lexer::getSourceText(
-            CharSourceRange::getTokenRange(InitExpr->getSourceRange()),
-            *Result.SourceManager, getLangOpts());
+        Diag << FixItHint::CreateInsertion(
+            InitExpr->getBeginLoc(),
+            Designators.at(InitExpr->getBeginLoc()) + "=");
       }
-      NewList += "}";
-      diag(InitList->getLBraceLoc(), "use designated initializer list")
-          << FixItHint::CreateReplacement(InitList->getSourceRange(), NewList);
     } else {
       for (const auto *InitExpr : *SyntacticInitList) {
         if (!isa<DesignatedInitExpr>(InitExpr)) {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index f65afa1def9a22..a62ee1e609388e 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -52,7 +52,7 @@ S3 s32 = {{.i = 1, 2}};
 // CHECK-MESSAGES: :[[@LINE-2]]:20: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-4]]:20: warning: use designated init expression [modernize-use-designated-initializers]
-// CHECK-FIXES: S3 s32 = {.s2={.i = 1, 2}};
+// CHECK-FIXES: S3 s32 = {.s2={.i = 1, .j=2}};
 
 struct S4 {
     double d;
@@ -119,7 +119,7 @@ struct S11 { int i; S10 s10; };
 S11 s111 { .i = 1 };
 S11 s112 { 1 };
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
-// CHECK-FIXES: S11 s112 {.i=1};
+// CHECK-FIXES: S11 s112 { .i=1 };
 
 S11 s113 { .i=1, {}};
 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use designated init expression [modernize-use-designated-initializers]

>From 586fffccf0a64716d938a8eb4c5a554e1f746b1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Tue, 13 Feb 2024 21:41:13 +0100
Subject: [PATCH 29/62] Keep order in release notes

---
 clang-tools-extra/docs/ReleaseNotes.rst | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index c2c7c0db56a68b..4b860fab0a8abd 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -100,18 +100,18 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
+- New :doc:`modernize-use-designated-initializers
+  <clang-tidy/checks/modernize/use-designated-initializers>` check.
+
+  Finds initializer lists for aggregate types that could be
+  written as designated initializers instead.
+
 - New :doc:`readability-use-std-min-max
   <clang-tidy/checks/readability/use-std-min-max>` check.
 
   Replaces certain conditional statements with equivalent calls to
   ``std::min`` or ``std::max``.
 
-- New :doc:`modernize-use-designated-initializers
-  <clang-tidy/checks/modernize/use-designated-initializers>` check.
-
-  Finds initializer lists for aggregate type that could be
-  written as designated initializers instead.
-
 New check aliases
 ^^^^^^^^^^^^^^^^^
 

>From 1d7db087ee9142b55564a46e81f46ea39cf61bde Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 18:50:28 +0100
Subject: [PATCH 30/62] Use constexpr

---
 .../modernize/UseDesignatedInitializersCheck.cpp          | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 67327c306e2755..09233191030e57 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -22,12 +22,12 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::modernize {
 
-static const char *IgnoreSingleElementAggregatesName =
+static constexpr char IgnoreSingleElementAggregatesName[] =
     "IgnoreSingleElementAggregates";
-static const bool IgnoreSingleElementAggregatesDefault = true;
+static constexpr bool IgnoreSingleElementAggregatesDefault = true;
 
-static const char *RestrictToPODTypesName = "RestrictToPODTypes";
-static const bool RestrictToPODTypesDefault = false;
+static constexpr char RestrictToPODTypesName[] = "RestrictToPODTypes";
+static constexpr bool RestrictToPODTypesDefault = false;
 
 UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
     StringRef Name, ClangTidyContext *Context)

>From 06d1869d4d578dbb31b51231db53157a4906832d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 18:51:46 +0100
Subject: [PATCH 31/62] Move after namespace

---
 .../modernize/UseDesignatedInitializersCheck.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 09233191030e57..db7f1f627aad58 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -29,14 +29,6 @@ static constexpr bool IgnoreSingleElementAggregatesDefault = true;
 static constexpr char RestrictToPODTypesName[] = "RestrictToPODTypes";
 static constexpr bool RestrictToPODTypesDefault = false;
 
-UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
-    StringRef Name, ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context), IgnoreSingleElementAggregates(Options.get(
-                                         IgnoreSingleElementAggregatesName,
-                                         IgnoreSingleElementAggregatesDefault)),
-      RestrictToPODTypes(
-          Options.get(RestrictToPODTypesName, RestrictToPODTypesDefault)) {}
-
 namespace {
 
 AST_MATCHER(CXXRecordDecl, isAggregate) { return Node.isAggregate(); }
@@ -67,6 +59,14 @@ AST_MATCHER(FieldDecl, isAnonymousDecl) {
 
 } // namespace
 
+UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context), IgnoreSingleElementAggregates(Options.get(
+                                         IgnoreSingleElementAggregatesName,
+                                         IgnoreSingleElementAggregatesDefault)),
+      RestrictToPODTypes(
+          Options.get(RestrictToPODTypesName, RestrictToPODTypesDefault)) {}
+
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
       initListExpr(

>From 5ccd21d18048b377fcbbe5c8fe8cf87639cb4111 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 18:54:24 +0100
Subject: [PATCH 32/62] Check for null

---
 .../modernize/UseDesignatedInitializersCheck.cpp     | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index db7f1f627aad58..2625a73ea28884 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -36,11 +36,13 @@ AST_MATCHER(CXXRecordDecl, isAggregate) { return Node.isAggregate(); }
 AST_MATCHER(CXXRecordDecl, isPOD) { return Node.isPOD(); }
 
 AST_MATCHER(InitListExpr, isFullyDesignated) {
-  const InitListExpr *SyntacticForm =
-      Node.isSyntacticForm() ? &Node : Node.getSyntacticForm();
-  return std::all_of(
-      SyntacticForm->begin(), SyntacticForm->end(),
-      [](auto *InitExpr) { return isa<DesignatedInitExpr>(InitExpr); });
+  if (const InitListExpr *SyntacticForm =
+          Node.isSyntacticForm() ? &Node : Node.getSyntacticForm()) {
+    return std::all_of(
+        SyntacticForm->begin(), SyntacticForm->end(),
+        [](auto *InitExpr) { return isa<DesignatedInitExpr>(InitExpr); });
+  }
+  return true;
 }
 
 AST_MATCHER(InitListExpr, hasSingleElement) { return Node.getNumInits() == 1; }

>From ab4a20ea8fbae28642f8341acbd3c6a2c298ca83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 19:00:45 +0100
Subject: [PATCH 33/62] Use llvm::all_of

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 2625a73ea28884..f7c10feeea1485 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -38,9 +38,9 @@ AST_MATCHER(CXXRecordDecl, isPOD) { return Node.isPOD(); }
 AST_MATCHER(InitListExpr, isFullyDesignated) {
   if (const InitListExpr *SyntacticForm =
           Node.isSyntacticForm() ? &Node : Node.getSyntacticForm()) {
-    return std::all_of(
-        SyntacticForm->begin(), SyntacticForm->end(),
-        [](auto *InitExpr) { return isa<DesignatedInitExpr>(InitExpr); });
+    return llvm::all_of(SyntacticForm->children(), [](auto *InitExpr) {
+      return isa<DesignatedInitExpr>(InitExpr);
+    });
   }
   return true;
 }

>From 4d5aa57bf33cd3cfcfea80261395101bcbe82d5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 19:02:44 +0100
Subject: [PATCH 34/62] Convert matcher to internal variable

---
 .../modernize/UseDesignatedInitializersCheck.cpp          | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index f7c10feeea1485..66c5b64c547d66 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -47,10 +47,6 @@ AST_MATCHER(InitListExpr, isFullyDesignated) {
 
 AST_MATCHER(InitListExpr, hasSingleElement) { return Node.getNumInits() == 1; }
 
-AST_MATCHER_FUNCTION(::internal::Matcher<CXXRecordDecl>, hasBaseWithFields) {
-  return hasAnyBase(hasType(cxxRecordDecl(has(fieldDecl()))));
-}
-
 AST_MATCHER(FieldDecl, isAnonymousDecl) {
   if (const auto *Record =
           Node.getType().getCanonicalType()->getAsRecordDecl()) {
@@ -70,10 +66,12 @@ UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
           Options.get(RestrictToPODTypesName, RestrictToPODTypesDefault)) {}
 
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
+  const auto HasBaseWithFields =
+      hasAnyBase(hasType(cxxRecordDecl(has(fieldDecl()))));
   Finder->addMatcher(
       initListExpr(
           hasType(cxxRecordDecl(RestrictToPODTypes ? isPOD() : isAggregate(),
-                                unless(hasBaseWithFields()),
+                                unless(HasBaseWithFields),
                                 unless(has(fieldDecl(isAnonymousDecl()))))
                       .bind("type")),
           unless(IgnoreSingleElementAggregates ? hasSingleElement()

>From 9c9b2eb01aa709046eaf856f415fdf02705bda20 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 19:07:13 +0100
Subject: [PATCH 35/62] Check for unset type

---
 .../modernize/UseDesignatedInitializersCheck.cpp           | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 66c5b64c547d66..05289257c4f944 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -48,8 +48,11 @@ AST_MATCHER(InitListExpr, isFullyDesignated) {
 AST_MATCHER(InitListExpr, hasSingleElement) { return Node.getNumInits() == 1; }
 
 AST_MATCHER(FieldDecl, isAnonymousDecl) {
-  if (const auto *Record =
-          Node.getType().getCanonicalType()->getAsRecordDecl()) {
+  const auto Type = Node.getType();
+  if (Type.isNull()) {
+    return true;
+  }
+  if (const auto *Record = Type.getCanonicalType()->getAsRecordDecl()) {
     return Record->isAnonymousStructOrUnion() || !Record->getIdentifier();
   }
   return false;

>From fb82fe22c4d532a171f9345f8a0ecc9b3bf629bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 19:36:01 +0100
Subject: [PATCH 36/62] Mention options for older standards

---
 .../checks/modernize/use-designated-initializers.rst     | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
index c17aea84b73941..cd5e706f177a80 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
@@ -14,9 +14,12 @@ C++20 supports the designated initializer syntax for aggregate types.
 By applying it, we can always be sure that aggregates are constructed correctly,
 because every variable being initialized is referenced by name.
 
-Even when compiling in a language version older than C++20, depending on you compiler,
-designated initializers are potentially supported. Therefore, the check is not restricted
-to C++20 and older.
+Even when compiling in a language version older than C++20, depending on your
+compiler, designated initializers are potentially supported. Therefore, the
+check is not restricted to C++20 and older. Check out the options
+``-Wc99-designator`` to get support for mixed designators in
+initializer list in C and ``-Wc++20-designator`` for support of designated
+initializers in older C++ language modes.
 
 Example:
 

>From 83ecafbe49f7c5e3695e3af2caf1cfeba78f40a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 19:56:03 +0100
Subject: [PATCH 37/62] Add -fno-delayed-template-parsing

---
 .../checkers/modernize/use-designated-initializers.cpp    | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index a62ee1e609388e..05ccbd0fa2b219 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -1,10 +1,12 @@
-// RUN: %check_clang_tidy -std=c++17 %s modernize-use-designated-initializers %t
+// RUN: %check_clang_tidy -std=c++17 %s modernize-use-designated-initializers %t \
+// RUN:     -- \
+// RUN:     -- -fno-delayed-template-parsing
 // RUN: %check_clang_tidy -check-suffixes=,SINGLE-ELEMENT -std=c++17 %s modernize-use-designated-initializers %t \
 // RUN:     -- -config="{CheckOptions: [{key: modernize-use-designated-initializers.IgnoreSingleElementAggregates, value: false}]}" \
-// RUN:     --
+// RUN:     -- -fno-delayed-template-parsing
 // RUN: %check_clang_tidy -check-suffixes=POD -std=c++17 %s modernize-use-designated-initializers %t \
 // RUN:     -- -config="{CheckOptions: [{key: modernize-use-designated-initializers.RestrictToPODTypes, value: true}]}" \
-// RUN:     --
+// RUN:     -- -fno-delayed-template-parsing
 
 struct S1 {};
 

>From 7d43f68f44062381d9138574372f2a47b22efa88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 21:13:40 +0100
Subject: [PATCH 38/62] Support inline defined structs and unions

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp  | 2 +-
 .../checkers/modernize/use-designated-initializers.cpp       | 5 +++++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 05289257c4f944..7a62ac0ac10339 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -53,7 +53,7 @@ AST_MATCHER(FieldDecl, isAnonymousDecl) {
     return true;
   }
   if (const auto *Record = Type.getCanonicalType()->getAsRecordDecl()) {
-    return Record->isAnonymousStructOrUnion() || !Record->getIdentifier();
+    return Record->isAnonymousStructOrUnion();
   }
   return false;
 }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 05ccbd0fa2b219..be2734307a1fe8 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -87,6 +87,9 @@ struct S6 {
 };
 
 S6 s61 {1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-2]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-FIXES: S6 s61 {.i=1, .s.j=2};
 
 struct S7 {
     union {
@@ -96,6 +99,8 @@ struct S7 {
 };
 
 S7 s71 {1};
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-FIXES-SINGLE-ELEMENT: S7 s71 {.u.k=1};
 
 struct S8: S7 { int i; };
 

>From 5a1f58a36fa3a602007494f058c5f92a8178be8a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 21:14:01 +0100
Subject: [PATCH 39/62] Support anonymous structs and unions

---
 .../UseDesignatedInitializersCheck.cpp        | 14 +----------
 .../modernize/use-designated-initializers.cpp | 23 +++++++++++++++++++
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 7a62ac0ac10339..70c7fd43926533 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -47,17 +47,6 @@ AST_MATCHER(InitListExpr, isFullyDesignated) {
 
 AST_MATCHER(InitListExpr, hasSingleElement) { return Node.getNumInits() == 1; }
 
-AST_MATCHER(FieldDecl, isAnonymousDecl) {
-  const auto Type = Node.getType();
-  if (Type.isNull()) {
-    return true;
-  }
-  if (const auto *Record = Type.getCanonicalType()->getAsRecordDecl()) {
-    return Record->isAnonymousStructOrUnion();
-  }
-  return false;
-}
-
 } // namespace
 
 UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
@@ -74,8 +63,7 @@ void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
       initListExpr(
           hasType(cxxRecordDecl(RestrictToPODTypes ? isPOD() : isAggregate(),
-                                unless(HasBaseWithFields),
-                                unless(has(fieldDecl(isAnonymousDecl()))))
+                                unless(HasBaseWithFields))
                       .bind("type")),
           unless(IgnoreSingleElementAggregates ? hasSingleElement()
                                                : unless(anything())),
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index be2734307a1fe8..8b050ce8de5119 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -135,3 +135,26 @@ S11 s113 { .i=1, {}};
 S11 s114 { .i=1, .s10={1, .j=2}};
 // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-FIXES: S11 s114 { .i=1, .s10={.i=1, .j=2}};
+
+struct S12 {
+    int i;
+    struct { int j; };
+};
+
+S12 s121 {1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-2]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-FIXES: S12 s121 {.i=1, .j=2};
+
+struct S13 {
+    union {
+        int k;
+        double d;
+    };
+    int i;
+};
+
+S13 s131 {1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-2]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-FIXES: S13 s131 {.k=1, .i=2};

>From 79f9dd7748ea535bd4610c3300bb848cee9a4e80 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 21:26:58 +0100
Subject: [PATCH 40/62] Test aggregate in aggregate

---
 .../checkers/modernize/use-designated-initializers.cpp     | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 8b050ce8de5119..c932784f7f5bc9 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -56,6 +56,13 @@ S3 s32 = {{.i = 1, 2}};
 // CHECK-MESSAGES-POD: :[[@LINE-4]]:20: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-FIXES: S3 s32 = {.s2={.i = 1, .j=2}};
 
+S3 s33 = {{2}, .d=3.1};
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-2]]:11: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:11: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-4]]:11: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-FIXES: S3 s33 = {.s2={.i=2}, .d=3.1};
+
 struct S4 {
     double d;
     private: static int i;

>From 0c4163826b04dfc3b52e264234d8c64123ab1a14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 21:34:44 +0100
Subject: [PATCH 41/62] Add test for template values

---
 .../checkers/modernize/use-designated-initializers.cpp     | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index c932784f7f5bc9..159e3b05274ea4 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -165,3 +165,10 @@ S13 s131 {1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-2]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
 // CHECK-FIXES: S13 s131 {.k=1, .i=2};
+
+#define A (3+2)
+#define B .j=1
+
+S9 s92 {A, B};
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-FIXES: S9 s92 {.i=A, B};

>From f6fd1de365c0c499d347bf9d13c5bf14d83eee77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 22:02:44 +0100
Subject: [PATCH 42/62] Add option to ignore macros

---
 .../UseDesignatedInitializersCheck.cpp        | 30 +++++++++++++------
 .../UseDesignatedInitializersCheck.h          |  1 +
 .../modernize/use-designated-initializers.rst |  5 ++++
 .../modernize/use-designated-initializers.cpp | 13 ++++++--
 4 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 70c7fd43926533..45774a7095b485 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -29,6 +29,9 @@ static constexpr bool IgnoreSingleElementAggregatesDefault = true;
 static constexpr char RestrictToPODTypesName[] = "RestrictToPODTypes";
 static constexpr bool RestrictToPODTypesDefault = false;
 
+static constexpr char IgnoreMacrosName[] = "IgnoreMacros";
+static constexpr bool IgnoreMacrosDefault = true;
+
 namespace {
 
 AST_MATCHER(CXXRecordDecl, isAggregate) { return Node.isAggregate(); }
@@ -55,7 +58,8 @@ UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
                                          IgnoreSingleElementAggregatesName,
                                          IgnoreSingleElementAggregatesDefault)),
       RestrictToPODTypes(
-          Options.get(RestrictToPODTypesName, RestrictToPODTypesDefault)) {}
+          Options.get(RestrictToPODTypesName, RestrictToPODTypesDefault)),
+      IgnoreMacros(Options.get(IgnoreMacrosName, IgnoreMacrosDefault)) {}
 
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
   const auto HasBaseWithFields =
@@ -88,6 +92,9 @@ void UseDesignatedInitializersCheck::check(
     const llvm::DenseMap<clang::SourceLocation, std::string> Designators =
         clang::tooling::getUnwrittenDesignators(SyntacticInitList);
     if (isFullyUndesignated(SyntacticInitList)) {
+      if (IgnoreMacros && InitList->getBeginLoc().isMacroID()) {
+        return;
+      }
       DiagnosticBuilder Diag =
           diag(InitList->getLBraceLoc(), "use designated initializer list");
       for (const Stmt *InitExpr : *SyntacticInitList) {
@@ -95,15 +102,19 @@ void UseDesignatedInitializersCheck::check(
             InitExpr->getBeginLoc(),
             Designators.at(InitExpr->getBeginLoc()) + "=");
       }
-    } else {
-      for (const auto *InitExpr : *SyntacticInitList) {
-        if (!isa<DesignatedInitExpr>(InitExpr)) {
-          diag(InitExpr->getBeginLoc(), "use designated init expression")
-              << FixItHint::CreateInsertion(
-                     InitExpr->getBeginLoc(),
-                     Designators.at(InitExpr->getBeginLoc()) + "=");
-        }
+      return;
+    }
+    for (const auto *InitExpr : *SyntacticInitList) {
+      if (isa<DesignatedInitExpr>(InitExpr)) {
+        continue;
+      }
+      if (IgnoreMacros && InitExpr->getBeginLoc().isMacroID()) {
+        continue;
       }
+      diag(InitExpr->getBeginLoc(), "use designated init expression")
+          << FixItHint::CreateInsertion(
+                 InitExpr->getBeginLoc(),
+                 Designators.at(InitExpr->getBeginLoc()) + "=");
     }
   }
 }
@@ -113,6 +124,7 @@ void UseDesignatedInitializersCheck::storeOptions(
   Options.store(Opts, IgnoreSingleElementAggregatesName,
                 IgnoreSingleElementAggregates);
   Options.store(Opts, RestrictToPODTypesName, RestrictToPODTypes);
+  Options.store(Opts, IgnoreMacrosName, IgnoreMacros);
 }
 
 } // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
index 8c947a1027d957..0a496f51b95762 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.h
@@ -32,6 +32,7 @@ class UseDesignatedInitializersCheck : public ClangTidyCheck {
 private:
   bool IgnoreSingleElementAggregates;
   bool RestrictToPODTypes;
+  bool IgnoreMacros;
 };
 
 } // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
index cd5e706f177a80..4bb2406f792a45 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-designated-initializers.rst
@@ -45,6 +45,11 @@ declaration of ``S``.
 Options
 -------
 
+.. option::  IgnoreMacros
+
+  The value `false` specifies that components of initializer lists expanded
+  from macros are not checked. The default value is `true`.
+
 .. option:: IgnoreSingleElementAggregates
 
     The value `false` specifies that even initializers for aggregate types
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 159e3b05274ea4..832453453c93ad 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -7,6 +7,9 @@
 // RUN: %check_clang_tidy -check-suffixes=POD -std=c++17 %s modernize-use-designated-initializers %t \
 // RUN:     -- -config="{CheckOptions: [{key: modernize-use-designated-initializers.RestrictToPODTypes, value: true}]}" \
 // RUN:     -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -check-suffixes=,MACROS -std=c++17 %s modernize-use-designated-initializers %t \
+// RUN:     -- -config="{CheckOptions: [{key: modernize-use-designated-initializers.IgnoreMacros, value: false}]}" \
+// RUN:     -- -fno-delayed-template-parsing
 
 struct S1 {};
 
@@ -170,5 +173,11 @@ S13 s131 {1, 2};
 #define B .j=1
 
 S9 s92 {A, B};
-// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use designated init expression [modernize-use-designated-initializers]
-// CHECK-FIXES: S9 s92 {.i=A, B};
+// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:9: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES-MACROS: :[[@LINE-5]]:11: note: expanded from macro 'A'
+
+#define DECLARE_S93 S9 s93 {1, 2}
+
+DECLARE_S93;
+// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:1: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-MACROS: :[[@LINE-4]]:28: note: expanded from macro 'DECLARE_S93'

>From dc8b65361655dd6274c28f454c707b784f9d9a3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 14 Feb 2024 22:33:30 +0100
Subject: [PATCH 43/62] Stream full source ranges into diagnostics

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp     | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 45774a7095b485..71fae40f0dc600 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -97,6 +97,7 @@ void UseDesignatedInitializersCheck::check(
       }
       DiagnosticBuilder Diag =
           diag(InitList->getLBraceLoc(), "use designated initializer list");
+      Diag << InitList->getSourceRange();
       for (const Stmt *InitExpr : *SyntacticInitList) {
         Diag << FixItHint::CreateInsertion(
             InitExpr->getBeginLoc(),
@@ -112,6 +113,7 @@ void UseDesignatedInitializersCheck::check(
         continue;
       }
       diag(InitExpr->getBeginLoc(), "use designated init expression")
+          << InitExpr->getSourceRange()
           << FixItHint::CreateInsertion(
                  InitExpr->getBeginLoc(),
                  Designators.at(InitExpr->getBeginLoc()) + "=");

>From 3403af6b8e2c5929acd11230cdd7ff18144eb83a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Thu, 15 Feb 2024 20:44:03 +0100
Subject: [PATCH 44/62] Use getLocalOrGlobal for IgnoreMacros option

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp    | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 71fae40f0dc600..e4b153fcc4cbf4 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -59,7 +59,8 @@ UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
                                          IgnoreSingleElementAggregatesDefault)),
       RestrictToPODTypes(
           Options.get(RestrictToPODTypesName, RestrictToPODTypesDefault)),
-      IgnoreMacros(Options.get(IgnoreMacrosName, IgnoreMacrosDefault)) {}
+      IgnoreMacros(
+          Options.getLocalOrGlobal(IgnoreMacrosName, IgnoreMacrosDefault)) {}
 
 void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
   const auto HasBaseWithFields =

>From 0e111254e8f1927e46f69f2e0dccd9d310347d50 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Thu, 15 Feb 2024 20:44:18 +0100
Subject: [PATCH 45/62] Avoid negation

---
 .../modernize/UseDesignatedInitializersCheck.cpp           | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index e4b153fcc4cbf4..3f2ee1abc8582b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -48,7 +48,9 @@ AST_MATCHER(InitListExpr, isFullyDesignated) {
   return true;
 }
 
-AST_MATCHER(InitListExpr, hasSingleElement) { return Node.getNumInits() == 1; }
+AST_MATCHER(InitListExpr, hasMoreThanOneElement) {
+  return Node.getNumInits() > 1;
+}
 
 } // namespace
 
@@ -70,8 +72,7 @@ void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
           hasType(cxxRecordDecl(RestrictToPODTypes ? isPOD() : isAggregate(),
                                 unless(HasBaseWithFields))
                       .bind("type")),
-          unless(IgnoreSingleElementAggregates ? hasSingleElement()
-                                               : unless(anything())),
+          IgnoreSingleElementAggregates ? hasMoreThanOneElement() : anything(),
           unless(isFullyDesignated()))
           .bind("init"),
       this);

>From 0a065458e9f8f921cc7525b91ef69c563f4bbf20 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Thu, 15 Feb 2024 20:44:35 +0100
Subject: [PATCH 46/62] Use llvm::all_of

---
 .../modernize/UseDesignatedInitializersCheck.cpp          | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 3f2ee1abc8582b..273c0ab127f33f 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -41,7 +41,7 @@ AST_MATCHER(CXXRecordDecl, isPOD) { return Node.isPOD(); }
 AST_MATCHER(InitListExpr, isFullyDesignated) {
   if (const InitListExpr *SyntacticForm =
           Node.isSyntacticForm() ? &Node : Node.getSyntacticForm()) {
-    return llvm::all_of(SyntacticForm->children(), [](auto *InitExpr) {
+    return llvm::all_of(*SyntacticForm, [](auto *InitExpr) {
       return isa<DesignatedInitExpr>(InitExpr);
     });
   }
@@ -79,9 +79,9 @@ void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
 }
 
 static bool isFullyUndesignated(const InitListExpr *SyntacticInitList) {
-  return std::all_of(
-      SyntacticInitList->begin(), SyntacticInitList->end(),
-      [](auto *InitExpr) { return !isa<DesignatedInitExpr>(InitExpr); });
+  return llvm::all_of(*SyntacticInitList, [](auto *InitExpr) {
+    return !isa<DesignatedInitExpr>(InitExpr);
+  });
 }
 
 void UseDesignatedInitializersCheck::check(

>From f5f15aab72674e32bfa50ba2a648cac684569a57 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Thu, 15 Feb 2024 20:48:25 +0100
Subject: [PATCH 47/62] Reduce nesting level

---
 .../UseDesignatedInitializersCheck.cpp        | 59 ++++++++++---------
 1 file changed, 31 insertions(+), 28 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 273c0ab127f33f..060907e0e07cc9 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -88,38 +88,41 @@ void UseDesignatedInitializersCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *InitList = Result.Nodes.getNodeAs<InitListExpr>("init");
   const auto *Type = Result.Nodes.getNodeAs<CXXRecordDecl>("type");
-  if (!Type || !InitList)
+  if (!Type || !InitList) {
     return;
-  if (const auto *SyntacticInitList = InitList->getSyntacticForm()) {
-    const llvm::DenseMap<clang::SourceLocation, std::string> Designators =
-        clang::tooling::getUnwrittenDesignators(SyntacticInitList);
-    if (isFullyUndesignated(SyntacticInitList)) {
-      if (IgnoreMacros && InitList->getBeginLoc().isMacroID()) {
-        return;
-      }
-      DiagnosticBuilder Diag =
-          diag(InitList->getLBraceLoc(), "use designated initializer list");
-      Diag << InitList->getSourceRange();
-      for (const Stmt *InitExpr : *SyntacticInitList) {
-        Diag << FixItHint::CreateInsertion(
-            InitExpr->getBeginLoc(),
-            Designators.at(InitExpr->getBeginLoc()) + "=");
-      }
+  }
+  const auto *SyntacticInitList = InitList->getSyntacticForm();
+  if (!SyntacticInitList) {
+    return;
+  }
+  const llvm::DenseMap<clang::SourceLocation, std::string> Designators =
+      clang::tooling::getUnwrittenDesignators(SyntacticInitList);
+  if (isFullyUndesignated(SyntacticInitList)) {
+    if (IgnoreMacros && InitList->getBeginLoc().isMacroID()) {
       return;
     }
-    for (const auto *InitExpr : *SyntacticInitList) {
-      if (isa<DesignatedInitExpr>(InitExpr)) {
-        continue;
-      }
-      if (IgnoreMacros && InitExpr->getBeginLoc().isMacroID()) {
-        continue;
-      }
-      diag(InitExpr->getBeginLoc(), "use designated init expression")
-          << InitExpr->getSourceRange()
-          << FixItHint::CreateInsertion(
-                 InitExpr->getBeginLoc(),
-                 Designators.at(InitExpr->getBeginLoc()) + "=");
+    DiagnosticBuilder Diag =
+        diag(InitList->getLBraceLoc(), "use designated initializer list");
+    Diag << InitList->getSourceRange();
+    for (const Stmt *InitExpr : *SyntacticInitList) {
+      Diag << FixItHint::CreateInsertion(
+          InitExpr->getBeginLoc(),
+          Designators.at(InitExpr->getBeginLoc()) + "=");
+    }
+    return;
+  }
+  for (const auto *InitExpr : *SyntacticInitList) {
+    if (isa<DesignatedInitExpr>(InitExpr)) {
+      continue;
+    }
+    if (IgnoreMacros && InitExpr->getBeginLoc().isMacroID()) {
+      continue;
     }
+    diag(InitExpr->getBeginLoc(), "use designated init expression")
+        << InitExpr->getSourceRange()
+        << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
+                                      Designators.at(InitExpr->getBeginLoc()) +
+                                          "=");
   }
 }
 

>From b6fa8bdde58873d69d0b0b0d178d0e4ab379c440 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Thu, 15 Feb 2024 21:52:35 +0100
Subject: [PATCH 48/62] Compute designators lazily and exit/continue early

---
 .../UseDesignatedInitializersCheck.cpp        | 56 ++++++++++++-------
 1 file changed, 36 insertions(+), 20 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 060907e0e07cc9..8daa6e873443f7 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -34,6 +34,12 @@ static constexpr bool IgnoreMacrosDefault = true;
 
 namespace {
 
+unsigned getNumberOfDesignated(const InitListExpr *SyntacticInitList) {
+  return llvm::count_if(*SyntacticInitList, [](auto *InitExpr) {
+    return isa<DesignatedInitExpr>(InitExpr);
+  });
+}
+
 AST_MATCHER(CXXRecordDecl, isAggregate) { return Node.isAggregate(); }
 
 AST_MATCHER(CXXRecordDecl, isPOD) { return Node.isPOD(); }
@@ -41,9 +47,7 @@ AST_MATCHER(CXXRecordDecl, isPOD) { return Node.isPOD(); }
 AST_MATCHER(InitListExpr, isFullyDesignated) {
   if (const InitListExpr *SyntacticForm =
           Node.isSyntacticForm() ? &Node : Node.getSyntacticForm()) {
-    return llvm::all_of(*SyntacticForm, [](auto *InitExpr) {
-      return isa<DesignatedInitExpr>(InitExpr);
-    });
+    return getNumberOfDesignated(SyntacticForm) == SyntacticForm->getNumInits();
   }
   return true;
 }
@@ -78,12 +82,6 @@ void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
       this);
 }
 
-static bool isFullyUndesignated(const InitListExpr *SyntacticInitList) {
-  return llvm::all_of(*SyntacticInitList, [](auto *InitExpr) {
-    return !isa<DesignatedInitExpr>(InitExpr);
-  });
-}
-
 void UseDesignatedInitializersCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *InitList = Result.Nodes.getNodeAs<InitListExpr>("init");
@@ -95,19 +93,33 @@ void UseDesignatedInitializersCheck::check(
   if (!SyntacticInitList) {
     return;
   }
-  const llvm::DenseMap<clang::SourceLocation, std::string> Designators =
-      clang::tooling::getUnwrittenDesignators(SyntacticInitList);
-  if (isFullyUndesignated(SyntacticInitList)) {
+  std::optional<llvm::DenseMap<clang::SourceLocation, std::string>>
+      Designators{};
+  const auto LazyDesignators = [SyntacticInitList, &Designators] {
+    return Designators
+               ? Designators
+               : Designators.emplace(clang::tooling::getUnwrittenDesignators(
+                     SyntacticInitList));
+  };
+  const unsigned NumberOfDesignated = getNumberOfDesignated(SyntacticInitList);
+  if (0 == NumberOfDesignated) {
     if (IgnoreMacros && InitList->getBeginLoc().isMacroID()) {
       return;
     }
+    if (SyntacticInitList->getNumInits() - NumberOfDesignated >
+        LazyDesignators()->size()) {
+      return;
+    }
     DiagnosticBuilder Diag =
         diag(InitList->getLBraceLoc(), "use designated initializer list");
     Diag << InitList->getSourceRange();
     for (const Stmt *InitExpr : *SyntacticInitList) {
-      Diag << FixItHint::CreateInsertion(
-          InitExpr->getBeginLoc(),
-          Designators.at(InitExpr->getBeginLoc()) + "=");
+      const std::string Designator =
+          LazyDesignators()->at(InitExpr->getBeginLoc());
+      if (!Designator.empty()) {
+        Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
+                                           Designator + "=");
+      }
     }
     return;
   }
@@ -118,11 +130,15 @@ void UseDesignatedInitializersCheck::check(
     if (IgnoreMacros && InitExpr->getBeginLoc().isMacroID()) {
       continue;
     }
-    diag(InitExpr->getBeginLoc(), "use designated init expression")
-        << InitExpr->getSourceRange()
-        << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
-                                      Designators.at(InitExpr->getBeginLoc()) +
-                                          "=");
+    DiagnosticBuilder Diag =
+        diag(InitExpr->getBeginLoc(), "use designated init expression");
+    Diag << InitExpr->getSourceRange();
+    const std::string Designator =
+        LazyDesignators()->at(InitExpr->getBeginLoc());
+    if (!Designator.empty()) {
+      Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
+                                         Designator + "=");
+    }
   }
 }
 

>From 6c01ec832e761a126aa47d37245a966105edf290 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Fri, 16 Feb 2024 21:03:35 +0100
Subject: [PATCH 49/62] Point to type to initialize

---
 .../UseDesignatedInitializersCheck.cpp        | 22 +++++-----
 .../modernize/use-designated-initializers.cpp | 40 ++++++++++++++-----
 2 files changed, 43 insertions(+), 19 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 8daa6e873443f7..730687fc5c0dc6 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -110,17 +110,21 @@ void UseDesignatedInitializersCheck::check(
         LazyDesignators()->size()) {
       return;
     }
-    DiagnosticBuilder Diag =
-        diag(InitList->getLBraceLoc(), "use designated initializer list");
-    Diag << InitList->getSourceRange();
-    for (const Stmt *InitExpr : *SyntacticInitList) {
-      const std::string Designator =
-          LazyDesignators()->at(InitExpr->getBeginLoc());
-      if (!Designator.empty()) {
-        Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
-                                           Designator + "=");
+    {
+      DiagnosticBuilder Diag =
+          diag(InitList->getLBraceLoc(), "use designated initializer list");
+      Diag << InitList->getSourceRange();
+      for (const Stmt *InitExpr : *SyntacticInitList) {
+        const std::string Designator =
+            LazyDesignators()->at(InitExpr->getBeginLoc());
+        if (!Designator.empty()) {
+          Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
+                                             Designator + "=");
+        }
       }
     }
+    diag(Type->getBeginLoc(), "this is the type to initialize",
+         DiagnosticIDs::Note);
     return;
   }
   for (const auto *InitExpr : *SyntacticInitList) {
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 832453453c93ad..0d8f288a0a1fe4 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -24,12 +24,16 @@ S2 s21{.i=1, .j =2};
 
 S2 s22 = {1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-2]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-6]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-8]]:1: note: this is the type to initialize
 // CHECK-FIXES: S2 s22 = {.i=1, .j=2};
 
 S2 s23{1};
 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-2]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-13]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-15]]:1: note: this is the type to initialize
 // CHECK-FIXES: S2 s23{.i=1};
 
 S2 s24{.i = 1};
@@ -54,16 +58,20 @@ S3 s31 = {.s2 = 1, 2, 3.1};
 
 S3 s32 = {{.i = 1, 2}};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-2]]:20: warning: use designated init expression [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-4]]:20: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-15]]:1: note: this is the type to initialize
+// CHECK-MESSAGES: :[[@LINE-3]]:20: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-4]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-18]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-6]]:20: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-FIXES: S3 s32 = {.s2={.i = 1, .j=2}};
 
 S3 s33 = {{2}, .d=3.1};
 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use designated init expression [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: use designated initializer list [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-3]]:11: warning: use designated init expression [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-4]]:11: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-50]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-4]]:11: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-5]]:11: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-53]]:1: note: this is the type to initialize
 // CHECK-FIXES: S3 s33 = {.s2={.i=2}, .d=3.1};
 
 struct S4 {
@@ -73,10 +81,12 @@ struct S4 {
 
 S4 s41 {2.2};
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-7]]:1: note: this is the type to initialize
 // CHECK-FIXES-SINGLE-ELEMENT: S4 s41 {.d=2.2};
 
 S4 s42 = {{}};
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-12]]:1: note: this is the type to initialize
 // CHECK-FIXES-SINGLE-ELEMENT: S4 s42 = {.d={}};
 
 template<typename S> S template1() { return {10, 11}; }
@@ -98,7 +108,9 @@ struct S6 {
 
 S6 s61 {1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-2]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-7]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-9]]:1: note: this is the type to initialize
 // CHECK-FIXES: S6 s61 {.i=1, .s.j=2};
 
 struct S7 {
@@ -110,6 +122,7 @@ struct S7 {
 
 S7 s71 {1};
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-9]]:1: note: this is the type to initialize
 // CHECK-FIXES-SINGLE-ELEMENT: S7 s71 {.u.k=1};
 
 struct S8: S7 { int i; };
@@ -123,6 +136,7 @@ struct S9 {
 
 S9 s91{1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-7]]:1: note: this is the type to initialize
 // CHECK-FIXES: S9 s91{.i=1, .j=2};
 
 struct S10 { int i = 1, j = 2; };
@@ -136,6 +150,7 @@ struct S11 { int i; S10 s10; };
 S11 s111 { .i = 1 };
 S11 s112 { 1 };
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-5]]:1: note: this is the type to initialize
 // CHECK-FIXES: S11 s112 { .i=1 };
 
 S11 s113 { .i=1, {}};
@@ -153,7 +168,9 @@ struct S12 {
 
 S12 s121 {1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-2]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-7]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-9]]:1: note: this is the type to initialize
 // CHECK-FIXES: S12 s121 {.i=1, .j=2};
 
 struct S13 {
@@ -166,7 +183,9 @@ struct S13 {
 
 S13 s131 {1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-2]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-10]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-12]]:1: note: this is the type to initialize
 // CHECK-FIXES: S13 s131 {.k=1, .i=2};
 
 #define A (3+2)
@@ -181,3 +200,4 @@ S9 s92 {A, B};
 DECLARE_S93;
 // CHECK-MESSAGES-MACROS: :[[@LINE-1]]:1: warning: use designated initializer list [modernize-use-designated-initializers]
 // CHECK-MESSAGES-MACROS: :[[@LINE-4]]:28: note: expanded from macro 'DECLARE_S93'
+// CHECK-MESSAGES-MACROS: :[[@LINE-71]]:1: note: this is the type to initialize

>From 3fd9bf7119a81c213852bee49ae2f7875443e7b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Fri, 16 Feb 2024 21:39:00 +0100
Subject: [PATCH 50/62] Mention type or field name in diagnostic

---
 .../UseDesignatedInitializersCheck.cpp        | 14 ++--
 .../modernize/use-designated-initializers.cpp | 68 +++++++++----------
 2 files changed, 43 insertions(+), 39 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 730687fc5c0dc6..7745eda692e70e 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -112,7 +112,9 @@ void UseDesignatedInitializersCheck::check(
     }
     {
       DiagnosticBuilder Diag =
-          diag(InitList->getLBraceLoc(), "use designated initializer list");
+          diag(InitList->getLBraceLoc(),
+               "use designated initializer list to initialize %0");
+      Diag << Type->getDeclName();
       Diag << InitList->getSourceRange();
       for (const Stmt *InitExpr : *SyntacticInitList) {
         const std::string Designator =
@@ -134,12 +136,14 @@ void UseDesignatedInitializersCheck::check(
     if (IgnoreMacros && InitExpr->getBeginLoc().isMacroID()) {
       continue;
     }
-    DiagnosticBuilder Diag =
-        diag(InitExpr->getBeginLoc(), "use designated init expression");
-    Diag << InitExpr->getSourceRange();
     const std::string Designator =
         LazyDesignators()->at(InitExpr->getBeginLoc());
-    if (!Designator.empty()) {
+    DiagnosticBuilder Diag =
+        diag(InitExpr->getBeginLoc(),
+             "use designated init expression to initialize field '%0'");
+    Diag << InitExpr->getSourceRange();
+    if (!Designator.empty() && Designator.front() == '.') {
+      Diag << Designator.substr(1); // Strip leading dot
       Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
                                          Designator + "=");
     }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 0d8f288a0a1fe4..924e0fcc29e02e 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -23,24 +23,24 @@ struct S2 { int i, j; };
 S2 s21{.i=1, .j =2};
 
 S2 s22 = {1, 2};
-// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-6]]:1: note: this is the type to initialize
-// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-8]]:1: note: this is the type to initialize
 // CHECK-FIXES: S2 s22 = {.i=1, .j=2};
 
 S2 s23{1};
-// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-13]]:1: note: this is the type to initialize
-// CHECK-MESSAGES-POD: :[[@LINE-3]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:7: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-15]]:1: note: this is the type to initialize
 // CHECK-FIXES: S2 s23{.i=1};
 
 S2 s24{.i = 1};
 
 S2 s25 = {.i=1, 2};
-// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use designated init expression [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-2]]:17: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use designated init expression to initialize field 'j' [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-2]]:17: warning: use designated init expression to initialize field 'j' [modernize-use-designated-initializers]
 // CHECK-FIXES: S2 s25 = {.i=1, .j=2};
 
 class S3 {
@@ -50,27 +50,27 @@ class S3 {
 };
 
 S3 s31 = {.s2 = 1, 2, 3.1};
-// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use designated init expression [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use designated init expression [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-3]]:20: warning: use designated init expression [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-4]]:23: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use designated init expression to initialize field 's2.j' [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use designated init expression to initialize field 'd' [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:20: warning: use designated init expression to initialize field 's2.j' [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-4]]:23: warning: use designated init expression to initialize field 'd' [modernize-use-designated-initializers]
 // CHECK-FIXES: S3 s31 = {.s2 = 1, .s2.j=2, .d=3.1};
 
 S3 s32 = {{.i = 1, 2}};
-// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S3' [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-15]]:1: note: this is the type to initialize
-// CHECK-MESSAGES: :[[@LINE-3]]:20: warning: use designated init expression [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-4]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-3]]:20: warning: use designated init expression to initialize field 'j' [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-4]]:10: warning: use designated initializer list to initialize 'S3' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-18]]:1: note: this is the type to initialize
-// CHECK-MESSAGES-POD: :[[@LINE-6]]:20: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-6]]:20: warning: use designated init expression to initialize field 'j' [modernize-use-designated-initializers]
 // CHECK-FIXES: S3 s32 = {.s2={.i = 1, .j=2}};
 
 S3 s33 = {{2}, .d=3.1};
-// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use designated init expression [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-2]]:11: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use designated init expression to initialize field 's2' [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-2]]:11: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-50]]:1: note: this is the type to initialize
-// CHECK-MESSAGES-POD: :[[@LINE-4]]:11: warning: use designated init expression [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-5]]:11: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-4]]:11: warning: use designated init expression to initialize field 's2' [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-5]]:11: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-53]]:1: note: this is the type to initialize
 // CHECK-FIXES: S3 s33 = {.s2={.i=2}, .d=3.1};
 
@@ -80,12 +80,12 @@ struct S4 {
 };
 
 S4 s41 {2.2};
-// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list to initialize 'S4' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-7]]:1: note: this is the type to initialize
 // CHECK-FIXES-SINGLE-ELEMENT: S4 s41 {.d=2.2};
 
 S4 s42 = {{}};
-// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S4' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-12]]:1: note: this is the type to initialize
 // CHECK-FIXES-SINGLE-ELEMENT: S4 s42 = {.d={}};
 
@@ -107,9 +107,9 @@ struct S6 {
 };
 
 S6 s61 {1, 2};
-// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use designated initializer list to initialize 'S6' [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-7]]:1: note: this is the type to initialize
-// CHECK-MESSAGES-POD: :[[@LINE-3]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:8: warning: use designated initializer list to initialize 'S6' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-9]]:1: note: this is the type to initialize
 // CHECK-FIXES: S6 s61 {.i=1, .s.j=2};
 
@@ -121,7 +121,7 @@ struct S7 {
 };
 
 S7 s71 {1};
-// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list to initialize 'S7' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-9]]:1: note: this is the type to initialize
 // CHECK-FIXES-SINGLE-ELEMENT: S7 s71 {.u.k=1};
 
@@ -135,30 +135,30 @@ struct S9 {
 };
 
 S9 s91{1, 2};
-// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list to initialize 'S9' [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-7]]:1: note: this is the type to initialize
 // CHECK-FIXES: S9 s91{.i=1, .j=2};
 
 struct S10 { int i = 1, j = 2; };
 
 S10 s101 {1, .j=2};
-// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use designated init expression to initialize field 'i' [modernize-use-designated-initializers]
 // CHECK-FIXES: S10 s101 {.i=1, .j=2};
 
 struct S11 { int i; S10 s10; };
 
 S11 s111 { .i = 1 };
 S11 s112 { 1 };
-// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S11' [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-5]]:1: note: this is the type to initialize
 // CHECK-FIXES: S11 s112 { .i=1 };
 
 S11 s113 { .i=1, {}};
-// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use designated init expression to initialize field 's10' [modernize-use-designated-initializers]
 // CHECK-FIXES: S11 s113 { .i=1, .s10={}};
 
 S11 s114 { .i=1, .s10={1, .j=2}};
-// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use designated init expression to initialize field 'i' [modernize-use-designated-initializers]
 // CHECK-FIXES: S11 s114 { .i=1, .s10={.i=1, .j=2}};
 
 struct S12 {
@@ -167,9 +167,9 @@ struct S12 {
 };
 
 S12 s121 {1, 2};
-// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S12' [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-7]]:1: note: this is the type to initialize
-// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list to initialize 'S12' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-9]]:1: note: this is the type to initialize
 // CHECK-FIXES: S12 s121 {.i=1, .j=2};
 
@@ -182,9 +182,9 @@ struct S13 {
 };
 
 S13 s131 {1, 2};
-// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S13' [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-10]]:1: note: this is the type to initialize
-// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list to initialize 'S13' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-12]]:1: note: this is the type to initialize
 // CHECK-FIXES: S13 s131 {.k=1, .i=2};
 
@@ -192,12 +192,12 @@ S13 s131 {1, 2};
 #define B .j=1
 
 S9 s92 {A, B};
-// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:9: warning: use designated init expression [modernize-use-designated-initializers]
+// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:9: warning: use designated init expression to initialize field 'i' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-MACROS: :[[@LINE-5]]:11: note: expanded from macro 'A'
 
 #define DECLARE_S93 S9 s93 {1, 2}
 
 DECLARE_S93;
-// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:1: warning: use designated initializer list [modernize-use-designated-initializers]
+// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:1: warning: use designated initializer list to initialize 'S9' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-MACROS: :[[@LINE-4]]:28: note: expanded from macro 'DECLARE_S93'
 // CHECK-MESSAGES-MACROS: :[[@LINE-71]]:1: note: this is the type to initialize

>From 0e52af4e41a8db0eb36355d911ccfbe2b53d5f9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Sat, 17 Feb 2024 20:25:32 +0100
Subject: [PATCH 51/62] Move designator computation to clang-tidy/utils and
 link it into Clangd

---
 .../modernize/UseDesignatedInitializersCheck.cpp         | 9 ++++-----
 clang-tools-extra/clang-tidy/utils/CMakeLists.txt        | 1 +
 .../clang-tidy/utils}/DesignatedInitializers.cpp         | 8 ++++----
 .../clang-tidy/utils}/DesignatedInitializers.h           | 6 +++---
 clang-tools-extra/clangd/CMakeLists.txt                  | 1 +
 clang-tools-extra/clangd/InlayHints.cpp                  | 4 ++--
 clang-tools-extra/clangd/tool/CMakeLists.txt             | 1 +
 clang-tools-extra/clangd/unittests/CMakeLists.txt        | 1 +
 clang/lib/Tooling/CMakeLists.txt                         | 1 -
 9 files changed, 17 insertions(+), 15 deletions(-)
 rename {clang/lib/Tooling => clang-tools-extra/clang-tidy/utils}/DesignatedInitializers.cpp (97%)
 rename {clang/include/clang/Tooling => clang-tools-extra/clang-tidy/utils}/DesignatedInitializers.h (91%)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 7745eda692e70e..c6f906f0d57eba 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "UseDesignatedInitializersCheck.h"
+#include "../utils/DesignatedInitializers.h"
 #include "clang/AST/APValue.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
@@ -16,7 +17,6 @@
 #include "clang/ASTMatchers/ASTMatchersMacros.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Lex/Lexer.h"
-#include "clang/Tooling/DesignatedInitializers.h"
 
 using namespace clang::ast_matchers;
 
@@ -96,10 +96,9 @@ void UseDesignatedInitializersCheck::check(
   std::optional<llvm::DenseMap<clang::SourceLocation, std::string>>
       Designators{};
   const auto LazyDesignators = [SyntacticInitList, &Designators] {
-    return Designators
-               ? Designators
-               : Designators.emplace(clang::tooling::getUnwrittenDesignators(
-                     SyntacticInitList));
+    return Designators ? Designators
+                       : Designators.emplace(
+                             utils::getUnwrittenDesignators(SyntacticInitList));
   };
   const unsigned NumberOfDesignated = getNumberOfDesignated(SyntacticInitList);
   if (0 == NumberOfDesignated) {
diff --git a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
index 88638d4acd5567..f0160fa9df7487 100644
--- a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
@@ -7,6 +7,7 @@ add_clang_library(clangTidyUtils
   Aliasing.cpp
   ASTUtils.cpp
   DeclRefExprUtils.cpp
+  DesignatedInitializers.cpp
   ExceptionAnalyzer.cpp
   ExceptionSpecAnalyzer.cpp
   ExprSequence.cpp
diff --git a/clang/lib/Tooling/DesignatedInitializers.cpp b/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp
similarity index 97%
rename from clang/lib/Tooling/DesignatedInitializers.cpp
rename to clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp
index 9d8d0a5f4795a7..6faeb7a0b76e19 100644
--- a/clang/lib/Tooling/DesignatedInitializers.cpp
+++ b/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.cpp
@@ -1,4 +1,4 @@
-//===--- DesignatedInitializers.cpp ---------------------------------------===//
+//===--- DesignatedInitializers.cpp - clang-tidy --------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -11,12 +11,12 @@
 ///
 //===----------------------------------------------------------------------===//
 
-#include "clang/Tooling/DesignatedInitializers.h"
+#include "DesignatedInitializers.h"
 #include "clang/AST/DeclCXX.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/ScopeExit.h"
 
-namespace clang::tooling {
+namespace clang::tidy::utils {
 
 namespace {
 
@@ -192,4 +192,4 @@ getUnwrittenDesignators(const InitListExpr *Syn) {
   return Designators;
 }
 
-} // namespace clang::tooling
+} // namespace clang::tidy::utils
diff --git a/clang/include/clang/Tooling/DesignatedInitializers.h b/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.h
similarity index 91%
rename from clang/include/clang/Tooling/DesignatedInitializers.h
rename to clang-tools-extra/clang-tidy/utils/DesignatedInitializers.h
index fa1deeae0791fc..a6cb2963faf72f 100644
--- a/clang/include/clang/Tooling/DesignatedInitializers.h
+++ b/clang-tools-extra/clang-tidy/utils/DesignatedInitializers.h
@@ -1,4 +1,4 @@
-//===--- DesignatedInitializers.h -------------------------------*- C++ -*-===//
+//===--- DesignatedInitializers.h - clang-tidy ------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -15,7 +15,7 @@
 #include "clang/Basic/SourceLocation.h"
 #include "llvm/ADT/DenseMap.h"
 
-namespace clang::tooling {
+namespace clang::tidy::utils {
 
 /// Get designators describing the elements of a (syntactic) init list.
 ///
@@ -39,4 +39,4 @@ namespace clang::tooling {
 llvm::DenseMap<clang::SourceLocation, std::string>
 getUnwrittenDesignators(const clang::InitListExpr *Syn);
 
-} // namespace clang::tooling
+} // namespace clang::tidy::utils
diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt
index 3911fb6c6c746a..f49704157880d3 100644
--- a/clang-tools-extra/clangd/CMakeLists.txt
+++ b/clang-tools-extra/clangd/CMakeLists.txt
@@ -182,6 +182,7 @@ target_link_libraries(clangDaemon
   clangIncludeCleaner
   clangPseudo
   clangTidy
+  clangTidyUtils
 
   clangdSupport
   )
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index c8d3a94affee9d..a0ebc631ef8285 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "InlayHints.h"
+#include "../clang-tidy/utils/DesignatedInitializers.h"
 #include "AST.h"
 #include "Config.h"
 #include "HeuristicResolver.h"
@@ -23,7 +24,6 @@
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/OperatorKinds.h"
 #include "clang/Basic/SourceManager.h"
-#include "clang/Tooling/DesignatedInitializers.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
@@ -692,7 +692,7 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
     if (Syn->isIdiomaticZeroInitializer(AST.getLangOpts()))
       return true;
     llvm::DenseMap<SourceLocation, std::string> Designators =
-        clang::tooling::getUnwrittenDesignators(Syn);
+        tidy::utils::getUnwrittenDesignators(Syn);
     for (const Expr *Init : Syn->inits()) {
       if (llvm::isa<DesignatedInitExpr>(Init))
         continue;
diff --git a/clang-tools-extra/clangd/tool/CMakeLists.txt b/clang-tools-extra/clangd/tool/CMakeLists.txt
index 6c21175d7687c3..4012b6401c0080 100644
--- a/clang-tools-extra/clangd/tool/CMakeLists.txt
+++ b/clang-tools-extra/clangd/tool/CMakeLists.txt
@@ -33,6 +33,7 @@ clang_target_link_libraries(clangdMain
 target_link_libraries(clangdMain
   PRIVATE
   clangTidy
+  clangTidyUtils
 
   clangDaemon
   clangdRemoteIndex
diff --git a/clang-tools-extra/clangd/unittests/CMakeLists.txt b/clang-tools-extra/clangd/unittests/CMakeLists.txt
index 9cd195eaf164fb..e432db8d0912e7 100644
--- a/clang-tools-extra/clangd/unittests/CMakeLists.txt
+++ b/clang-tools-extra/clangd/unittests/CMakeLists.txt
@@ -175,6 +175,7 @@ target_link_libraries(ClangdTests
   clangIncludeCleaner
   clangTesting
   clangTidy
+  clangTidyUtils
   clangdSupport
   )
 
diff --git a/clang/lib/Tooling/CMakeLists.txt b/clang/lib/Tooling/CMakeLists.txt
index 8b0853d9150bb3..aff39e4de13c0b 100644
--- a/clang/lib/Tooling/CMakeLists.txt
+++ b/clang/lib/Tooling/CMakeLists.txt
@@ -106,7 +106,6 @@ add_clang_library(clangTooling
   ArgumentsAdjusters.cpp
   CommonOptionsParser.cpp
   CompilationDatabase.cpp
-  DesignatedInitializers.cpp
   Execution.cpp
   ExpandResponseFilesCompilationDatabase.cpp
   FileMatchTrie.cpp

>From 9877fa8e5f81d738239e3a18c2a6abd0a034f22d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Tue, 20 Feb 2024 20:02:53 +0100
Subject: [PATCH 52/62] Return without block

---
 .../UseDesignatedInitializersCheck.cpp        | 24 +++++++------------
 1 file changed, 8 insertions(+), 16 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index c6f906f0d57eba..3f70699b860392 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -46,9 +46,8 @@ AST_MATCHER(CXXRecordDecl, isPOD) { return Node.isPOD(); }
 
 AST_MATCHER(InitListExpr, isFullyDesignated) {
   if (const InitListExpr *SyntacticForm =
-          Node.isSyntacticForm() ? &Node : Node.getSyntacticForm()) {
+          Node.isSyntacticForm() ? &Node : Node.getSyntacticForm())
     return getNumberOfDesignated(SyntacticForm) == SyntacticForm->getNumInits();
-  }
   return true;
 }
 
@@ -86,13 +85,11 @@ void UseDesignatedInitializersCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *InitList = Result.Nodes.getNodeAs<InitListExpr>("init");
   const auto *Type = Result.Nodes.getNodeAs<CXXRecordDecl>("type");
-  if (!Type || !InitList) {
+  if (!Type || !InitList)
     return;
-  }
   const auto *SyntacticInitList = InitList->getSyntacticForm();
-  if (!SyntacticInitList) {
+  if (!SyntacticInitList)
     return;
-  }
   std::optional<llvm::DenseMap<clang::SourceLocation, std::string>>
       Designators{};
   const auto LazyDesignators = [SyntacticInitList, &Designators] {
@@ -102,13 +99,11 @@ void UseDesignatedInitializersCheck::check(
   };
   const unsigned NumberOfDesignated = getNumberOfDesignated(SyntacticInitList);
   if (0 == NumberOfDesignated) {
-    if (IgnoreMacros && InitList->getBeginLoc().isMacroID()) {
+    if (IgnoreMacros && InitList->getBeginLoc().isMacroID())
       return;
-    }
     if (SyntacticInitList->getNumInits() - NumberOfDesignated >
-        LazyDesignators()->size()) {
+        LazyDesignators()->size())
       return;
-    }
     {
       DiagnosticBuilder Diag =
           diag(InitList->getLBraceLoc(),
@@ -118,10 +113,9 @@ void UseDesignatedInitializersCheck::check(
       for (const Stmt *InitExpr : *SyntacticInitList) {
         const std::string Designator =
             LazyDesignators()->at(InitExpr->getBeginLoc());
-        if (!Designator.empty()) {
+        if (!Designator.empty())
           Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
                                              Designator + "=");
-        }
       }
     }
     diag(Type->getBeginLoc(), "this is the type to initialize",
@@ -129,12 +123,10 @@ void UseDesignatedInitializersCheck::check(
     return;
   }
   for (const auto *InitExpr : *SyntacticInitList) {
-    if (isa<DesignatedInitExpr>(InitExpr)) {
+    if (isa<DesignatedInitExpr>(InitExpr))
       continue;
-    }
-    if (IgnoreMacros && InitExpr->getBeginLoc().isMacroID()) {
+    if (IgnoreMacros && InitExpr->getBeginLoc().isMacroID())
       continue;
-    }
     const std::string Designator =
         LazyDesignators()->at(InitExpr->getBeginLoc());
     DiagnosticBuilder Diag =

>From 4a1ee88bccc4ed183faa2f88c2b3431c5b510479 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Tue, 20 Feb 2024 20:14:09 +0100
Subject: [PATCH 53/62] Have safety check for both cases

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 3f70699b860392..2338e7a705ace9 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -98,12 +98,12 @@ void UseDesignatedInitializersCheck::check(
                              utils::getUnwrittenDesignators(SyntacticInitList));
   };
   const unsigned NumberOfDesignated = getNumberOfDesignated(SyntacticInitList);
+  if (SyntacticInitList->getNumInits() - NumberOfDesignated >
+      LazyDesignators()->size())
+    return;
   if (0 == NumberOfDesignated) {
     if (IgnoreMacros && InitList->getBeginLoc().isMacroID())
       return;
-    if (SyntacticInitList->getNumInits() - NumberOfDesignated >
-        LazyDesignators()->size())
-      return;
     {
       DiagnosticBuilder Diag =
           diag(InitList->getLBraceLoc(),

>From 45276cd56e83d3455ce8b797ef33bfeacba56ec7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Tue, 20 Feb 2024 20:21:01 +0100
Subject: [PATCH 54/62] Prefer references to avoid performance issues

---
 .../modernize/UseDesignatedInitializersCheck.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 2338e7a705ace9..d1e3819c10d8ba 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -92,14 +92,14 @@ void UseDesignatedInitializersCheck::check(
     return;
   std::optional<llvm::DenseMap<clang::SourceLocation, std::string>>
       Designators{};
-  const auto LazyDesignators = [SyntacticInitList, &Designators] {
-    return Designators ? Designators
+  const auto LazyDesignators = [SyntacticInitList, &Designators]() -> auto & {
+    return Designators ? *Designators
                        : Designators.emplace(
                              utils::getUnwrittenDesignators(SyntacticInitList));
   };
   const unsigned NumberOfDesignated = getNumberOfDesignated(SyntacticInitList);
   if (SyntacticInitList->getNumInits() - NumberOfDesignated >
-      LazyDesignators()->size())
+      LazyDesignators().size())
     return;
   if (0 == NumberOfDesignated) {
     if (IgnoreMacros && InitList->getBeginLoc().isMacroID())
@@ -111,8 +111,8 @@ void UseDesignatedInitializersCheck::check(
       Diag << Type->getDeclName();
       Diag << InitList->getSourceRange();
       for (const Stmt *InitExpr : *SyntacticInitList) {
-        const std::string Designator =
-            LazyDesignators()->at(InitExpr->getBeginLoc());
+        const std::string &Designator =
+            LazyDesignators().at(InitExpr->getBeginLoc());
         if (!Designator.empty())
           Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
                                              Designator + "=");
@@ -127,14 +127,14 @@ void UseDesignatedInitializersCheck::check(
       continue;
     if (IgnoreMacros && InitExpr->getBeginLoc().isMacroID())
       continue;
-    const std::string Designator =
-        LazyDesignators()->at(InitExpr->getBeginLoc());
+    const std::string &Designator =
+        LazyDesignators().at(InitExpr->getBeginLoc());
     DiagnosticBuilder Diag =
         diag(InitExpr->getBeginLoc(),
              "use designated init expression to initialize field '%0'");
     Diag << InitExpr->getSourceRange();
     if (!Designator.empty() && Designator.front() == '.') {
-      Diag << Designator.substr(1); // Strip leading dot
+      Diag << StringRef(Designator).substr(1); // Strip leading dot
       Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
                                          Designator + "=");
     }

>From 865c2aadd405a3b137de55497a2770ad95b91296 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Tue, 20 Feb 2024 20:22:20 +0100
Subject: [PATCH 55/62] Refer to type only

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index d1e3819c10d8ba..946197643f4c6e 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -108,7 +108,7 @@ void UseDesignatedInitializersCheck::check(
       DiagnosticBuilder Diag =
           diag(InitList->getLBraceLoc(),
                "use designated initializer list to initialize %0");
-      Diag << Type->getDeclName();
+      Diag << Type;
       Diag << InitList->getSourceRange();
       for (const Stmt *InitExpr : *SyntacticInitList) {
         const std::string &Designator =

>From f0dd7f31f8992f6c84f60efc7f1f3b5e00bf3688 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Tue, 20 Feb 2024 20:23:47 +0100
Subject: [PATCH 56/62] Improve type hint

---
 .../UseDesignatedInitializersCheck.cpp        |  2 +-
 .../modernize/use-designated-initializers.cpp | 40 +++++++++----------
 2 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 946197643f4c6e..fab2366c5ba8a2 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -118,7 +118,7 @@ void UseDesignatedInitializersCheck::check(
                                              Designator + "=");
       }
     }
-    diag(Type->getBeginLoc(), "this is the type to initialize",
+    diag(Type->getBeginLoc(), "aggregate type is defined here",
          DiagnosticIDs::Note);
     return;
   }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 924e0fcc29e02e..57dbc739dcb422 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -24,16 +24,16 @@ S2 s21{.i=1, .j =2};
 
 S2 s22 = {1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-6]]:1: note: this is the type to initialize
+// CHECK-MESSAGES: :[[@LINE-6]]:1: note: aggregate type is defined here
 // CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-8]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-8]]:1: note: aggregate type is defined here
 // CHECK-FIXES: S2 s22 = {.i=1, .j=2};
 
 S2 s23{1};
 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-13]]:1: note: this is the type to initialize
+// CHECK-MESSAGES: :[[@LINE-13]]:1: note: aggregate type is defined here
 // CHECK-MESSAGES-POD: :[[@LINE-3]]:7: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-15]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-15]]:1: note: aggregate type is defined here
 // CHECK-FIXES: S2 s23{.i=1};
 
 S2 s24{.i = 1};
@@ -58,20 +58,20 @@ S3 s31 = {.s2 = 1, 2, 3.1};
 
 S3 s32 = {{.i = 1, 2}};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S3' [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-15]]:1: note: this is the type to initialize
+// CHECK-MESSAGES: :[[@LINE-15]]:1: note: aggregate type is defined here
 // CHECK-MESSAGES: :[[@LINE-3]]:20: warning: use designated init expression to initialize field 'j' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-4]]:10: warning: use designated initializer list to initialize 'S3' [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-18]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-18]]:1: note: aggregate type is defined here
 // CHECK-MESSAGES-POD: :[[@LINE-6]]:20: warning: use designated init expression to initialize field 'j' [modernize-use-designated-initializers]
 // CHECK-FIXES: S3 s32 = {.s2={.i = 1, .j=2}};
 
 S3 s33 = {{2}, .d=3.1};
 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use designated init expression to initialize field 's2' [modernize-use-designated-initializers]
 // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-50]]:1: note: this is the type to initialize
+// CHECK-MESSAGES: :[[@LINE-50]]:1: note: aggregate type is defined here
 // CHECK-MESSAGES-POD: :[[@LINE-4]]:11: warning: use designated init expression to initialize field 's2' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-POD: :[[@LINE-5]]:11: warning: use designated initializer list to initialize 'S2' [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-53]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-53]]:1: note: aggregate type is defined here
 // CHECK-FIXES: S3 s33 = {.s2={.i=2}, .d=3.1};
 
 struct S4 {
@@ -81,12 +81,12 @@ struct S4 {
 
 S4 s41 {2.2};
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list to initialize 'S4' [modernize-use-designated-initializers]
-// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-7]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-7]]:1: note: aggregate type is defined here
 // CHECK-FIXES-SINGLE-ELEMENT: S4 s41 {.d=2.2};
 
 S4 s42 = {{}};
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S4' [modernize-use-designated-initializers]
-// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-12]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-12]]:1: note: aggregate type is defined here
 // CHECK-FIXES-SINGLE-ELEMENT: S4 s42 = {.d={}};
 
 template<typename S> S template1() { return {10, 11}; }
@@ -108,9 +108,9 @@ struct S6 {
 
 S6 s61 {1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use designated initializer list to initialize 'S6' [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-7]]:1: note: this is the type to initialize
+// CHECK-MESSAGES: :[[@LINE-7]]:1: note: aggregate type is defined here
 // CHECK-MESSAGES-POD: :[[@LINE-3]]:8: warning: use designated initializer list to initialize 'S6' [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-9]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-9]]:1: note: aggregate type is defined here
 // CHECK-FIXES: S6 s61 {.i=1, .s.j=2};
 
 struct S7 {
@@ -122,7 +122,7 @@ struct S7 {
 
 S7 s71 {1};
 // CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list to initialize 'S7' [modernize-use-designated-initializers]
-// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-9]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-9]]:1: note: aggregate type is defined here
 // CHECK-FIXES-SINGLE-ELEMENT: S7 s71 {.u.k=1};
 
 struct S8: S7 { int i; };
@@ -136,7 +136,7 @@ struct S9 {
 
 S9 s91{1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list to initialize 'S9' [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-7]]:1: note: this is the type to initialize
+// CHECK-MESSAGES: :[[@LINE-7]]:1: note: aggregate type is defined here
 // CHECK-FIXES: S9 s91{.i=1, .j=2};
 
 struct S10 { int i = 1, j = 2; };
@@ -150,7 +150,7 @@ struct S11 { int i; S10 s10; };
 S11 s111 { .i = 1 };
 S11 s112 { 1 };
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S11' [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-5]]:1: note: this is the type to initialize
+// CHECK-MESSAGES: :[[@LINE-5]]:1: note: aggregate type is defined here
 // CHECK-FIXES: S11 s112 { .i=1 };
 
 S11 s113 { .i=1, {}};
@@ -168,9 +168,9 @@ struct S12 {
 
 S12 s121 {1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S12' [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-7]]:1: note: this is the type to initialize
+// CHECK-MESSAGES: :[[@LINE-7]]:1: note: aggregate type is defined here
 // CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list to initialize 'S12' [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-9]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-9]]:1: note: aggregate type is defined here
 // CHECK-FIXES: S12 s121 {.i=1, .j=2};
 
 struct S13 {
@@ -183,9 +183,9 @@ struct S13 {
 
 S13 s131 {1, 2};
 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list to initialize 'S13' [modernize-use-designated-initializers]
-// CHECK-MESSAGES: :[[@LINE-10]]:1: note: this is the type to initialize
+// CHECK-MESSAGES: :[[@LINE-10]]:1: note: aggregate type is defined here
 // CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list to initialize 'S13' [modernize-use-designated-initializers]
-// CHECK-MESSAGES-POD: :[[@LINE-12]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-POD: :[[@LINE-12]]:1: note: aggregate type is defined here
 // CHECK-FIXES: S13 s131 {.k=1, .i=2};
 
 #define A (3+2)
@@ -200,4 +200,4 @@ S9 s92 {A, B};
 DECLARE_S93;
 // CHECK-MESSAGES-MACROS: :[[@LINE-1]]:1: warning: use designated initializer list to initialize 'S9' [modernize-use-designated-initializers]
 // CHECK-MESSAGES-MACROS: :[[@LINE-4]]:28: note: expanded from macro 'DECLARE_S93'
-// CHECK-MESSAGES-MACROS: :[[@LINE-71]]:1: note: this is the type to initialize
+// CHECK-MESSAGES-MACROS: :[[@LINE-71]]:1: note: aggregate type is defined here

>From 429f4eae6417818b7419f81bc5adca89b9510e26 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Tue, 20 Feb 2024 20:30:03 +0100
Subject: [PATCH 57/62] Use new option format

---
 .../checkers/modernize/use-designated-initializers.cpp      | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
index 57dbc739dcb422..7e5c26e3f4404a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp
@@ -2,13 +2,13 @@
 // RUN:     -- \
 // RUN:     -- -fno-delayed-template-parsing
 // RUN: %check_clang_tidy -check-suffixes=,SINGLE-ELEMENT -std=c++17 %s modernize-use-designated-initializers %t \
-// RUN:     -- -config="{CheckOptions: [{key: modernize-use-designated-initializers.IgnoreSingleElementAggregates, value: false}]}" \
+// RUN:     -- -config="{CheckOptions: {modernize-use-designated-initializers.IgnoreSingleElementAggregates: false}}" \
 // RUN:     -- -fno-delayed-template-parsing
 // RUN: %check_clang_tidy -check-suffixes=POD -std=c++17 %s modernize-use-designated-initializers %t \
-// RUN:     -- -config="{CheckOptions: [{key: modernize-use-designated-initializers.RestrictToPODTypes, value: true}]}" \
+// RUN:     -- -config="{CheckOptions: {modernize-use-designated-initializers.RestrictToPODTypes: true}}" \
 // RUN:     -- -fno-delayed-template-parsing
 // RUN: %check_clang_tidy -check-suffixes=,MACROS -std=c++17 %s modernize-use-designated-initializers %t \
-// RUN:     -- -config="{CheckOptions: [{key: modernize-use-designated-initializers.IgnoreMacros, value: false}]}" \
+// RUN:     -- -config="{CheckOptions: {modernize-use-designated-initializers.IgnoreMacros: false}}" \
 // RUN:     -- -fno-delayed-template-parsing
 
 struct S1 {};

>From 00a6e51de568a9455b5050381ef88c8d6b3bf025 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Tue, 20 Feb 2024 21:27:27 +0100
Subject: [PATCH 58/62] Extract to class to handle missing elements gracefully

---
 .../UseDesignatedInitializersCheck.cpp        | 53 +++++++++++++------
 1 file changed, 36 insertions(+), 17 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index fab2366c5ba8a2..fd17af557f5c00 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -34,6 +34,34 @@ static constexpr bool IgnoreMacrosDefault = true;
 
 namespace {
 
+struct Designators {
+
+  Designators(const InitListExpr *InitList) : InitList(InitList) {
+    assert(InitList->isSyntacticForm());
+  };
+
+  unsigned size() { return get().size(); }
+
+  std::optional<llvm::StringRef> operator[](const SourceLocation &Location) {
+    const auto Result = get().find(Location);
+    if (Result == get().end())
+      return {};
+    return Result->getSecond();
+  }
+
+private:
+  using LocationToNameMap = llvm::DenseMap<clang::SourceLocation, std::string>;
+
+  std::optional<LocationToNameMap> CachedDesignators;
+  const InitListExpr *InitList;
+
+  LocationToNameMap &get() {
+    return CachedDesignators ? *CachedDesignators
+                             : CachedDesignators.emplace(
+                                   utils::getUnwrittenDesignators(InitList));
+  }
+};
+
 unsigned getNumberOfDesignated(const InitListExpr *SyntacticInitList) {
   return llvm::count_if(*SyntacticInitList, [](auto *InitExpr) {
     return isa<DesignatedInitExpr>(InitExpr);
@@ -90,16 +118,10 @@ void UseDesignatedInitializersCheck::check(
   const auto *SyntacticInitList = InitList->getSyntacticForm();
   if (!SyntacticInitList)
     return;
-  std::optional<llvm::DenseMap<clang::SourceLocation, std::string>>
-      Designators{};
-  const auto LazyDesignators = [SyntacticInitList, &Designators]() -> auto & {
-    return Designators ? *Designators
-                       : Designators.emplace(
-                             utils::getUnwrittenDesignators(SyntacticInitList));
-  };
+  Designators Designators{SyntacticInitList};
   const unsigned NumberOfDesignated = getNumberOfDesignated(SyntacticInitList);
   if (SyntacticInitList->getNumInits() - NumberOfDesignated >
-      LazyDesignators().size())
+      Designators.size())
     return;
   if (0 == NumberOfDesignated) {
     if (IgnoreMacros && InitList->getBeginLoc().isMacroID())
@@ -111,11 +133,9 @@ void UseDesignatedInitializersCheck::check(
       Diag << Type;
       Diag << InitList->getSourceRange();
       for (const Stmt *InitExpr : *SyntacticInitList) {
-        const std::string &Designator =
-            LazyDesignators().at(InitExpr->getBeginLoc());
-        if (!Designator.empty())
+        if (const auto Designator = Designators[InitExpr->getBeginLoc()])
           Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
-                                             Designator + "=");
+                                             (*Designator + "=").str());
       }
     }
     diag(Type->getBeginLoc(), "aggregate type is defined here",
@@ -127,16 +147,15 @@ void UseDesignatedInitializersCheck::check(
       continue;
     if (IgnoreMacros && InitExpr->getBeginLoc().isMacroID())
       continue;
-    const std::string &Designator =
-        LazyDesignators().at(InitExpr->getBeginLoc());
     DiagnosticBuilder Diag =
         diag(InitExpr->getBeginLoc(),
              "use designated init expression to initialize field '%0'");
     Diag << InitExpr->getSourceRange();
-    if (!Designator.empty() && Designator.front() == '.') {
-      Diag << StringRef(Designator).substr(1); // Strip leading dot
+    const auto Designator = Designators[InitExpr->getBeginLoc()];
+    if (Designator && Designator->front() == '.') {
+      Diag << Designator->substr(1); // Strip leading dot
       Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
-                                         Designator + "=");
+                                         (*Designator + "=").str());
     }
   }
 }

>From 6e4435e719871f1719b20f581a725cd2319020d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 21 Feb 2024 07:57:56 +0100
Subject: [PATCH 59/62] Rename and avoid two calls

---
 .../modernize/UseDesignatedInitializersCheck.cpp         | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index fd17af557f5c00..d8ddcda378323c 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -40,11 +40,12 @@ struct Designators {
     assert(InitList->isSyntacticForm());
   };
 
-  unsigned size() { return get().size(); }
+  unsigned size() { return getCached().size(); }
 
   std::optional<llvm::StringRef> operator[](const SourceLocation &Location) {
-    const auto Result = get().find(Location);
-    if (Result == get().end())
+    const auto Designators = getCached();
+    const auto Result = Designators.find(Location);
+    if (Result == Designators.end())
       return {};
     return Result->getSecond();
   }
@@ -55,7 +56,7 @@ struct Designators {
   std::optional<LocationToNameMap> CachedDesignators;
   const InitListExpr *InitList;
 
-  LocationToNameMap &get() {
+  LocationToNameMap &getCached() {
     return CachedDesignators ? *CachedDesignators
                              : CachedDesignators.emplace(
                                    utils::getUnwrittenDesignators(InitList));

>From 6a77257c8d6ac43b1952771d0fa018660492fbc6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 21 Feb 2024 07:58:23 +0100
Subject: [PATCH 60/62] Combine diagnostic details aggregation

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp    | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index d8ddcda378323c..04162a738e21c0 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -131,8 +131,7 @@ void UseDesignatedInitializersCheck::check(
       DiagnosticBuilder Diag =
           diag(InitList->getLBraceLoc(),
                "use designated initializer list to initialize %0");
-      Diag << Type;
-      Diag << InitList->getSourceRange();
+      Diag << Type << InitList->getSourceRange();
       for (const Stmt *InitExpr : *SyntacticInitList) {
         if (const auto Designator = Designators[InitExpr->getBeginLoc()])
           Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),

>From 542459eb719559118400a8b8c574d5008a963730 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 21 Feb 2024 07:58:33 +0100
Subject: [PATCH 61/62] Add some doc

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 04162a738e21c0..4c030ec27f8a62 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -124,6 +124,9 @@ void UseDesignatedInitializersCheck::check(
   if (SyntacticInitList->getNumInits() - NumberOfDesignated >
       Designators.size())
     return;
+
+  // If the whole initializer list is un-designated, issue only one warning and
+  // a single fix-it for the whole expression.
   if (0 == NumberOfDesignated) {
     if (IgnoreMacros && InitList->getBeginLoc().isMacroID())
       return;
@@ -142,6 +145,9 @@ void UseDesignatedInitializersCheck::check(
          DiagnosticIDs::Note);
     return;
   }
+
+  // In case that a only few elements are un-designated (not all as before), the
+  // check offers dedicated issues and fix-its for each of them.
   for (const auto *InitExpr : *SyntacticInitList) {
     if (isa<DesignatedInitExpr>(InitExpr))
       continue;

>From e50677a700aee8fa35ea46cbad0daf76f900cb87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?= <danny.moesch at icloud.com>
Date: Wed, 21 Feb 2024 07:58:51 +0100
Subject: [PATCH 62/62] Make intention clearer

---
 .../clang-tidy/modernize/UseDesignatedInitializersCheck.cpp     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
index 4c030ec27f8a62..5acc83a6cf2c91 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp
@@ -158,7 +158,7 @@ void UseDesignatedInitializersCheck::check(
              "use designated init expression to initialize field '%0'");
     Diag << InitExpr->getSourceRange();
     const auto Designator = Designators[InitExpr->getBeginLoc()];
-    if (Designator && Designator->front() == '.') {
+    if (!Designator->empty() && Designator->front() == '.') {
       Diag << Designator->substr(1); // Strip leading dot
       Diag << FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
                                          (*Designator + "=").str());



More information about the cfe-commits mailing list