brintos

brintos / llvm-project-archived public Read only

0
0
Text · 28.7 KiB · 5770bf7 Raw
723 lines · cpp
1//===-- tools/extra/clang-reorder-fields/ReorderFieldsAction.cpp -*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file contains the definition of the11/// ReorderFieldsAction::newASTConsumer method12///13//===----------------------------------------------------------------------===//14 15#include "ReorderFieldsAction.h"16#include "Designator.h"17#include "clang/AST/AST.h"18#include "clang/AST/ASTConsumer.h"19#include "clang/AST/ASTContext.h"20#include "clang/AST/Decl.h"21#include "clang/AST/RecursiveASTVisitor.h"22#include "clang/ASTMatchers/ASTMatchFinder.h"23#include "clang/Basic/LangOptions.h"24#include "clang/Basic/SourceLocation.h"25#include "clang/Lex/Lexer.h"26#include "clang/Tooling/Refactoring.h"27#include "llvm/ADT/STLExtras.h"28#include "llvm/ADT/SetVector.h"29#include "llvm/Support/ErrorHandling.h"30#include <string>31 32namespace clang {33namespace reorder_fields {34using namespace clang::ast_matchers;35using llvm::SmallSetVector;36 37/// Finds the definition of a record by name.38///39/// \returns nullptr if the name is ambiguous or not found.40static const RecordDecl *findDefinition(StringRef RecordName,41                                        ASTContext &Context) {42  auto Results =43      match(recordDecl(hasName(RecordName), isDefinition()).bind("recordDecl"),44            Context);45  if (Results.empty()) {46    llvm::errs() << "Definition of " << RecordName << "  not found\n";47    return nullptr;48  }49  if (Results.size() > 1) {50    llvm::errs() << "The name " << RecordName51                 << " is ambiguous, several definitions found\n";52    return nullptr;53  }54  return selectFirst<RecordDecl>("recordDecl", Results);55}56 57static bool declaresMultipleFieldsInStatement(const RecordDecl *Decl) {58  SourceLocation LastTypeLoc;59  for (const auto &Field : Decl->fields()) {60    SourceLocation TypeLoc =61        Field->getTypeSourceInfo()->getTypeLoc().getBeginLoc();62    if (LastTypeLoc.isValid() && TypeLoc == LastTypeLoc)63      return true;64    LastTypeLoc = TypeLoc;65  }66  return false;67}68 69static bool declaresMultipleFieldsInMacro(const RecordDecl *Decl,70                                          const SourceManager &SrcMgr) {71  SourceLocation LastMacroLoc;72  for (const auto &Field : Decl->fields()) {73    if (!Field->getLocation().isMacroID())74      continue;75    SourceLocation MacroLoc = SrcMgr.getExpansionLoc(Field->getLocation());76    if (LastMacroLoc.isValid() && MacroLoc == LastMacroLoc)77      return true;78    LastMacroLoc = MacroLoc;79  }80  return false;81}82 83static bool containsPreprocessorDirectives(const RecordDecl *Decl,84                                           const SourceManager &SrcMgr,85                                           const LangOptions &LangOpts) {86  std::pair<FileID, unsigned> FileAndOffset =87      SrcMgr.getDecomposedLoc(Decl->field_begin()->getBeginLoc());88  assert(!Decl->field_empty());89  auto LastField = Decl->field_begin();90  while (std::next(LastField) != Decl->field_end())91    ++LastField;92  unsigned EndOffset = SrcMgr.getFileOffset(LastField->getEndLoc());93  StringRef SrcBuffer = SrcMgr.getBufferData(FileAndOffset.first);94  Lexer L(SrcMgr.getLocForStartOfFile(FileAndOffset.first), LangOpts,95          SrcBuffer.data(), SrcBuffer.data() + FileAndOffset.second,96          SrcBuffer.data() + SrcBuffer.size());97  IdentifierTable Identifiers(LangOpts);98  clang::Token T;99  while (!L.LexFromRawLexer(T) && L.getCurrentBufferOffset() < EndOffset) {100    if (T.getKind() == tok::hash) {101      L.LexFromRawLexer(T);102      if (T.getKind() == tok::raw_identifier) {103        clang::IdentifierInfo &II = Identifiers.get(T.getRawIdentifier());104        if (II.getPPKeywordID() != clang::tok::pp_not_keyword)105          return true;106      }107    }108  }109  return false;110}111 112static bool isSafeToRewrite(const RecordDecl *Decl, const ASTContext &Context) {113  // All following checks expect at least one field declaration.114  if (Decl->field_empty())115    return true;116 117  // Don't attempt to rewrite if there is a declaration like 'int a, b;'.118  if (declaresMultipleFieldsInStatement(Decl))119    return false;120 121  const SourceManager &SrcMgr = Context.getSourceManager();122 123  // Don't attempt to rewrite if a single macro expansion creates multiple124  // fields.125  if (declaresMultipleFieldsInMacro(Decl, SrcMgr))126    return false;127 128  // Prevent rewriting if there are preprocessor directives present between the129  // start of the first field and the end of last field.130  if (containsPreprocessorDirectives(Decl, SrcMgr, Context.getLangOpts()))131    return false;132 133  return true;134}135 136/// Calculates the new order of fields.137///138/// \returns empty vector if the list of fields doesn't match the definition.139static SmallVector<unsigned, 4>140getNewFieldsOrder(const RecordDecl *Definition,141                  ArrayRef<std::string> DesiredFieldsOrder) {142  assert(Definition && "Definition is null");143 144  llvm::StringMap<unsigned> NameToIndex;145  for (const auto *Field : Definition->fields())146    NameToIndex[Field->getName()] = Field->getFieldIndex();147 148  if (DesiredFieldsOrder.size() != NameToIndex.size()) {149    llvm::errs() << "Number of provided fields (" << DesiredFieldsOrder.size()150                 << ") doesn't match definition (" << NameToIndex.size()151                 << ").\n";152    return {};153  }154  SmallVector<unsigned, 4> NewFieldsOrder;155  for (const auto &Name : DesiredFieldsOrder) {156    auto It = NameToIndex.find(Name);157    if (It == NameToIndex.end()) {158      llvm::errs() << "Field " << Name << " not found in definition.\n";159      return {};160    }161    NewFieldsOrder.push_back(It->second);162  }163  assert(NewFieldsOrder.size() == NameToIndex.size());164  return NewFieldsOrder;165}166 167static bool isOrderValid(const RecordDecl *RD, ArrayRef<unsigned> FieldOrder) {168  if (FieldOrder.empty())169    return false;170 171  // If there is a flexible array member in the struct, it must remain the last172  // field.173  if (RD->hasFlexibleArrayMember() &&174      FieldOrder.back() != FieldOrder.size() - 1) {175    llvm::errs()176        << "Flexible array member must remain the last field in the struct\n";177    return false;178  }179 180  return true;181}182 183struct ReorderedStruct {184public:185  ReorderedStruct(const RecordDecl *Decl, ArrayRef<unsigned> NewFieldsOrder)186      : Definition(Decl), NewFieldsOrder(NewFieldsOrder),187        NewFieldsPositions(NewFieldsOrder.size()) {188    for (unsigned I = 0; I < NewFieldsPositions.size(); ++I)189      NewFieldsPositions[NewFieldsOrder[I]] = I;190  }191 192  /// Compares compatible designators according to the new struct order.193  /// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0194  /// if they are equal.195  bool operator()(const Designator &Lhs, const Designator &Rhs) const;196 197  /// Compares compatible designator lists according to the new struct order.198  /// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0199  /// if they are equal.200  bool operator()(const Designators &Lhs, const Designators &Rhs) const;201 202  const RecordDecl *Definition;203  ArrayRef<unsigned> NewFieldsOrder;204  SmallVector<unsigned, 4> NewFieldsPositions;205};206 207bool ReorderedStruct::operator()(const Designator &Lhs,208                                 const Designator &Rhs) const {209  switch (Lhs.getTag()) {210  case Designator::STRUCT:211    assert(Rhs.getTag() == Designator::STRUCT && "Incompatible designators");212    assert(Lhs.getStructDecl() == Rhs.getStructDecl() &&213           "Incompatible structs");214    // Use the new layout for reordered struct.215    if (Definition == Lhs.getStructDecl()) {216      return NewFieldsPositions[Lhs.getStructIter()->getFieldIndex()] <217             NewFieldsPositions[Rhs.getStructIter()->getFieldIndex()];218    }219    return Lhs.getStructIter()->getFieldIndex() <220           Rhs.getStructIter()->getFieldIndex();221  case Designator::ARRAY:222  case Designator::ARRAY_RANGE:223    // Array designators can be compared to array range designators.224    assert((Rhs.getTag() == Designator::ARRAY ||225            Rhs.getTag() == Designator::ARRAY_RANGE) &&226           "Incompatible designators");227    size_t LhsIdx = Lhs.getTag() == Designator::ARRAY228                        ? Lhs.getArrayIndex()229                        : Lhs.getArrayRangeStart();230    size_t RhsIdx = Rhs.getTag() == Designator::ARRAY231                        ? Rhs.getArrayIndex()232                        : Rhs.getArrayRangeStart();233    return LhsIdx < RhsIdx;234  }235  llvm_unreachable("Invalid designator tag");236}237 238bool ReorderedStruct::operator()(const Designators &Lhs,239                                 const Designators &Rhs) const {240  return std::lexicographical_compare(Lhs.begin(), Lhs.end(), Rhs.begin(),241                                      Rhs.end(), *this);242}243 244// FIXME: error-handling245/// Replaces a range of source code by the specified text.246static void247addReplacement(SourceRange Old, StringRef New, const ASTContext &Context,248               std::map<std::string, tooling::Replacements> &Replacements) {249  tooling::Replacement R(Context.getSourceManager(),250                         CharSourceRange::getTokenRange(Old), New,251                         Context.getLangOpts());252  consumeError(Replacements[std::string(R.getFilePath())].add(R));253}254 255/// Replaces one range of source code by another and adds a prefix.256static void257addReplacement(SourceRange Old, SourceRange New, StringRef Prefix,258               const ASTContext &Context,259               std::map<std::string, tooling::Replacements> &Replacements) {260  std::string NewText =261      (Prefix + Lexer::getSourceText(CharSourceRange::getTokenRange(New),262                                     Context.getSourceManager(),263                                     Context.getLangOpts()))264          .str();265  addReplacement(Old, NewText, Context, Replacements);266}267 268/// Replaces one range of source code by another.269static void270addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context,271               std::map<std::string, tooling::Replacements> &Replacements) {272  if (Old.getBegin().isMacroID())273    Old = Context.getSourceManager().getExpansionRange(Old).getAsRange();274  if (New.getBegin().isMacroID())275    New = Context.getSourceManager().getExpansionRange(New).getAsRange();276  StringRef NewText =277      Lexer::getSourceText(CharSourceRange::getTokenRange(New),278                           Context.getSourceManager(), Context.getLangOpts());279  addReplacement(Old, NewText.str(), Context, Replacements);280}281 282/// Find all member fields used in the given init-list initializer expr283/// that belong to the same record284///285/// \returns a set of field declarations, empty if none were present286static SmallSetVector<FieldDecl *, 1>287findMembersUsedInInitExpr(const CXXCtorInitializer *Initializer,288                          ASTContext &Context) {289  SmallSetVector<FieldDecl *, 1> Results;290  // Note that this does not pick up member fields of base classes since291  // for those accesses Sema::PerformObjectMemberConversion always inserts an292  // UncheckedDerivedToBase ImplicitCastExpr between the this expr and the293  // object expression294  auto FoundExprs = match(295      traverse(296          TK_AsIs,297          findAll(memberExpr(hasObjectExpression(cxxThisExpr())).bind("ME"))),298      *Initializer->getInit(), Context);299  for (BoundNodes &BN : FoundExprs)300    if (auto *MemExpr = BN.getNodeAs<MemberExpr>("ME"))301      if (auto *FD = dyn_cast<FieldDecl>(MemExpr->getMemberDecl()))302        Results.insert(FD);303  return Results;304}305 306/// Returns the start of the leading comments before `Loc`.307static SourceLocation getStartOfLeadingComment(SourceLocation Loc,308                                               const SourceManager &SM,309                                               const LangOptions &LangOpts) {310  // We consider any leading comment token that is on the same line or311  // indented similarly to the first comment to be part of the leading comment.312  const unsigned Line = SM.getPresumedLineNumber(Loc);313  const unsigned Column = SM.getPresumedColumnNumber(Loc);314  std::optional<Token> Tok =315      Lexer::findPreviousToken(Loc, SM, LangOpts, /*IncludeComments=*/true);316  while (Tok && Tok->is(tok::comment)) {317    const SourceLocation CommentLoc =318        Lexer::GetBeginningOfToken(Tok->getLocation(), SM, LangOpts);319    if (SM.getPresumedLineNumber(CommentLoc) != Line &&320        SM.getPresumedColumnNumber(CommentLoc) != Column) {321      break;322    }323    Loc = CommentLoc;324    Tok = Lexer::findPreviousToken(Loc, SM, LangOpts, /*IncludeComments=*/true);325  }326  return Loc;327}328 329/// Returns the end of the trailing comments after `Loc`.330static SourceLocation getEndOfTrailingComment(SourceLocation Loc,331                                              const SourceManager &SM,332                                              const LangOptions &LangOpts) {333  // We consider any following comment token that is indented more than the334  // first comment to be part of the trailing comment.335  const unsigned Column = SM.getPresumedColumnNumber(Loc);336  std::optional<Token> Tok =337      Lexer::findNextToken(Loc, SM, LangOpts, /*IncludeComments=*/true);338  while (Tok && Tok->is(tok::comment) &&339         SM.getPresumedColumnNumber(Tok->getLocation()) > Column) {340    Loc = Tok->getEndLoc();341    Tok = Lexer::findNextToken(Loc, SM, LangOpts, /*IncludeComments=*/true);342  }343  return Loc;344}345 346/// Returns the full source range for the field declaration up to (including)347/// the trailing semicolumn, including potential macro invocations,348/// e.g. `int a GUARDED_BY(mu);`. If there is a trailing comment, include it.349static SourceRange getFullFieldSourceRange(const FieldDecl &Field,350                                           const ASTContext &Context) {351  const SourceRange Range = Field.getSourceRange();352  SourceLocation Begin = Range.getBegin();353  SourceLocation End = Range.getEnd();354  const SourceManager &SM = Context.getSourceManager();355  const LangOptions &LangOpts = Context.getLangOpts();356  while (true) {357    std::optional<Token> CurrentToken = Lexer::findNextToken(End, SM, LangOpts);358 359    if (!CurrentToken)360      return SourceRange(Begin, End);361 362    if (CurrentToken->is(tok::eof))363      return Range; // Something is wrong, return the original range.364 365    End = CurrentToken->getLastLoc();366 367    if (CurrentToken->is(tok::semi))368      break;369  }370  Begin = getStartOfLeadingComment(Begin, SM, LangOpts);371  End = getEndOfTrailingComment(End, SM, LangOpts);372  return SourceRange(Begin, End);373}374 375/// Reorders fields in the definition of a struct/class.376///377/// At the moment reordering of fields with378/// different accesses (public/protected/private) is not supported.379/// \returns true on success.380static bool reorderFieldsInDefinition(381    const ReorderedStruct &RS, const ASTContext &Context,382    std::map<std::string, tooling::Replacements> &Replacements) {383  assert(RS.Definition && "Definition is null");384 385  SmallVector<const FieldDecl *, 10> Fields;386  for (const auto *Field : RS.Definition->fields())387    Fields.push_back(Field);388 389  // Check that the permutation of the fields doesn't change the accesses390  for (const auto *Field : RS.Definition->fields()) {391    const auto FieldIndex = Field->getFieldIndex();392    if (Field->getAccess() !=393        Fields[RS.NewFieldsOrder[FieldIndex]]->getAccess()) {394      llvm::errs() << "Currently reordering of fields with different accesses "395                      "is not supported\n";396      return false;397    }398  }399 400  for (const auto *Field : RS.Definition->fields()) {401    const auto FieldIndex = Field->getFieldIndex();402    if (FieldIndex == RS.NewFieldsOrder[FieldIndex])403      continue;404    addReplacement(getFullFieldSourceRange(*Field, Context),405                   getFullFieldSourceRange(406                       *Fields[RS.NewFieldsOrder[FieldIndex]], Context),407                   Context, Replacements);408  }409  return true;410}411 412/// Reorders initializers in a C++ struct/class constructor.413///414/// A constructor can have initializers for an arbitrary subset of the class's415/// fields. Thus, we need to ensure that we reorder just the initializers that416/// are present.417static void reorderFieldsInConstructor(418    const CXXConstructorDecl *CtorDecl, const ReorderedStruct &RS,419    ASTContext &Context,420    std::map<std::string, tooling::Replacements> &Replacements) {421  assert(CtorDecl && "Constructor declaration is null");422  if (CtorDecl->isImplicit() || CtorDecl->getNumCtorInitializers() <= 1)423    return;424 425  // The method FunctionDecl::isThisDeclarationADefinition returns false426  // for a defaulted function unless that function has been implicitly defined.427  // Thus this assert needs to be after the previous checks.428  assert(CtorDecl->isThisDeclarationADefinition() && "Not a definition");429 430  SmallVector<const CXXCtorInitializer *, 10> OldWrittenInitializersOrder;431  SmallVector<const CXXCtorInitializer *, 10> NewWrittenInitializersOrder;432  for (const auto *Initializer : CtorDecl->inits()) {433    if (!Initializer->isMemberInitializer() || !Initializer->isWritten())434      continue;435 436    // Warn if this reordering violates initialization expr dependencies.437    const FieldDecl *ThisM = Initializer->getMember();438    const auto UsedMembers = findMembersUsedInInitExpr(Initializer, Context);439    for (const FieldDecl *UM : UsedMembers) {440      if (RS.NewFieldsPositions[UM->getFieldIndex()] >441          RS.NewFieldsPositions[ThisM->getFieldIndex()]) {442        DiagnosticsEngine &DiagEngine = Context.getDiagnostics();443        auto Description = ("reordering field " + UM->getName() + " after " +444                            ThisM->getName() + " makes " + UM->getName() +445                            " uninitialized when used in init expression")446                               .str();447        unsigned ID = DiagEngine.getDiagnosticIDs()->getCustomDiagID(448            DiagnosticIDs::Warning, Description);449        DiagEngine.Report(Initializer->getSourceLocation(), ID);450      }451    }452 453    OldWrittenInitializersOrder.push_back(Initializer);454    NewWrittenInitializersOrder.push_back(Initializer);455  }456  auto ByFieldNewPosition = [&](const CXXCtorInitializer *LHS,457                                const CXXCtorInitializer *RHS) {458    assert(LHS && RHS);459    return RS.NewFieldsPositions[LHS->getMember()->getFieldIndex()] <460           RS.NewFieldsPositions[RHS->getMember()->getFieldIndex()];461  };462  llvm::sort(NewWrittenInitializersOrder, ByFieldNewPosition);463  assert(OldWrittenInitializersOrder.size() ==464         NewWrittenInitializersOrder.size());465  for (unsigned i = 0, e = NewWrittenInitializersOrder.size(); i < e; ++i)466    if (OldWrittenInitializersOrder[i] != NewWrittenInitializersOrder[i])467      addReplacement(OldWrittenInitializersOrder[i]->getSourceRange(),468                     NewWrittenInitializersOrder[i]->getSourceRange(), Context,469                     Replacements);470}471 472/// Replacement for broken InitListExpr::isExplicit function.473/// FIXME: Remove when InitListExpr::isExplicit is fixed.474static bool isImplicitILE(const InitListExpr *ILE, const ASTContext &Context) {475  // The ILE is implicit if either:476  // - The left brace loc of the ILE matches the start of first init expression477  //   (for non designated decls)478  // - The right brace loc of the ILE matches the end of first init expression479  //   (for designated decls)480  // The first init expression should be taken from the syntactic form, but481  // since the ILE could be implicit, there might not be a syntactic form.482  // For that reason we have to check against all init expressions.483  for (const Expr *Init : ILE->inits()) {484    if (ILE->getLBraceLoc() == Init->getBeginLoc() ||485        ILE->getRBraceLoc() == Init->getEndLoc())486      return true;487  }488  return false;489}490 491/// Finds the semantic form of the first explicit ancestor of the given492/// initializer list including itself.493static const InitListExpr *getExplicitILE(const InitListExpr *ILE,494                                          ASTContext &Context) {495  if (!isImplicitILE(ILE, Context))496    return ILE;497  const InitListExpr *TopLevelILE = ILE;498  DynTypedNodeList Parents = Context.getParents(*TopLevelILE);499  while (!Parents.empty() && Parents.begin()->get<InitListExpr>()) {500    TopLevelILE = Parents.begin()->get<InitListExpr>();501    Parents = Context.getParents(*TopLevelILE);502    if (!isImplicitILE(TopLevelILE, Context))503      break;504  }505  if (!TopLevelILE->isSemanticForm()) {506    return TopLevelILE->getSemanticForm();507  }508  return TopLevelILE;509}510 511static void reportError(const Twine &Message, SourceLocation Loc,512                        const SourceManager &SM) {513  if (Loc.isValid()) {514    llvm::errs() << SM.getFilename(Loc) << ":" << SM.getPresumedLineNumber(Loc)515                 << ":" << SM.getPresumedColumnNumber(Loc) << ": ";516  }517  llvm::errs() << Message;518}519 520/// Reorders initializers in the brace initialization of an aggregate.521///522/// At the moment partial initialization is not supported.523/// \returns true on success524static bool reorderFieldsInInitListExpr(525    const InitListExpr *InitListEx, const ReorderedStruct &RS,526    ASTContext &Context,527    std::map<std::string, tooling::Replacements> &Replacements) {528  assert(InitListEx && "Init list expression is null");529  // Only process semantic forms of initializer lists.530  if (!InitListEx->isSemanticForm()) {531    return true;532  }533 534  // If there are no initializers we do not need to change anything.535  if (!InitListEx->getNumInits())536    return true;537 538  // We care only about InitListExprs which originate from source code.539  // Implicit InitListExprs are created by the semantic analyzer.540  // We find the first parent InitListExpr that exists in source code and541  // process it. This is necessary because of designated initializer lists and542  // possible omitted braces.543  InitListEx = getExplicitILE(InitListEx, Context);544 545  // Find if there are any designated initializations or implicit values. If all546  // initializers are present and none have designators then just reorder them547  // normally. Otherwise, designators are added to all initializers and they are548  // sorted in the new order.549  bool HasImplicitInit = false;550  bool HasDesignatedInit = false;551  // The method InitListExpr::getSyntacticForm may return nullptr indicating552  // that the current initializer list also serves as its syntactic form.553  const InitListExpr *SyntacticInitListEx = InitListEx;554  if (const InitListExpr *SynILE = InitListEx->getSyntacticForm()) {555    // Do not rewrite zero initializers. This check is only valid for syntactic556    // forms.557    if (SynILE->isIdiomaticZeroInitializer(Context.getLangOpts()))558      return true;559 560    HasImplicitInit = InitListEx->getNumInits() != SynILE->getNumInits();561    HasDesignatedInit = llvm::any_of(SynILE->inits(), [](const Expr *Init) {562      return isa<DesignatedInitExpr>(Init);563    });564 565    SyntacticInitListEx = SynILE;566  } else {567    // If there is no syntactic form, there can be no designators. Instead,568    // there might be implicit values.569    HasImplicitInit =570        (RS.NewFieldsOrder.size() != InitListEx->getNumInits()) ||571        llvm::any_of(InitListEx->inits(), [&Context](const Expr *Init) {572          return isa<ImplicitValueInitExpr>(Init) ||573                 (isa<InitListExpr>(Init) &&574                  isImplicitILE(dyn_cast<InitListExpr>(Init), Context));575        });576  }577 578  if (HasImplicitInit || HasDesignatedInit) {579    // Designators are only supported from C++20.580    if (!HasDesignatedInit && Context.getLangOpts().CPlusPlus &&581        !Context.getLangOpts().CPlusPlus20) {582      reportError(583          "Only full initialization without implicit values is supported\n",584          InitListEx->getBeginLoc(), Context.getSourceManager());585      return false;586    }587 588    // Handle case when some fields are designated. Some fields can be589    // missing. Insert any missing designators and reorder the expressions590    // according to the new order.591    std::optional<Designators> CurrentDesignators;592    // Remember each initializer expression along with its designators. They are593    // sorted later to determine the correct order.594    std::vector<std::pair<Designators, const Expr *>> Rewrites;595    for (const Expr *Init : SyntacticInitListEx->inits()) {596      if (const auto *DIE = dyn_cast_or_null<DesignatedInitExpr>(Init)) {597        CurrentDesignators.emplace(DIE, SyntacticInitListEx, &Context);598        if (!CurrentDesignators->isValid()) {599          reportError("Unsupported initializer list\n", DIE->getBeginLoc(),600                      Context.getSourceManager());601          return false;602        }603 604        // Use the child of the DesignatedInitExpr. This way designators are605        // always replaced.606        Rewrites.emplace_back(*CurrentDesignators, DIE->getInit());607      } else {608        // If designators are not initialized then initialize to the first609        // field, otherwise move the next field.610        if (!CurrentDesignators) {611          CurrentDesignators.emplace(Init, SyntacticInitListEx, &Context);612          if (!CurrentDesignators->isValid()) {613            reportError("Unsupported initializer list\n",614                        InitListEx->getBeginLoc(), Context.getSourceManager());615            return false;616          }617        } else if (!CurrentDesignators->advanceToNextField(Init)) {618          reportError("Unsupported initializer list\n",619                      InitListEx->getBeginLoc(), Context.getSourceManager());620          return false;621        }622 623        // Do not rewrite implicit values. They just had to be processed to624        // find the correct designator.625        if (!isa<ImplicitValueInitExpr>(Init))626          Rewrites.emplace_back(*CurrentDesignators, Init);627      }628    }629 630    // Sort the designators according to the new order.631    llvm::stable_sort(Rewrites, [&RS](const auto &Lhs, const auto &Rhs) {632      return RS(Lhs.first, Rhs.first);633    });634 635    for (unsigned i = 0, e = Rewrites.size(); i < e; ++i) {636      addReplacement(SyntacticInitListEx->getInit(i)->getSourceRange(),637                     Rewrites[i].second->getSourceRange(),638                     Rewrites[i].first.toString(), Context, Replacements);639    }640  } else {641    // Handle excess initializers by leaving them unchanged.642    assert(SyntacticInitListEx->getNumInits() >= InitListEx->getNumInits());643 644    // All field initializers are present and none have designators. They can be645    // reordered normally.646    for (unsigned i = 0, e = RS.NewFieldsOrder.size(); i < e; ++i) {647      if (i != RS.NewFieldsOrder[i])648        addReplacement(SyntacticInitListEx->getInit(i)->getSourceRange(),649                       SyntacticInitListEx->getInit(RS.NewFieldsOrder[i])650                           ->getSourceRange(),651                       Context, Replacements);652    }653  }654  return true;655}656 657namespace {658class ReorderingConsumer : public ASTConsumer {659  StringRef RecordName;660  ArrayRef<std::string> DesiredFieldsOrder;661  std::map<std::string, tooling::Replacements> &Replacements;662 663public:664  ReorderingConsumer(StringRef RecordName,665                     ArrayRef<std::string> DesiredFieldsOrder,666                     std::map<std::string, tooling::Replacements> &Replacements)667      : RecordName(RecordName), DesiredFieldsOrder(DesiredFieldsOrder),668        Replacements(Replacements) {}669 670  ReorderingConsumer(const ReorderingConsumer &) = delete;671  ReorderingConsumer &operator=(const ReorderingConsumer &) = delete;672 673  void HandleTranslationUnit(ASTContext &Context) override {674    const RecordDecl *RD = findDefinition(RecordName, Context);675    if (!RD)676      return;677    if (!isSafeToRewrite(RD, Context))678      return;679    SmallVector<unsigned, 4> NewFieldsOrder =680        getNewFieldsOrder(RD, DesiredFieldsOrder);681    if (!isOrderValid(RD, NewFieldsOrder))682      return;683    ReorderedStruct RS{RD, NewFieldsOrder};684 685    if (!reorderFieldsInDefinition(RS, Context, Replacements))686      return;687 688    // CXXRD will be nullptr if C code (not C++) is being processed.689    const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD);690    if (CXXRD)691      for (const auto *C : CXXRD->ctors())692        if (const auto *D = dyn_cast<CXXConstructorDecl>(C->getDefinition()))693          reorderFieldsInConstructor(cast<const CXXConstructorDecl>(D), RS,694                                     Context, Replacements);695 696    // We only need to reorder init list expressions for697    // plain C structs or C++ aggregate types.698    // For other types the order of constructor parameters is used,699    // which we don't change at the moment.700    // Now (v0) partial initialization is not supported.701    if (!CXXRD || CXXRD->isAggregate()) {702      for (auto Result :703           match(initListExpr(hasType(equalsNode(RD))).bind("initListExpr"),704                 Context))705        if (!reorderFieldsInInitListExpr(706                Result.getNodeAs<InitListExpr>("initListExpr"), RS, Context,707                Replacements)) {708          Replacements.clear();709          return;710        }711    }712  }713};714} // end anonymous namespace715 716std::unique_ptr<ASTConsumer> ReorderFieldsAction::newASTConsumer() {717  return std::make_unique<ReorderingConsumer>(RecordName, DesiredFieldsOrder,718                                              Replacements);719}720 721} // namespace reorder_fields722} // namespace clang723