Skip to content

Commit bcdb0fd

Browse files
committed
[clang] Add FixItHint for designated init order
1 parent 5a581ac commit bcdb0fd

File tree

1 file changed

+58
-1
lines changed

1 file changed

+58
-1
lines changed

clang/lib/Sema/SemaInit.cpp

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
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,60 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
30923094
PrevField = *FI;
30933095
}
30943096

3097+
const auto GenerateDesignatedInitReorderingFixit = [&]() -> FixItHint {
3098+
struct ReorderInfo {
3099+
int Pos{};
3100+
const Expr *InitExpr{};
3101+
};
3102+
3103+
llvm::SmallDenseMap<IdentifierInfo *, int> MemberNameInx{};
3104+
llvm::SmallVector<ReorderInfo, 16> ReorderedInitExprs{};
3105+
3106+
const auto *CxxRecord =
3107+
IList->getSemanticForm()->getType()->getAsCXXRecordDecl();
3108+
3109+
for (const auto &Field : CxxRecord->fields()) {
3110+
MemberNameInx[Field->getIdentifier()] = Field->getFieldIndex();
3111+
}
3112+
3113+
for (const auto *Init : IList->inits()) {
3114+
if (const auto *DI = dyn_cast_if_present<DesignatedInitExpr>(Init)) {
3115+
// We expect only one Designator
3116+
if (DI->size() != 1)
3117+
return {};
3118+
3119+
const auto *const FieldName = DI->getDesignator(0)->getFieldName();
3120+
// In case we have an unknown initializer in the source, not in the
3121+
// record
3122+
if (MemberNameInx.contains(FieldName))
3123+
ReorderedInitExprs.emplace_back(
3124+
ReorderInfo{MemberNameInx.at(FieldName), Init});
3125+
}
3126+
}
3127+
3128+
llvm::sort(ReorderedInitExprs,
3129+
[](const auto &A, const auto &B) { return A.Pos < B.Pos; });
3130+
3131+
// generate replacement
3132+
llvm::SmallString<128> FixedInitList{};
3133+
SourceManager &SM = SemaRef.getSourceManager();
3134+
const LangOptions &LangOpts = SemaRef.getLangOpts();
3135+
3136+
FixedInitList += "{";
3137+
for (const auto &Item : ReorderedInitExprs) {
3138+
CharSourceRange CharRange =
3139+
CharSourceRange::getTokenRange(Item.InitExpr->getSourceRange());
3140+
const auto InitText =
3141+
Lexer::getSourceText(CharRange, SM, LangOpts) + ", ";
3142+
FixedInitList += InitText.str();
3143+
}
3144+
FixedInitList.pop_back_n(2); // remove trailing comma
3145+
FixedInitList += "}";
3146+
3147+
return FixItHint::CreateReplacement(IList->getSourceRange(),
3148+
FixedInitList);
3149+
};
3150+
30953151
if (PrevField &&
30963152
PrevField->getFieldIndex() > KnownField->getFieldIndex()) {
30973153
SemaRef.Diag(DIE->getInit()->getBeginLoc(),
@@ -3101,9 +3157,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
31013157
unsigned OldIndex = StructuredIndex - 1;
31023158
if (StructuredList && OldIndex <= StructuredList->getNumInits()) {
31033159
if (Expr *PrevInit = StructuredList->getInit(OldIndex)) {
3160+
auto ReorderFixit = GenerateDesignatedInitReorderingFixit();
31043161
SemaRef.Diag(PrevInit->getBeginLoc(),
31053162
diag::note_previous_field_init)
3106-
<< PrevField << PrevInit->getSourceRange();
3163+
<< PrevField << PrevInit->getSourceRange() << ReorderFixit;
31073164
}
31083165
}
31093166
}

0 commit comments

Comments
 (0)