-
Notifications
You must be signed in to change notification settings - Fork 15.6k
[clang] Add FixItHint for designated init order #172959
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
e745196 to
bcdb0fd
Compare
|
@llvm/pr-subscribers-clang Author: Mythreya Kuricheti (MythreyaK) ChangesGenerates vid.webmFrom issue clangd/clangd#965 (comment) Full diff: https://github.com/llvm/llvm-project/pull/172959.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index cc6ddf568d346..442ff41ddc82c 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -31,8 +31,10 @@
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaObjC.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
@@ -3092,6 +3094,66 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
PrevField = *FI;
}
+ const auto GenerateDesignatedInitReorderingFixit =
+ [&](SemaBase::SemaDiagnosticBuilder &Diags) {
+ struct ReorderInfo {
+ int Pos{};
+ const Expr *InitExpr{};
+ };
+
+ llvm::SmallDenseMap<IdentifierInfo *, int> MemberNameInx{};
+ llvm::SmallVector<ReorderInfo, 16> ReorderedInitExprs{};
+
+ const auto *CxxRecord =
+ IList->getSemanticForm()->getType()->getAsCXXRecordDecl();
+
+ for (const auto &Field : CxxRecord->fields()) {
+ MemberNameInx[Field->getIdentifier()] = Field->getFieldIndex();
+ }
+
+ for (const auto *Init : IList->inits()) {
+ if (const auto *DI =
+ dyn_cast_if_present<DesignatedInitExpr>(Init)) {
+ // We expect only one Designator
+ if (DI->size() != 1)
+ return;
+
+ const auto *const FieldName =
+ DI->getDesignator(0)->getFieldName();
+ // In case we have an unknown initializer in the source, not in
+ // the record
+ if (MemberNameInx.contains(FieldName))
+ ReorderedInitExprs.emplace_back(
+ ReorderInfo{MemberNameInx.at(FieldName), Init});
+ }
+ }
+
+ llvm::sort(ReorderedInitExprs, [](const auto &A, const auto &B) {
+ return A.Pos < B.Pos;
+ });
+
+ llvm::SmallString<128> FixedInitList{};
+ SourceManager &SM = SemaRef.getSourceManager();
+ const LangOptions &LangOpts = SemaRef.getLangOpts();
+
+ // if Record is derived, then the first n base-classes are
+ // initialized first, they cannot be initialized with designated
+ // init, so skip them
+ const auto IListInits =
+ IList->inits().drop_front(CxxRecord->getNumBases());
+ // loop over each existing expression and apply replacement
+ for (const auto &[OrigExpr, Repl] :
+ llvm::zip(IListInits, ReorderedInitExprs)) {
+ CharSourceRange CharRange = CharSourceRange::getTokenRange(
+ Repl.InitExpr->getSourceRange());
+ const auto InitText =
+ Lexer::getSourceText(CharRange, SM, LangOpts);
+
+ Diags << FixItHint::CreateReplacement(OrigExpr->getSourceRange(),
+ InitText.str());
+ }
+ };
+
if (PrevField &&
PrevField->getFieldIndex() > KnownField->getFieldIndex()) {
SemaRef.Diag(DIE->getInit()->getBeginLoc(),
@@ -3101,9 +3163,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
unsigned OldIndex = StructuredIndex - 1;
if (StructuredList && OldIndex <= StructuredList->getNumInits()) {
if (Expr *PrevInit = StructuredList->getInit(OldIndex)) {
- SemaRef.Diag(PrevInit->getBeginLoc(),
- diag::note_previous_field_init)
- << PrevField << PrevInit->getSourceRange();
+ auto Diags = SemaRef.Diag(PrevInit->getBeginLoc(),
+ diag::note_previous_field_init)
+ << PrevField << PrevInit->getSourceRange();
+ GenerateDesignatedInitReorderingFixit(Diags);
}
}
}
diff --git a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
index 1e9c5fa082d07..caadc84cf2e27 100644
--- a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
+++ b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
@@ -6,7 +6,7 @@
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,wmissing,wmissing-designated -Wmissing-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,wmissing -Wmissing-field-initializers -Wno-missing-designated-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
-
+// RUN: %clang_cc1 -std=c++20 -Wreorder-init-list -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
namespace class_with_ctor {
struct A { // cxx20-note 6{{candidate}}
@@ -38,6 +38,8 @@ A a1 = {
.y = 1, // reorder-note {{previous initialization for field 'y' is here}}
.x = 2 // reorder-error {{ISO C++ requires field designators to be specified in declaration order; field 'y' will be initialized after field 'x'}}
};
+// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:9}:".x = 2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:9}:".y = 1"
int arr[3] = {[1] = 5}; // pedantic-error {{array designators are a C99 extension}}
B b = {.a.x = 0}; // pedantic-error {{nested designators are a C99 extension}}
A a2 = {
@@ -71,6 +73,12 @@ C c = {
.x = 1, // reorder-error {{declaration order}} override-error {{overrides prior initialization}} override-note {{previous}}
.x = 1, // override-error {{overrides prior initialization}}
};
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".y = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".y = 1"
struct Foo { int a, b; };
@@ -118,6 +126,8 @@ namespace overload_resolution {
void i() {
h({.x = 1, .y = 2});
h({.y = 1, .x = 2}); // reorder-error {{declaration order}} reorder-note {{previous}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:8-[[@LINE-1]]:14}:".x = 2"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:22}:".y = 1"
h({.x = 1}); // expected-error {{ambiguous}}
}
@@ -228,6 +238,16 @@ struct : public A, public B {
.a = 1, // reorder-error {{field 'b' will be initialized after field 'a'}}
};
}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-17]]:4-[[@LINE-17]]:8}:".x=2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-15]]:4-[[@LINE-15]]:8}:".y=1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".z=0"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".a=4"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".b=3"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:5-[[@LINE-14]]:11}:".a = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-13]]:5-[[@LINE-13]]:11}:".b = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".c = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".d = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".e = 1"
namespace GH63759 {
struct C {
@@ -248,3 +268,39 @@ void foo() {
//
}
}
+
+namespace reorder_derived {
+struct col {
+ int r;
+ int g;
+ int b;
+};
+
+struct point {
+ float x;
+ float y;
+ float z;
+};
+
+struct lols : public col, public point {
+ int z2;
+ int z1;
+};
+
+void fosas() {
+ lols a {
+ {.b = 1, .g = 2, .r = 3},
+ { .z = 1, .y=2, .x = 3 },
+ .z1 = 1,
+ .z2 = 2,
+ };
+}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:6-[[@LINE-6]]:12}:".r = 3"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:14-[[@LINE-7]]:20}:".g = 2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:22-[[@LINE-8]]:28}:".b = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:15-[[@LINE-8]]:19}:".y=2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-9]]:21-[[@LINE-9]]:28}:".z = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:7-[[@LINE-10]]:13}:".x = 3"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:5-[[@LINE-10]]:12}:".z2 = 2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:5-[[@LINE-10]]:12}:".z1 = 1"
+} // namespace reorder_derived
|
🪟 Windows x64 Test Results
Failed Tests(click on a test name to see its output) ClangClang.SemaCXX/cxx2a-initializer-aggregates.cppIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
🐧 Linux x64 Test Results
Failed Tests(click on a test name to see its output) ClangClang.SemaCXX/cxx2a-initializer-aggregates.cppIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
5a9c009 to
a19416b
Compare
a19416b to
b6658b1
Compare
|
Closed in favor of #173136. |
Generates
FixItHintfor reordering incorrectly initialized designated initializers.vid.webm
From issue clangd/clangd#965 (comment)