3131#include " clang/Sema/SemaHLSL.h"
3232#include " clang/Sema/SemaObjC.h"
3333#include " llvm/ADT/APInt.h"
34+ #include " llvm/ADT/DenseMap.h"
3435#include " llvm/ADT/FoldingSet.h"
3536#include " llvm/ADT/PointerIntPair.h"
37+ #include " llvm/ADT/SmallString.h"
3638#include " llvm/ADT/SmallVector.h"
3739#include " llvm/ADT/StringExtras.h"
3840#include " llvm/Support/ErrorHandling.h"
@@ -3092,6 +3094,65 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
30923094 PrevField = *FI;
30933095 }
30943096
3097+ const auto GenerateDesignatedInitReorderingFixit =
3098+ [&](SemaBase::SemaDiagnosticBuilder &Diag) {
3099+ struct ReorderInfo {
3100+ int Pos{};
3101+ const Expr *InitExpr{};
3102+ };
3103+
3104+ llvm::SmallDenseMap<IdentifierInfo *, int > MemberNameInx{};
3105+ llvm::SmallVector<ReorderInfo, 16 > ReorderedInitExprs{};
3106+
3107+ const auto *CxxRecord =
3108+ IList->getSemanticForm ()->getType ()->getAsCXXRecordDecl ();
3109+
3110+ for (const FieldDecl *Field : CxxRecord->fields ())
3111+ MemberNameInx[Field->getIdentifier ()] = Field->getFieldIndex ();
3112+
3113+ for (const Expr *Init : IList->inits ()) {
3114+ if (const auto *DI =
3115+ dyn_cast_if_present<DesignatedInitExpr>(Init)) {
3116+ // We expect only one Designator
3117+ if (DI->size () != 1 )
3118+ return ;
3119+
3120+ const IdentifierInfo *const FieldName =
3121+ DI->getDesignator (0 )->getFieldName ();
3122+ // In case we have an unknown initializer in the source, not in
3123+ // the record
3124+ if (MemberNameInx.contains (FieldName))
3125+ ReorderedInitExprs.emplace_back (
3126+ ReorderInfo{MemberNameInx.at (FieldName), Init});
3127+ }
3128+ }
3129+
3130+ llvm::sort (ReorderedInitExprs,
3131+ [](const ReorderInfo &A, const ReorderInfo &B) {
3132+ return A.Pos < B.Pos ;
3133+ });
3134+
3135+ llvm::SmallString<128 > FixedInitList{};
3136+ SourceManager &SM = SemaRef.getSourceManager ();
3137+ const LangOptions &LangOpts = SemaRef.getLangOpts ();
3138+
3139+ // In a derived Record, first n base-classes are initialized first.
3140+ // They do not use designated init, so skip them
3141+ const ArrayRef<clang::Expr *> IListInits =
3142+ IList->inits ().drop_front (CxxRecord->getNumBases ());
3143+ // loop over each existing expressions and apply replacement
3144+ for (const auto &[OrigExpr, Repl] :
3145+ llvm::zip (IListInits, ReorderedInitExprs)) {
3146+ CharSourceRange CharRange = CharSourceRange::getTokenRange (
3147+ Repl.InitExpr ->getSourceRange ());
3148+ const StringRef InitText =
3149+ Lexer::getSourceText (CharRange, SM, LangOpts);
3150+
3151+ Diag << FixItHint::CreateReplacement (OrigExpr->getSourceRange (),
3152+ InitText.str ());
3153+ }
3154+ };
3155+
30953156 if (PrevField &&
30963157 PrevField->getFieldIndex () > KnownField->getFieldIndex ()) {
30973158 SemaRef.Diag (DIE->getInit ()->getBeginLoc (),
@@ -3101,9 +3162,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
31013162 unsigned OldIndex = StructuredIndex - 1 ;
31023163 if (StructuredList && OldIndex <= StructuredList->getNumInits ()) {
31033164 if (Expr *PrevInit = StructuredList->getInit (OldIndex)) {
3104- SemaRef.Diag (PrevInit->getBeginLoc (),
3105- diag::note_previous_field_init)
3106- << PrevField << PrevInit->getSourceRange ();
3165+ auto Diag = SemaRef.Diag (PrevInit->getBeginLoc (),
3166+ diag::note_previous_field_init)
3167+ << PrevField << PrevInit->getSourceRange ();
3168+ GenerateDesignatedInitReorderingFixit (Diag);
31073169 }
31083170 }
31093171 }
0 commit comments