[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
llvm-ci wrote: LLVM Buildbot has detected a new failure on builder `clang-ppc64le-rhel` running on `ppc64le-clang-rhel-test` while building `clang-tools-extra` at step 5 "build-unified-tree". Full details are available at: https://lab.llvm.org/buildbot/#/builders/145/builds/9503 Here is the relevant piece of the build log for the reference ``` Step 5 (build-unified-tree) failure: build (failure) ... 51.038 [1031/33/5575] Building CXX object tools/clang/tools/extra/clangd/refactor/tweaks/CMakeFiles/obj.clangDaemonTweaks.dir/DumpAST.cpp.o 51.071 [1031/32/5576] Building CXX object tools/clang/tools/extra/clangd/tool/CMakeFiles/obj.clangdMain.dir/Check.cpp.o 51.084 [1031/31/5577] Building CXX object tools/clang/tools/extra/clangd/refactor/tweaks/CMakeFiles/obj.clangDaemonTweaks.dir/ExpandMacro.cpp.o 51.085 [1031/30/5578] Building CXX object tools/clang/tools/extra/clang-query/CMakeFiles/obj.clangQuery.dir/Query.cpp.o 51.093 [1031/29/5579] Linking CXX shared library lib/libclangIncludeCleaner.so.22.0git 51.101 [1030/29/5580] Creating library symlink lib/libclangIncludeCleaner.so 51.120 [1030/28/5581] Building CXX object tools/clang/tools/extra/clangd/tool/CMakeFiles/obj.clangdMain.dir/ClangdMain.cpp.o 51.131 [1030/27/5582] Building CXX object tools/clang/tools/extra/clangd/refactor/tweaks/CMakeFiles/obj.clangDaemonTweaks.dir/DefineInline.cpp.o 51.292 [1030/26/5583] Building CXX object tools/clang/tools/extra/clangd/refactor/tweaks/CMakeFiles/obj.clangDaemonTweaks.dir/RemoveUsingNamespace.cpp.o 53.238 [1030/25/5584] Building CXX object tools/clang/tools/extra/clang-reorder-fields/CMakeFiles/obj.clangReorderFields.dir/Designator.cpp.o FAILED: tools/clang/tools/extra/clang-reorder-fields/CMakeFiles/obj.clangReorderFields.dir/Designator.cpp.o ccache /home/buildbots/llvm-external-buildbots/clang.19.1.7/bin/clang++ --gcc-toolchain=/gcc-toolchain/usr -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/build/tools/clang/tools/extra/clang-reorder-fields -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/llvm-project/clang-tools-extra/clang-reorder-fields -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/llvm-project/clang/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/build/tools/clang/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/build/include -I/home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/llvm-project/llvm/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG -std=c++17 -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT tools/clang/tools/extra/clang-reorder-fields/CMakeFiles/obj.clangReorderFields.dir/Designator.cpp.o -MF tools/clang/tools/extra/clang-reorder-fields/CMakeFiles/obj.clangReorderFields.dir/Designator.cpp.o.d -o tools/clang/tools/extra/clang-reorder-fields/CMakeFiles/obj.clangReorderFields.dir/Designator.cpp.o -c /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/llvm-project/clang-tools-extra/clang-reorder-fields/Designator.cpp In file included from /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/llvm-project/clang-tools-extra/clang-reorder-fields/Designator.cpp:15: /home/buildbots/llvm-external-buildbots/workers/ppc64le-clang-rhel-test/clang-ppc64le-rhel/llvm-project/clang-tools-extra/clang-reorder-fields/Designator.h:157:23: error: private field 'ILE' is not used [-Werror,-Wunused-private-field] 157 | const InitListExpr *ILE; | ^ 1 error generated. 53.523 [1030/24/5585] Building CXX object tools/clang/lib/Driver/CMakeFiles/obj.clangDriver.dir/ToolChains/HIPUtility.cpp.o 53.847 [1030/23/5586] Building RISCVGenInstrInfo.inc... 55.328 [1030/22/5587] Building AArch64GenSubtargetInfo.inc... 57.717 [1030/21/5588] Building AArch64GenInstrInfo.inc... 58.620 [1030/20/5589] Building RISCVGenDAGISel.inc... 61.264 [1030/19/5590] Building CXX object lib/CodeGen/AsmPrinter/CMakeFiles/LLVMAsmPrinter.dir/AsmPrinter.cpp.o 61.634 [1030/18/5591] Building CXX object lib/LTO/
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
vvuksanovic wrote: Thanks! https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
github-actions[bot] wrote: @vvuksanovic Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested by our [build bots](https://lab.llvm.org/buildbot/). If there is a problem with a build, you may receive a report in an email or a comment on this PR. Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues. How to do this, and the rest of the post-merge process, is covered in detail [here](https://llvm.org/docs/MyFirstTypoFix.html#myfirsttypofix-issues-after-landing-your-pr). If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of [LLVM development](https://llvm.org/docs/DeveloperPolicy.html#patch-reversion-policy). You can fix your changes and open a new PR to merge them again. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
nikic wrote: Fixed by https://github.com/llvm/llvm-project/commit/c128b8c46f2a3b750c9abcba1e303f92d6531e5f. https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
nikic wrote: ``` Building CXX object tools/clang/tools/extra/clang-reorder-fields/CMakeFiles/obj.clangReorderFields.dir/Designator.cpp.o FAILED: tools/clang/tools/extra/clang-reorder-fields/CMakeFiles/obj.clangReorderFields.dir/Designator.cpp.o sccache /opt/llvm/bin/clang++ -DGTEST_HAS_RTTI=0 -D_DEBUG -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/tools/extra/clang-reorder-fields -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/clang-reorder-fields -I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include -I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -gmlt -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG -std=c++17 -fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT tools/clang/tools/extra/clang-reorder-fields/CMakeFiles/obj.clangReorderFields.dir/Designator.cpp.o -MF tools/clang/tools/extra/clang-reorder-fields/CMakeFiles/obj.clangReorderFields.dir/Designator.cpp.o.d -o tools/clang/tools/extra/clang-reorder-fields/CMakeFiles/obj.clangReorderFields.dir/Designator.cpp.o -c /home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/clang-reorder-fields/Designator.cpp In file included from /home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/clang-reorder-fields/Designator.cpp:15: /home/gha/actions-runner/_work/llvm-project/llvm-project/clang-tools-extra/clang-reorder-fields/Designator.h:157:23: error: private field 'ILE' is not used [-Werror,-Wunused-private-field] 157 | const InitListExpr *ILE; | ^ 1 error generated. ``` https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
https://github.com/alexander-shaposhnikov closed https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
vvuksanovic wrote: Thank you for your patience. Can you please merge? https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
alexander-shaposhnikov wrote: lgtm https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
vvuksanovic wrote: Added `InitializerListExcessElements.c` and `IdiomaticZeroInitializer.c` tests. I can't find test cases for non constant-sized arrays in structs. I would change those checks for asserts, but there might be some way to trigger that, that I didn't think of. Also modified the message to include the location of the problematic initializer list. https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
https://github.com/alexander-shaposhnikov approved this pull request. LGTM (modulo comments) https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -0,0 +1,213 @@
+//===-- tools/extra/clang-reorder-fields/utils/Designator.cpp ---*- 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 contains the definition of the DesignatorIter and Designators
+/// utility classes.
+///
+//===--===//
+
+#include "Designator.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+namespace reorder_fields {
+
+DesignatorIter &DesignatorIter::operator++() {
+ assert(!isFinished() && "Iterator is already finished");
+ switch (Tag) {
+ case STRUCT:
+if (StructIt.Record->isUnion()) {
+ // Union always finishes on first increment.
+ StructIt.Field = StructIt.Record->field_end();
+ Type = QualType();
+ break;
+}
+++StructIt.Field;
+if (StructIt.Field != StructIt.Record->field_end()) {
+ Type = StructIt.Field->getType();
+} else {
+ Type = QualType();
+}
+break;
+ case ARRAY:
+++ArrayIt.Index;
+break;
+ case ARRAY_RANGE:
+ArrayIt.Index = ArrayRangeIt.End + 1;
+ArrayIt.Size = ArrayRangeIt.Size;
+Tag = ARRAY;
+break;
+ }
+ return *this;
+}
+
+bool DesignatorIter::isFinished() {
+ switch (Tag) {
+ case STRUCT:
+return StructIt.Field == StructIt.Record->field_end();
+ case ARRAY:
+return ArrayIt.Index == ArrayIt.Size;
+ case ARRAY_RANGE:
+return ArrayRangeIt.End == ArrayRangeIt.Size;
+ }
+ return false;
+}
+
+Designators::Designators(const Expr *Init, const InitListExpr *ILE,
+ const ASTContext *Context)
+: ILE(ILE), Context(Context) {
+ if (ILE->getType()->isArrayType()) {
+const ConstantArrayType *CAT =
+Context->getAsConstantArrayType(ILE->getType());
+// Only constant size arrays are supported.
+if (!CAT) {
+ DesignatorList.clear();
+ return;
+}
+DesignatorList.push_back(
+{CAT->getElementType(), 0, CAT->getSize().getZExtValue()});
+ } else {
+const RecordDecl *DesignatorRD = ILE->getType()->getAsRecordDecl();
+DesignatorList.push_back({DesignatorRD->field_begin()->getType(),
+ DesignatorRD->field_begin(), DesignatorRD});
+ }
+
+ // If the designator list is empty at this point, then there must be excess
+ // elements in the initializer list. They are not currently supported.
+ if (DesignatorList.empty())
+return;
+
+ if (!enterImplicitInitLists(Init))
+DesignatorList.clear();
+}
+
+Designators::Designators(const DesignatedInitExpr *DIE, const InitListExpr
*ILE,
+ const ASTContext *Context)
+: ILE(ILE), Context(Context) {
+ for (const auto &D : DIE->designators()) {
+if (D.isFieldDesignator()) {
+ RecordDecl *DesignatorRecord = D.getFieldDecl()->getParent();
+ for (auto FieldIt = DesignatorRecord->field_begin();
+ FieldIt != DesignatorRecord->field_end(); ++FieldIt) {
+if (*FieldIt == D.getFieldDecl()) {
+ DesignatorList.push_back(
+ {FieldIt->getType(), FieldIt, DesignatorRecord});
+ break;
+}
+ }
+} else {
+ const QualType CurrentType = DesignatorList.empty()
+ ? ILE->getType()
+ : DesignatorList.back().getType();
+ const ConstantArrayType *CAT =
+ Context->getAsConstantArrayType(CurrentType);
+ if (!CAT) {
+// Non-constant-sized arrays are not supported.
+DesignatorList.clear();
+return;
+ }
+ if (D.isArrayDesignator()) {
+DesignatorList.push_back({CAT->getElementType(),
+ DIE->getArrayIndex(D)
+ ->EvaluateKnownConstInt(*Context)
+ .getZExtValue(),
+ CAT->getSize().getZExtValue()});
+ } else if (D.isArrayRangeDesignator()) {
+DesignatorList.push_back({CAT->getElementType(),
+ DIE->getArrayRangeStart(D)
+ ->EvaluateKnownConstInt(*Context)
+ .getZExtValue(),
+ DIE->getArrayRangeEnd(D)
+ ->EvaluateKnownConstInt(*Context)
+ .getZExtValue(),
+ CAT->getSize().getZExtValue()});
+ } else {
+llvm_unreachable("Unexpected designator kind");
+ }
+}
+ }
+}
+
+bool Designators::advanceToNextField(const Expr *Init) {
+ // Remove all designators that refer to the last field of a struct or final
+
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
alexander-shaposhnikov wrote: p.s. also would be good to add a test with unsupported cases (and check that the file is unchanged for now) https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -0,0 +1,158 @@
+//===-- tools/extra/clang-reorder-fields/utils/Designator.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 contains the declarations of the DesignatorIter and Designators
+/// utility class.
+///
+//===--===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_UTILS_DESIGNATOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_UTILS_DESIGNATOR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+
+namespace clang {
+namespace reorder_fields {
+
+class DesignatorIter {
alexander-shaposhnikov wrote:
1. Would be good to add a class-level comment.
2. I don't have a strong opinion, so up to you, but I'd consider renaming this
class to `Designator`.
Yes, it resembles an iterator, but not really suitable for use with any
standard algorithms, so, perhaps,
we can rename operator++ to advanceToNextElement()
https://github.com/llvm/llvm-project/pull/142150
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
alexander-shaposhnikov wrote: Do you mind adding a test with c++20 designated initializers ? https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
vvuksanovic wrote: Thank you for the suggestions, the code looks cleaner now. I don't see any new comments? https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
alexander-shaposhnikov wrote: I've added a couple of comments, but overall this looks reasonable to me, thank your for your patience https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -289,35 +321,215 @@ static void reorderFieldsInConstructor(
Replacements);
}
+/// Replacement for broken InitListExpr::isExplicit function.
+/// FIXME: Remove when InitListExpr::isExplicit is fixed.
+static bool isImplicitILE(const InitListExpr *ILE, const ASTContext &Context) {
+ // The ILE is implicit if either:
+ // - The left brace loc of the ILE matches the start of first init expression
+ // (for non designated decls)
+ // - The right brace loc of the ILE matches the end of first init expression
+ // (for designated decls)
+ // The first init expression should be taken from the syntactic form, but
+ // since the ILE could be implicit, there might not be a syntactic form.
+ // For that reason we have to check against all init expressions.
+ for (const Expr *Init : ILE->inits()) {
+if (ILE->getLBraceLoc() == Init->getBeginLoc() ||
+ILE->getRBraceLoc() == Init->getEndLoc())
+ return true;
+ }
+ return false;
+}
+
+/// Compares compatible designators according to the new struct order.
+/// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0 if
+/// they are equal.
+static int cmpDesignators(const DesignatorIter &Lhs, const DesignatorIter &Rhs,
+ const ReorderedStruct &Struct) {
+ switch (Lhs.getTag()) {
+ case DesignatorIter::STRUCT:
+assert(Rhs.getTag() == DesignatorIter::STRUCT &&
+ "Incompatible designators");
+assert(Lhs.getStructDecl() == Rhs.getStructDecl() &&
+ "Incompatible structs");
+// Use the new layout for reordered struct.
+if (Struct.Definition == Lhs.getStructDecl()) {
+ return Struct.NewFieldsPositions[Lhs.getStructIter()->getFieldIndex()] -
+ Struct.NewFieldsPositions[Rhs.getStructIter()->getFieldIndex()];
+}
+return Lhs.getStructIter()->getFieldIndex() -
+ Rhs.getStructIter()->getFieldIndex();
+ case DesignatorIter::ARRAY:
+ case DesignatorIter::ARRAY_RANGE:
+// Array designators can be compared to array range designators.
+assert((Rhs.getTag() == DesignatorIter::ARRAY ||
+Rhs.getTag() == DesignatorIter::ARRAY_RANGE) &&
+ "Incompatible designators");
+size_t LhsIdx = Lhs.getTag() == DesignatorIter::ARRAY
+? Lhs.getArrayIndex()
+: Lhs.getArrayRangeStart();
+size_t RhsIdx = Rhs.getTag() == DesignatorIter::ARRAY
+? Rhs.getArrayIndex()
+: Rhs.getArrayRangeStart();
+return LhsIdx - RhsIdx;
+ }
+ llvm_unreachable("Invalid designator tag");
+}
+
+/// Compares compatible designator lists according to the new struct order.
+/// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0 if
+/// they are equal.
+static int cmpDesignatorLists(const Designators &Lhs, const Designators &Rhs,
+ const ReorderedStruct &Reorders) {
+ for (unsigned Idx = 0, Size = std::min(Lhs.size(), Rhs.size()); Idx < Size;
+ ++Idx) {
+int DesignatorComp = cmpDesignators(Lhs[Idx], Rhs[Idx], Reorders);
+// If the current designators are not equal, return the result
+if (DesignatorComp != 0)
+ return DesignatorComp;
+// Otherwise, continue to the next pair.
+ }
+ // If all common designators were equal, compare the sizes of the designator
+ // lists.
+ return Lhs.size() - Rhs.size();
+}
+
+/// Finds the semantic form of the first explicit ancestor of the given
+/// initializer list including itself.
+static const InitListExpr *getExplicitILE(const InitListExpr *ILE,
+ ASTContext &Context) {
+ if (!isImplicitILE(ILE, Context))
+return ILE;
+ const InitListExpr *TopLevelILE = ILE;
+ DynTypedNodeList Parents = Context.getParents(*TopLevelILE);
+ while (!Parents.empty() && Parents.begin()->get()) {
+TopLevelILE = Parents.begin()->get();
+Parents = Context.getParents(*TopLevelILE);
+if (!isImplicitILE(TopLevelILE, Context))
+ break;
+ }
+ if (!TopLevelILE->isSemanticForm()) {
+return TopLevelILE->getSemanticForm();
+ }
+ return TopLevelILE;
+}
+
/// Reorders initializers in the brace initialization of an aggregate.
///
/// At the moment partial initialization is not supported.
/// \returns true on success
static bool reorderFieldsInInitListExpr(
-const InitListExpr *InitListEx, ArrayRef NewFieldsOrder,
-const ASTContext &Context,
+const InitListExpr *InitListEx, const ReorderedStruct &RS,
+ASTContext &Context,
std::map &Replacements) {
assert(InitListEx && "Init list expression is null");
- // We care only about InitListExprs which originate from source code.
- // Implicit InitListExprs are created by the semantic analyzer.
- if (!InitListEx->isExplicit())
+ // Only process semantic forms of initializer lists.
+ if (!InitListEx->isSemanticForm()) {
return true;
- // The method InitListExpr::getSyntacticForm
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
https://github.com/vvuksanovic updated
https://github.com/llvm/llvm-project/pull/142150
>From 69381c74c9c3adf97770cdd2e72f0bd8d862e33c Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic
Date: Tue, 22 Jul 2025 02:50:02 -0700
Subject: [PATCH 1/3] [clang-reorder-fields] Refactor the new order information
Move the new fields order information to a new struct.
---
.../ReorderFieldsAction.cpp | 82 +++
1 file changed, 48 insertions(+), 34 deletions(-)
diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
index ea0207619fb2b..e5bdf9ab5957e 100644
--- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
+++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -81,6 +81,20 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
+public:
+ ReorderedStruct(const RecordDecl *Decl, ArrayRef NewFieldsOrder)
+ : Definition(Decl), NewFieldsOrder(NewFieldsOrder),
+NewFieldsPositions(NewFieldsOrder.size()) {
+for (unsigned I = 0; I < NewFieldsPositions.size(); ++I)
+ NewFieldsPositions[NewFieldsOrder[I]] = I;
+ }
+
+ const RecordDecl *Definition;
+ ArrayRef NewFieldsOrder;
+ SmallVector NewFieldsPositions;
+};
+
// FIXME: error-handling
/// Replaces one range of source code by another.
static void
@@ -194,33 +208,33 @@ static SourceRange getFullFieldSourceRange(const
FieldDecl &Field,
/// different accesses (public/protected/private) is not supported.
/// \returns true on success.
static bool reorderFieldsInDefinition(
-const RecordDecl *Definition, ArrayRef NewFieldsOrder,
-const ASTContext &Context,
+const ReorderedStruct &RS, const ASTContext &Context,
std::map &Replacements) {
- assert(Definition && "Definition is null");
+ assert(RS.Definition && "Definition is null");
SmallVector Fields;
- for (const auto *Field : Definition->fields())
+ for (const auto *Field : RS.Definition->fields())
Fields.push_back(Field);
// Check that the permutation of the fields doesn't change the accesses
- for (const auto *Field : Definition->fields()) {
+ for (const auto *Field : RS.Definition->fields()) {
const auto FieldIndex = Field->getFieldIndex();
-if (Field->getAccess() != Fields[NewFieldsOrder[FieldIndex]]->getAccess())
{
+if (Field->getAccess() !=
+Fields[RS.NewFieldsOrder[FieldIndex]]->getAccess()) {
llvm::errs() << "Currently reordering of fields with different accesses "
"is not supported\n";
return false;
}
}
- for (const auto *Field : Definition->fields()) {
+ for (const auto *Field : RS.Definition->fields()) {
const auto FieldIndex = Field->getFieldIndex();
-if (FieldIndex == NewFieldsOrder[FieldIndex])
+if (FieldIndex == RS.NewFieldsOrder[FieldIndex])
continue;
-addReplacement(
-getFullFieldSourceRange(*Field, Context),
-getFullFieldSourceRange(*Fields[NewFieldsOrder[FieldIndex]], Context),
-Context, Replacements);
+addReplacement(getFullFieldSourceRange(*Field, Context),
+ getFullFieldSourceRange(
+ *Fields[RS.NewFieldsOrder[FieldIndex]], Context),
+ Context, Replacements);
}
return true;
}
@@ -231,7 +245,7 @@ static bool reorderFieldsInDefinition(
/// fields. Thus, we need to ensure that we reorder just the initializers that
/// are present.
static void reorderFieldsInConstructor(
-const CXXConstructorDecl *CtorDecl, ArrayRef NewFieldsOrder,
+const CXXConstructorDecl *CtorDecl, const ReorderedStruct &RS,
ASTContext &Context,
std::map &Replacements) {
assert(CtorDecl && "Constructor declaration is null");
@@ -243,10 +257,6 @@ static void reorderFieldsInConstructor(
// Thus this assert needs to be after the previous checks.
assert(CtorDecl->isThisDeclarationADefinition() && "Not a definition");
- SmallVector NewFieldsPositions(NewFieldsOrder.size());
- for (unsigned i = 0, e = NewFieldsOrder.size(); i < e; ++i)
-NewFieldsPositions[NewFieldsOrder[i]] = i;
-
SmallVector OldWrittenInitializersOrder;
SmallVector NewWrittenInitializersOrder;
for (const auto *Initializer : CtorDecl->inits()) {
@@ -257,8 +267,8 @@ static void reorderFieldsInConstructor(
const FieldDecl *ThisM = Initializer->getMember();
const auto UsedMembers = findMembersUsedInInitExpr(Initializer, Context);
for (const FieldDecl *UM : UsedMembers) {
- if (NewFieldsPositions[UM->getFieldIndex()] >
- NewFieldsPositions[ThisM->getFieldIndex()]) {
+ if (RS.NewFieldsPositions[UM->getFieldIndex()] >
+ RS.NewFieldsPositions[ThisM->getFieldIndex()]) {
DiagnosticsEngine &DiagEngine = Context.getDiagnostics();
auto Description = ("reordering field " + UM->getName() + " after " +
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
https://github.com/alexander-shaposhnikov edited https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
vvuksanovic wrote: Ping https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -81,18 +83,52 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
vvuksanovic wrote:
Okay, I separated the commits.
https://github.com/llvm/llvm-project/pull/142150
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
https://github.com/vvuksanovic updated
https://github.com/llvm/llvm-project/pull/142150
>From 69381c74c9c3adf97770cdd2e72f0bd8d862e33c Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic
Date: Tue, 22 Jul 2025 02:50:02 -0700
Subject: [PATCH 1/2] [clang-reorder-fields] Refactor the new order information
Move the new fields order information to a new struct.
---
.../ReorderFieldsAction.cpp | 82 +++
1 file changed, 48 insertions(+), 34 deletions(-)
diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
index ea0207619fb2b..e5bdf9ab5957e 100644
--- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
+++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -81,6 +81,20 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
+public:
+ ReorderedStruct(const RecordDecl *Decl, ArrayRef NewFieldsOrder)
+ : Definition(Decl), NewFieldsOrder(NewFieldsOrder),
+NewFieldsPositions(NewFieldsOrder.size()) {
+for (unsigned I = 0; I < NewFieldsPositions.size(); ++I)
+ NewFieldsPositions[NewFieldsOrder[I]] = I;
+ }
+
+ const RecordDecl *Definition;
+ ArrayRef NewFieldsOrder;
+ SmallVector NewFieldsPositions;
+};
+
// FIXME: error-handling
/// Replaces one range of source code by another.
static void
@@ -194,33 +208,33 @@ static SourceRange getFullFieldSourceRange(const
FieldDecl &Field,
/// different accesses (public/protected/private) is not supported.
/// \returns true on success.
static bool reorderFieldsInDefinition(
-const RecordDecl *Definition, ArrayRef NewFieldsOrder,
-const ASTContext &Context,
+const ReorderedStruct &RS, const ASTContext &Context,
std::map &Replacements) {
- assert(Definition && "Definition is null");
+ assert(RS.Definition && "Definition is null");
SmallVector Fields;
- for (const auto *Field : Definition->fields())
+ for (const auto *Field : RS.Definition->fields())
Fields.push_back(Field);
// Check that the permutation of the fields doesn't change the accesses
- for (const auto *Field : Definition->fields()) {
+ for (const auto *Field : RS.Definition->fields()) {
const auto FieldIndex = Field->getFieldIndex();
-if (Field->getAccess() != Fields[NewFieldsOrder[FieldIndex]]->getAccess())
{
+if (Field->getAccess() !=
+Fields[RS.NewFieldsOrder[FieldIndex]]->getAccess()) {
llvm::errs() << "Currently reordering of fields with different accesses "
"is not supported\n";
return false;
}
}
- for (const auto *Field : Definition->fields()) {
+ for (const auto *Field : RS.Definition->fields()) {
const auto FieldIndex = Field->getFieldIndex();
-if (FieldIndex == NewFieldsOrder[FieldIndex])
+if (FieldIndex == RS.NewFieldsOrder[FieldIndex])
continue;
-addReplacement(
-getFullFieldSourceRange(*Field, Context),
-getFullFieldSourceRange(*Fields[NewFieldsOrder[FieldIndex]], Context),
-Context, Replacements);
+addReplacement(getFullFieldSourceRange(*Field, Context),
+ getFullFieldSourceRange(
+ *Fields[RS.NewFieldsOrder[FieldIndex]], Context),
+ Context, Replacements);
}
return true;
}
@@ -231,7 +245,7 @@ static bool reorderFieldsInDefinition(
/// fields. Thus, we need to ensure that we reorder just the initializers that
/// are present.
static void reorderFieldsInConstructor(
-const CXXConstructorDecl *CtorDecl, ArrayRef NewFieldsOrder,
+const CXXConstructorDecl *CtorDecl, const ReorderedStruct &RS,
ASTContext &Context,
std::map &Replacements) {
assert(CtorDecl && "Constructor declaration is null");
@@ -243,10 +257,6 @@ static void reorderFieldsInConstructor(
// Thus this assert needs to be after the previous checks.
assert(CtorDecl->isThisDeclarationADefinition() && "Not a definition");
- SmallVector NewFieldsPositions(NewFieldsOrder.size());
- for (unsigned i = 0, e = NewFieldsOrder.size(); i < e; ++i)
-NewFieldsPositions[NewFieldsOrder[i]] = i;
-
SmallVector OldWrittenInitializersOrder;
SmallVector NewWrittenInitializersOrder;
for (const auto *Initializer : CtorDecl->inits()) {
@@ -257,8 +267,8 @@ static void reorderFieldsInConstructor(
const FieldDecl *ThisM = Initializer->getMember();
const auto UsedMembers = findMembersUsedInInitExpr(Initializer, Context);
for (const FieldDecl *UM : UsedMembers) {
- if (NewFieldsPositions[UM->getFieldIndex()] >
- NewFieldsPositions[ThisM->getFieldIndex()]) {
+ if (RS.NewFieldsPositions[UM->getFieldIndex()] >
+ RS.NewFieldsPositions[ThisM->getFieldIndex()]) {
DiagnosticsEngine &DiagEngine = Context.getDiagnostics();
auto Description = ("reordering field " + UM->getName() + " after " +
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -81,18 +83,52 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
legrosbuffle wrote:
> Should I move addReplacement changes there?
Your choice, the idea is mostly to separate the logical and the refactoring
changes to make review easier, we can squash before merge.
https://github.com/llvm/llvm-project/pull/142150
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
alexander-shaposhnikov wrote: apologize for the delay, I'll get back to this PR within a couple of days https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
vvuksanovic wrote: ping @legrosbuffle https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -81,18 +83,52 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
vvuksanovic wrote:
Can you clarify what should I pull to a separate commit? I can create a new
commit for the `ReorderedStruct` changes, before the designator changes. Should
I move `addReplacement` changes there? The new overload would be unused in that
commit.
https://github.com/llvm/llvm-project/pull/142150
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -0,0 +1,256 @@
+//===-- tools/extra/clang-reorder-fields/utils/Designator.cpp ---*- 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 contains the definition of the DesignatorIter and Designators
+/// utility classes.
+///
+//===--===//
+
+#include "Designator.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+namespace reorder_fields {
+
+DesignatorIter::DesignatorIter(const QualType Type,
vvuksanovic wrote:
Done.
https://github.com/llvm/llvm-project/pull/142150
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -0,0 +1,256 @@
+//===-- tools/extra/clang-reorder-fields/utils/Designator.cpp ---*- 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 contains the definition of the DesignatorIter and Designators
+/// utility classes.
+///
+//===--===//
+
+#include "Designator.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+namespace reorder_fields {
+
+DesignatorIter::DesignatorIter(const QualType Type,
+ RecordDecl::field_iterator Field,
+ const RecordDecl *RD)
+: Tag(STRUCT), Type(Type), StructIt({Field, RD}) {}
+
+DesignatorIter::DesignatorIter(const QualType Type, uint64_t Idx, uint64_t
Size)
+: Tag(ARRAY), Type(Type), ArrayIt({Idx, Size}) {}
+
+DesignatorIter::DesignatorIter(const QualType Type, uint64_t Start,
+ uint64_t End, uint64_t Size)
+: Tag(ARRAY_RANGE), Type(Type), ArrayRangeIt({Start, End, Size}) {}
+
+DesignatorIter &DesignatorIter::operator++() {
+ assert(!isFinished() && "Iterator is already finished");
+ switch (Tag) {
+ case STRUCT:
+if (StructIt.Record->isUnion()) {
+ // Union always finishes on first increment.
+ StructIt.Field = StructIt.Record->field_end();
+ Type = QualType();
+ break;
+}
+++StructIt.Field;
+if (StructIt.Field != StructIt.Record->field_end()) {
+ Type = StructIt.Field->getType();
+} else {
+ Type = QualType();
+}
+break;
+ case ARRAY:
+++ArrayIt.Index;
+break;
+ case ARRAY_RANGE:
+ArrayIt.Index = ArrayRangeIt.End + 1;
+ArrayIt.Size = ArrayRangeIt.Size;
+Tag = ARRAY;
+break;
+ }
+ return *this;
+}
+
+bool DesignatorIter::isFinished() {
+ switch (Tag) {
+ case STRUCT:
+return StructIt.Field == StructIt.Record->field_end();
+ case ARRAY:
+return ArrayIt.Index == ArrayIt.Size;
+ case ARRAY_RANGE:
+return ArrayRangeIt.End == ArrayRangeIt.Size;
+ }
+ return false;
+}
+
+DesignatorIter::Kind DesignatorIter::getTag() const { return Tag; }
+
+QualType DesignatorIter::getType() const { return Type; }
+
+RecordDecl::field_iterator &DesignatorIter::getStructIter() {
vvuksanovic wrote:
Done.
https://github.com/llvm/llvm-project/pull/142150
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -289,35 +321,213 @@ static void reorderFieldsInConstructor( Replacements); } +/// Replacement for broken InitListExpr::isExplicit function. +/// TODO: Remove when InitListExpr::isExplicit is fixed. vvuksanovic wrote: Replaced. I can't find an open issue, but there is a comment at that function: `FIXME: This is wrong; InitListExprs created by semantic analysis have valid source locations too!` https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -289,35 +321,213 @@ static void reorderFieldsInConstructor(
Replacements);
}
+/// Replacement for broken InitListExpr::isExplicit function.
+/// TODO: Remove when InitListExpr::isExplicit is fixed.
+static bool isImplicitILE(const InitListExpr *ILE, const ASTContext &Context) {
+ // The ILE is implicit if either:
+ // - The left brace loc of the ILE matches the start of first init expression
+ // (for non designated decls)
+ // - The right brace loc of the ILE matches the end of first init expression
+ // (for designated decls)
+ // The first init expression should be taken from the syntactic form, but
+ // since the ILE could be implicit, there might not be a syntactic form.
+ // For that reason we have to check against all init expressions.
+ for (const Expr *Init : ILE->inits()) {
+if (ILE->getLBraceLoc() == Init->getBeginLoc() ||
+ILE->getRBraceLoc() == Init->getEndLoc())
+ return true;
+ }
+ return false;
+}
+
+/// Compares compatible designators according to the new struct order.
+/// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0 if
+/// they are equal.
+static int cmpDesignators(const DesignatorIter &Lhs, const DesignatorIter &Rhs,
+ const ReorderedStruct &Struct) {
+ if (Lhs.getTag() == DesignatorIter::STRUCT) {
vvuksanovic wrote:
Done.
https://github.com/llvm/llvm-project/pull/142150
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
vvuksanovic wrote: Moved to parent directory. https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
https://github.com/vvuksanovic updated
https://github.com/llvm/llvm-project/pull/142150
>From df2e394f94397bf5d371586703a70b8e9bec1aaa Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic
Date: Fri, 30 May 2025 05:37:06 -0700
Subject: [PATCH 1/3] [clang-reorder-fields] Support designated initializers
Initializer lists with designators, missing elements or omitted braces can now
be rewritten. Any missing designators are added and they get sorted according
to the new order.
```
struct Foo {
int a;
int b;
int c;
};
struct Foo foo = { .a = 1, 2, 3 }
```
when reordering elements to "b,a,c" becomes:
```
struct Foo {
int b;
int a;
int c;
};
struct Foo foo = { .b = 2, .a = 1, .c = 3 }
```
---
.../clang-reorder-fields/CMakeLists.txt | 1 +
.../ReorderFieldsAction.cpp | 309 +++---
.../clang-reorder-fields/utils/Designator.cpp | 256 +++
.../clang-reorder-fields/utils/Designator.h | 118 +++
.../DesignatedInitializerList.c | 31 ++
5 files changed, 667 insertions(+), 48 deletions(-)
create mode 100644 clang-tools-extra/clang-reorder-fields/utils/Designator.cpp
create mode 100644 clang-tools-extra/clang-reorder-fields/utils/Designator.h
create mode 100644
clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c
diff --git a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
index 2fdeb65d89767..dfb28234fd548 100644
--- a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
+++ b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangReorderFields STATIC
+ utils/Designator.cpp
ReorderFieldsAction.cpp
DEPENDS
diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
index ea0207619fb2b..b243723b21a32 100644
--- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
+++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -13,6 +13,7 @@
//===--===//
#include "ReorderFieldsAction.h"
+#include "utils/Designator.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -23,6 +24,7 @@
#include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/ErrorHandling.h"
#include
namespace clang {
@@ -81,7 +83,44 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
+public:
+ ReorderedStruct(const RecordDecl *Decl, ArrayRef NewFieldsOrder)
+ : Definition(Decl), NewFieldsOrder(NewFieldsOrder),
+NewFieldsPositions(NewFieldsOrder.size()) {
+for (unsigned I = 0; I < NewFieldsPositions.size(); ++I)
+ NewFieldsPositions[NewFieldsOrder[I]] = I;
+ }
+
+ const RecordDecl *Definition;
+ ArrayRef NewFieldsOrder;
+ SmallVector NewFieldsPositions;
+};
+
// FIXME: error-handling
+/// Replaces a range of source code by the specified text.
+static void
+addReplacement(SourceRange Old, StringRef New, const ASTContext &Context,
+ std::map &Replacements) {
+ tooling::Replacement R(Context.getSourceManager(),
+ CharSourceRange::getTokenRange(Old), New,
+ Context.getLangOpts());
+ consumeError(Replacements[std::string(R.getFilePath())].add(R));
+}
+
+/// Replaces one range of source code by another and adds a prefix.
+static void
+addReplacement(SourceRange Old, SourceRange New, StringRef Prefix,
+ const ASTContext &Context,
+ std::map &Replacements) {
+ std::string NewText =
+ (Prefix + Lexer::getSourceText(CharSourceRange::getTokenRange(New),
+ Context.getSourceManager(),
+ Context.getLangOpts()))
+ .str();
+ addReplacement(Old, NewText, Context, Replacements);
+}
+
/// Replaces one range of source code by another.
static void
addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context,
@@ -89,10 +128,7 @@ addReplacement(SourceRange Old, SourceRange New, const
ASTContext &Context,
StringRef NewText =
Lexer::getSourceText(CharSourceRange::getTokenRange(New),
Context.getSourceManager(), Context.getLangOpts());
- tooling::Replacement R(Context.getSourceManager(),
- CharSourceRange::getTokenRange(Old), NewText,
- Context.getLangOpts());
- consumeError(Replacements[std::string(R.getFilePath())].add(R));
+ addReplacement(Old, NewText.str(), Context, Replacements);
}
/// Find all member fields used in the given init-list initializer expr
@@ -194,33 +230,33 @@ static SourceRange getFullFieldSourceRange(const
FieldDecl &Field,
/// different accesse
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
https://github.com/vvuksanovic updated
https://github.com/llvm/llvm-project/pull/142150
>From df2e394f94397bf5d371586703a70b8e9bec1aaa Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic
Date: Fri, 30 May 2025 05:37:06 -0700
Subject: [PATCH 1/2] [clang-reorder-fields] Support designated initializers
Initializer lists with designators, missing elements or omitted braces can now
be rewritten. Any missing designators are added and they get sorted according
to the new order.
```
struct Foo {
int a;
int b;
int c;
};
struct Foo foo = { .a = 1, 2, 3 }
```
when reordering elements to "b,a,c" becomes:
```
struct Foo {
int b;
int a;
int c;
};
struct Foo foo = { .b = 2, .a = 1, .c = 3 }
```
---
.../clang-reorder-fields/CMakeLists.txt | 1 +
.../ReorderFieldsAction.cpp | 309 +++---
.../clang-reorder-fields/utils/Designator.cpp | 256 +++
.../clang-reorder-fields/utils/Designator.h | 118 +++
.../DesignatedInitializerList.c | 31 ++
5 files changed, 667 insertions(+), 48 deletions(-)
create mode 100644 clang-tools-extra/clang-reorder-fields/utils/Designator.cpp
create mode 100644 clang-tools-extra/clang-reorder-fields/utils/Designator.h
create mode 100644
clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c
diff --git a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
index 2fdeb65d89767..dfb28234fd548 100644
--- a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
+++ b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangReorderFields STATIC
+ utils/Designator.cpp
ReorderFieldsAction.cpp
DEPENDS
diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
index ea0207619fb2b..b243723b21a32 100644
--- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
+++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -13,6 +13,7 @@
//===--===//
#include "ReorderFieldsAction.h"
+#include "utils/Designator.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -23,6 +24,7 @@
#include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/ErrorHandling.h"
#include
namespace clang {
@@ -81,7 +83,44 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
+public:
+ ReorderedStruct(const RecordDecl *Decl, ArrayRef NewFieldsOrder)
+ : Definition(Decl), NewFieldsOrder(NewFieldsOrder),
+NewFieldsPositions(NewFieldsOrder.size()) {
+for (unsigned I = 0; I < NewFieldsPositions.size(); ++I)
+ NewFieldsPositions[NewFieldsOrder[I]] = I;
+ }
+
+ const RecordDecl *Definition;
+ ArrayRef NewFieldsOrder;
+ SmallVector NewFieldsPositions;
+};
+
// FIXME: error-handling
+/// Replaces a range of source code by the specified text.
+static void
+addReplacement(SourceRange Old, StringRef New, const ASTContext &Context,
+ std::map &Replacements) {
+ tooling::Replacement R(Context.getSourceManager(),
+ CharSourceRange::getTokenRange(Old), New,
+ Context.getLangOpts());
+ consumeError(Replacements[std::string(R.getFilePath())].add(R));
+}
+
+/// Replaces one range of source code by another and adds a prefix.
+static void
+addReplacement(SourceRange Old, SourceRange New, StringRef Prefix,
+ const ASTContext &Context,
+ std::map &Replacements) {
+ std::string NewText =
+ (Prefix + Lexer::getSourceText(CharSourceRange::getTokenRange(New),
+ Context.getSourceManager(),
+ Context.getLangOpts()))
+ .str();
+ addReplacement(Old, NewText, Context, Replacements);
+}
+
/// Replaces one range of source code by another.
static void
addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context,
@@ -89,10 +128,7 @@ addReplacement(SourceRange Old, SourceRange New, const
ASTContext &Context,
StringRef NewText =
Lexer::getSourceText(CharSourceRange::getTokenRange(New),
Context.getSourceManager(), Context.getLangOpts());
- tooling::Replacement R(Context.getSourceManager(),
- CharSourceRange::getTokenRange(Old), NewText,
- Context.getLangOpts());
- consumeError(Replacements[std::string(R.getFilePath())].add(R));
+ addReplacement(Old, NewText.str(), Context, Replacements);
}
/// Find all member fields used in the given init-list initializer expr
@@ -194,33 +230,33 @@ static SourceRange getFullFieldSourceRange(const
FieldDecl &Field,
/// different accesse
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -81,18 +83,52 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
legrosbuffle wrote:
If you can pull out this refactoring (`ReorderedStruct` + `addRepacement`) to a
separate commit that'd be great.
https://github.com/llvm/llvm-project/pull/142150
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -0,0 +1,256 @@
+//===-- tools/extra/clang-reorder-fields/utils/Designator.cpp ---*- 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 contains the definition of the DesignatorIter and Designators
+/// utility classes.
+///
+//===--===//
+
+#include "Designator.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+namespace reorder_fields {
+
+DesignatorIter::DesignatorIter(const QualType Type,
legrosbuffle wrote:
[nit] Inline those three constructors ?
https://github.com/llvm/llvm-project/pull/142150
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -289,35 +321,213 @@ static void reorderFieldsInConstructor( Replacements); } +/// Replacement for broken InitListExpr::isExplicit function. +/// TODO: Remove when InitListExpr::isExplicit is fixed. legrosbuffle wrote: s/TODO/FIXME/ If there and open bug for this ? https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -0,0 +1,256 @@
+//===-- tools/extra/clang-reorder-fields/utils/Designator.cpp ---*- 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 contains the definition of the DesignatorIter and Designators
+/// utility classes.
+///
+//===--===//
+
+#include "Designator.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+namespace reorder_fields {
+
+DesignatorIter::DesignatorIter(const QualType Type,
+ RecordDecl::field_iterator Field,
+ const RecordDecl *RD)
+: Tag(STRUCT), Type(Type), StructIt({Field, RD}) {}
+
+DesignatorIter::DesignatorIter(const QualType Type, uint64_t Idx, uint64_t
Size)
+: Tag(ARRAY), Type(Type), ArrayIt({Idx, Size}) {}
+
+DesignatorIter::DesignatorIter(const QualType Type, uint64_t Start,
+ uint64_t End, uint64_t Size)
+: Tag(ARRAY_RANGE), Type(Type), ArrayRangeIt({Start, End, Size}) {}
+
+DesignatorIter &DesignatorIter::operator++() {
+ assert(!isFinished() && "Iterator is already finished");
+ switch (Tag) {
+ case STRUCT:
+if (StructIt.Record->isUnion()) {
+ // Union always finishes on first increment.
+ StructIt.Field = StructIt.Record->field_end();
+ Type = QualType();
+ break;
+}
+++StructIt.Field;
+if (StructIt.Field != StructIt.Record->field_end()) {
+ Type = StructIt.Field->getType();
+} else {
+ Type = QualType();
+}
+break;
+ case ARRAY:
+++ArrayIt.Index;
+break;
+ case ARRAY_RANGE:
+ArrayIt.Index = ArrayRangeIt.End + 1;
+ArrayIt.Size = ArrayRangeIt.Size;
+Tag = ARRAY;
+break;
+ }
+ return *this;
+}
+
+bool DesignatorIter::isFinished() {
+ switch (Tag) {
+ case STRUCT:
+return StructIt.Field == StructIt.Record->field_end();
+ case ARRAY:
+return ArrayIt.Index == ArrayIt.Size;
+ case ARRAY_RANGE:
+return ArrayRangeIt.End == ArrayRangeIt.Size;
+ }
+ return false;
+}
+
+DesignatorIter::Kind DesignatorIter::getTag() const { return Tag; }
+
+QualType DesignatorIter::getType() const { return Type; }
+
+RecordDecl::field_iterator &DesignatorIter::getStructIter() {
legrosbuffle wrote:
Inline all those ?
https://github.com/llvm/llvm-project/pull/142150
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
legrosbuffle wrote: I would put this in the parent directory, the `utils/` subdir does not bring that much IMO. https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
@@ -289,35 +321,213 @@ static void reorderFieldsInConstructor(
Replacements);
}
+/// Replacement for broken InitListExpr::isExplicit function.
+/// TODO: Remove when InitListExpr::isExplicit is fixed.
+static bool isImplicitILE(const InitListExpr *ILE, const ASTContext &Context) {
+ // The ILE is implicit if either:
+ // - The left brace loc of the ILE matches the start of first init expression
+ // (for non designated decls)
+ // - The right brace loc of the ILE matches the end of first init expression
+ // (for designated decls)
+ // The first init expression should be taken from the syntactic form, but
+ // since the ILE could be implicit, there might not be a syntactic form.
+ // For that reason we have to check against all init expressions.
+ for (const Expr *Init : ILE->inits()) {
+if (ILE->getLBraceLoc() == Init->getBeginLoc() ||
+ILE->getRBraceLoc() == Init->getEndLoc())
+ return true;
+ }
+ return false;
+}
+
+/// Compares compatible designators according to the new struct order.
+/// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0 if
+/// they are equal.
+static int cmpDesignators(const DesignatorIter &Lhs, const DesignatorIter &Rhs,
+ const ReorderedStruct &Struct) {
+ if (Lhs.getTag() == DesignatorIter::STRUCT) {
legrosbuffle wrote:
a `switch` might make this a bit more readable
https://github.com/llvm/llvm-project/pull/142150
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
https://github.com/legrosbuffle commented: Nice ! Conceptually this looks good, only stylistic comments. https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
https://github.com/legrosbuffle edited https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
vvuksanovic wrote: @alexander-shaposhnikov https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
https://github.com/vvuksanovic updated
https://github.com/llvm/llvm-project/pull/142150
>From df2e394f94397bf5d371586703a70b8e9bec1aaa Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic
Date: Fri, 30 May 2025 05:37:06 -0700
Subject: [PATCH] [clang-reorder-fields] Support designated initializers
Initializer lists with designators, missing elements or omitted braces can now
be rewritten. Any missing designators are added and they get sorted according
to the new order.
```
struct Foo {
int a;
int b;
int c;
};
struct Foo foo = { .a = 1, 2, 3 }
```
when reordering elements to "b,a,c" becomes:
```
struct Foo {
int b;
int a;
int c;
};
struct Foo foo = { .b = 2, .a = 1, .c = 3 }
```
---
.../clang-reorder-fields/CMakeLists.txt | 1 +
.../ReorderFieldsAction.cpp | 309 +++---
.../clang-reorder-fields/utils/Designator.cpp | 256 +++
.../clang-reorder-fields/utils/Designator.h | 118 +++
.../DesignatedInitializerList.c | 31 ++
5 files changed, 667 insertions(+), 48 deletions(-)
create mode 100644 clang-tools-extra/clang-reorder-fields/utils/Designator.cpp
create mode 100644 clang-tools-extra/clang-reorder-fields/utils/Designator.h
create mode 100644
clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c
diff --git a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
index 2fdeb65d89767..dfb28234fd548 100644
--- a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
+++ b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangReorderFields STATIC
+ utils/Designator.cpp
ReorderFieldsAction.cpp
DEPENDS
diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
index ea0207619fb2b..b243723b21a32 100644
--- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
+++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -13,6 +13,7 @@
//===--===//
#include "ReorderFieldsAction.h"
+#include "utils/Designator.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -23,6 +24,7 @@
#include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/ErrorHandling.h"
#include
namespace clang {
@@ -81,7 +83,44 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
+public:
+ ReorderedStruct(const RecordDecl *Decl, ArrayRef NewFieldsOrder)
+ : Definition(Decl), NewFieldsOrder(NewFieldsOrder),
+NewFieldsPositions(NewFieldsOrder.size()) {
+for (unsigned I = 0; I < NewFieldsPositions.size(); ++I)
+ NewFieldsPositions[NewFieldsOrder[I]] = I;
+ }
+
+ const RecordDecl *Definition;
+ ArrayRef NewFieldsOrder;
+ SmallVector NewFieldsPositions;
+};
+
// FIXME: error-handling
+/// Replaces a range of source code by the specified text.
+static void
+addReplacement(SourceRange Old, StringRef New, const ASTContext &Context,
+ std::map &Replacements) {
+ tooling::Replacement R(Context.getSourceManager(),
+ CharSourceRange::getTokenRange(Old), New,
+ Context.getLangOpts());
+ consumeError(Replacements[std::string(R.getFilePath())].add(R));
+}
+
+/// Replaces one range of source code by another and adds a prefix.
+static void
+addReplacement(SourceRange Old, SourceRange New, StringRef Prefix,
+ const ASTContext &Context,
+ std::map &Replacements) {
+ std::string NewText =
+ (Prefix + Lexer::getSourceText(CharSourceRange::getTokenRange(New),
+ Context.getSourceManager(),
+ Context.getLangOpts()))
+ .str();
+ addReplacement(Old, NewText, Context, Replacements);
+}
+
/// Replaces one range of source code by another.
static void
addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context,
@@ -89,10 +128,7 @@ addReplacement(SourceRange Old, SourceRange New, const
ASTContext &Context,
StringRef NewText =
Lexer::getSourceText(CharSourceRange::getTokenRange(New),
Context.getSourceManager(), Context.getLangOpts());
- tooling::Replacement R(Context.getSourceManager(),
- CharSourceRange::getTokenRange(Old), NewText,
- Context.getLangOpts());
- consumeError(Replacements[std::string(R.getFilePath())].add(R));
+ addReplacement(Old, NewText.str(), Context, Replacements);
}
/// Find all member fields used in the given init-list initializer expr
@@ -194,33 +230,33 @@ static SourceRange getFullFieldSourceRange(const
FieldDecl &Field,
/// different accesses (p
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
vvuksanovic wrote: @legrosbuffle https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
llvmbot wrote:
@llvm/pr-subscribers-clang-tools-extra
Author: Vladimir Vuksanovic (vvuksanovic)
Changes
Initializer lists with designators, missing elements or omitted braces can now
be rewritten. Any missing designators are added and they get sorted according
to the new order.
```
struct Foo {
int a;
int b;
int c;
};
struct Foo foo = { .a = 1, 2, 3 }
```
when reordering elements to "b,a,c" becomes:
```
struct Foo {
int b;
int a;
int c;
};
struct Foo foo = { .b = 2, .a = 1, .c = 3 }
```
---
Patch is 34.11 KiB, truncated to 20.00 KiB below, full version:
https://github.com/llvm/llvm-project/pull/142150.diff
5 Files Affected:
- (modified) clang-tools-extra/clang-reorder-fields/CMakeLists.txt (+1)
- (modified) clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
(+253-48)
- (added) clang-tools-extra/clang-reorder-fields/utils/Designator.cpp (+256)
- (added) clang-tools-extra/clang-reorder-fields/utils/Designator.h (+118)
- (added)
clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c (+31)
``diff
diff --git a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
index 2fdeb65d89767..dfb28234fd548 100644
--- a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
+++ b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangReorderFields STATIC
+ utils/Designator.cpp
ReorderFieldsAction.cpp
DEPENDS
diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
index ea0207619fb2b..f5961a7dab0c9 100644
--- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
+++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -13,6 +13,7 @@
//===--===//
#include "ReorderFieldsAction.h"
+#include "utils/Designator.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -23,6 +24,7 @@
#include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/ErrorHandling.h"
#include
namespace clang {
@@ -81,7 +83,44 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
+public:
+ ReorderedStruct(const RecordDecl *Decl, ArrayRef NewFieldsOrder)
+ : Definition(Decl), NewFieldsOrder(NewFieldsOrder),
+NewFieldsPositions(NewFieldsOrder.size()) {
+for (unsigned I = 0; I < NewFieldsPositions.size(); ++I)
+ NewFieldsPositions[NewFieldsOrder[I]] = I;
+ }
+
+ const RecordDecl *Definition;
+ ArrayRef NewFieldsOrder;
+ SmallVector NewFieldsPositions;
+};
+
// FIXME: error-handling
+/// Replaces a range of source code by the specified text.
+static void
+addReplacement(SourceRange Old, StringRef New, const ASTContext &Context,
+ std::map &Replacements) {
+ tooling::Replacement R(Context.getSourceManager(),
+ CharSourceRange::getTokenRange(Old), New,
+ Context.getLangOpts());
+ consumeError(Replacements[std::string(R.getFilePath())].add(R));
+}
+
+/// Replaces one range of source code by another and adds a prefix.
+static void
+addReplacement(SourceRange Old, SourceRange New, StringRef Prefix,
+ const ASTContext &Context,
+ std::map &Replacements) {
+ std::string NewText =
+ (Prefix + Lexer::getSourceText(CharSourceRange::getTokenRange(New),
+ Context.getSourceManager(),
+ Context.getLangOpts()))
+ .str();
+ addReplacement(Old, NewText, Context, Replacements);
+}
+
/// Replaces one range of source code by another.
static void
addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context,
@@ -89,10 +128,7 @@ addReplacement(SourceRange Old, SourceRange New, const
ASTContext &Context,
StringRef NewText =
Lexer::getSourceText(CharSourceRange::getTokenRange(New),
Context.getSourceManager(), Context.getLangOpts());
- tooling::Replacement R(Context.getSourceManager(),
- CharSourceRange::getTokenRange(Old), NewText,
- Context.getLangOpts());
- consumeError(Replacements[std::string(R.getFilePath())].add(R));
+ addReplacement(Old, NewText.str(), Context, Replacements);
}
/// Find all member fields used in the given init-list initializer expr
@@ -194,33 +230,33 @@ static SourceRange getFullFieldSourceRange(const
FieldDecl &Field,
/// different accesses (public/protected/private) is not supported.
/// \returns true on success.
static bool reorderFieldsInDefinition(
-const RecordDecl *Definition, ArrayRef NewFieldsOrder,
-const ASTContext &Context,
+const ReorderedStruct &RS, cons
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
github-actions[bot] wrote: Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using `@` followed by their GitHub username. If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the [LLVM GitHub User Guide](https://llvm.org/docs/GitHub.html). You can also ask questions in a comment on this PR, on the [LLVM Discord](https://discord.com/invite/xS7Z362) or on the [forums](https://discourse.llvm.org/). https://github.com/llvm/llvm-project/pull/142150 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-reorder-fields] Support designated initializers (PR #142150)
https://github.com/vvuksanovic created
https://github.com/llvm/llvm-project/pull/142150
Initializer lists with designators, missing elements or omitted braces can now
be rewritten. Any missing designators are added and they get sorted according
to the new order.
```
struct Foo {
int a;
int b;
int c;
};
struct Foo foo = { .a = 1, 2, 3 }
```
when reordering elements to "b,a,c" becomes:
```
struct Foo {
int b;
int a;
int c;
};
struct Foo foo = { .b = 2, .a = 1, .c = 3 }
```
>From 67febc3e5b388d38025a87e7824f5a0e5d6adaaa Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic
Date: Fri, 30 May 2025 05:37:06 -0700
Subject: [PATCH] [clang-reorder-fields] Support designated initializers
Initializer lists with designators, missing elements or omitted braces can now
be rewritten. Any missing designators are added and they get sorted according
to the new order.
```
struct Foo {
int a;
int b;
int c;
};
struct Foo foo = { .a = 1, 2, 3 }
```
when reordering elements to "b,a,c" becomes:
```
struct Foo {
int b;
int a;
int c;
};
struct Foo foo = { .b = 2, .a = 1, .c = 3 }
```
---
.../clang-reorder-fields/CMakeLists.txt | 1 +
.../ReorderFieldsAction.cpp | 301 +++---
.../clang-reorder-fields/utils/Designator.cpp | 256 +++
.../clang-reorder-fields/utils/Designator.h | 118 +++
.../DesignatedInitializerList.c | 31 ++
5 files changed, 659 insertions(+), 48 deletions(-)
create mode 100644 clang-tools-extra/clang-reorder-fields/utils/Designator.cpp
create mode 100644 clang-tools-extra/clang-reorder-fields/utils/Designator.h
create mode 100644
clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c
diff --git a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
index 2fdeb65d89767..dfb28234fd548 100644
--- a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
+++ b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangReorderFields STATIC
+ utils/Designator.cpp
ReorderFieldsAction.cpp
DEPENDS
diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
index ea0207619fb2b..f5961a7dab0c9 100644
--- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
+++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -13,6 +13,7 @@
//===--===//
#include "ReorderFieldsAction.h"
+#include "utils/Designator.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -23,6 +24,7 @@
#include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/ErrorHandling.h"
#include
namespace clang {
@@ -81,7 +83,44 @@ getNewFieldsOrder(const RecordDecl *Definition,
return NewFieldsOrder;
}
+struct ReorderedStruct {
+public:
+ ReorderedStruct(const RecordDecl *Decl, ArrayRef NewFieldsOrder)
+ : Definition(Decl), NewFieldsOrder(NewFieldsOrder),
+NewFieldsPositions(NewFieldsOrder.size()) {
+for (unsigned I = 0; I < NewFieldsPositions.size(); ++I)
+ NewFieldsPositions[NewFieldsOrder[I]] = I;
+ }
+
+ const RecordDecl *Definition;
+ ArrayRef NewFieldsOrder;
+ SmallVector NewFieldsPositions;
+};
+
// FIXME: error-handling
+/// Replaces a range of source code by the specified text.
+static void
+addReplacement(SourceRange Old, StringRef New, const ASTContext &Context,
+ std::map &Replacements) {
+ tooling::Replacement R(Context.getSourceManager(),
+ CharSourceRange::getTokenRange(Old), New,
+ Context.getLangOpts());
+ consumeError(Replacements[std::string(R.getFilePath())].add(R));
+}
+
+/// Replaces one range of source code by another and adds a prefix.
+static void
+addReplacement(SourceRange Old, SourceRange New, StringRef Prefix,
+ const ASTContext &Context,
+ std::map &Replacements) {
+ std::string NewText =
+ (Prefix + Lexer::getSourceText(CharSourceRange::getTokenRange(New),
+ Context.getSourceManager(),
+ Context.getLangOpts()))
+ .str();
+ addReplacement(Old, NewText, Context, Replacements);
+}
+
/// Replaces one range of source code by another.
static void
addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context,
@@ -89,10 +128,7 @@ addReplacement(SourceRange Old, SourceRange New, const
ASTContext &Context,
StringRef NewText =
Lexer::getSourceText(CharSourceRange::getTokenRange(New),
Context.getSourceManager(), Context.getLangOpts());
- tooling::Replacement R(Context.getSourceManager(),
- CharSourceRang
