@SuppressWarnings("unchecked")
  private <E extends ArrangementEntry> void doArrange(@NotNull List<? extends ArrangementEntryWrapper<E>> wrappers,
                                                      @NotNull Context<E> context) {
    if (wrappers.isEmpty()) {
      return;
    }

    Map<E, ArrangementSectionRule> entryToSection = new HashMap<>();
    Map<E, ArrangementEntryWrapper<E>> map = new HashMap<>();
    List<E> arranged = new ArrayList<>();
    List<E> toArrange = new ArrayList<>();
    for (ArrangementEntryWrapper<E> wrapper : wrappers) {
      E entry = wrapper.getEntry();
      map.put(wrapper.getEntry(), wrapper);
      if (!entry.canBeMatched()) {
        // Split entries to arrange by 'can not be matched' rules.
        // See IDEA-104046 for a problem use-case example.
        arranged.add(entry);
        toArrange.clear();
      }
      else {
        toArrange.add(entry);
      }
    }
    if (!toArrange.isEmpty()) {
      E contextEntry = toArrange.get(0);
      Language language = contextEntry instanceof LanguageAwareArrangementEntry ?
                          ((LanguageAwareArrangementEntry)contextEntry).getLanguage() : null;
      ArrangementSettings settings = context.getArrangementSettings(language);
      List<? extends ArrangementMatchRule> rulesByPriority = settings.getRulesSortedByPriority();
      List<ArrangementSectionRule> sectionRules = ArrangementUtil.getExtendedSectionRules(settings);
      arranged.addAll(arrange(toArrange, sectionRules, rulesByPriority, entryToSection));
    }

    final NewSectionInfo<E> newSectionsInfo = NewSectionInfo.create(arranged, entryToSection);
    context.changer.prepare(wrappers, context);
    // We apply changes from the last position to the first position in order not to bother with offsets shifts.
    for (int i = arranged.size() - 1; i >= 0; i--) {
      ArrangementEntryWrapper<E> arrangedWrapper = map.get(arranged.get(i));
      ArrangementEntryWrapper<E> initialWrapper = wrappers.get(i);

      ArrangementEntryWrapper<E> previous = i > 0 ? map.get(arranged.get(i - 1)) : null;
      ArrangementEntryWrapper<E> previousInitial = i > 0 ? wrappers.get(i - 1) : null;

      final ArrangementEntryWrapper<E> parentWrapper = initialWrapper.getParent();
      if (arrangedWrapper.equals(initialWrapper)) {
        if (previous != null && previous.equals(previousInitial) || previous == null && previousInitial == null) {
          final int beforeOffset = arrangedWrapper.getStartOffset();
          final int afterOffset = arrangedWrapper.getEndOffset();

          boolean isInserted = context.changer.insertSection(context, arranged.get(i), newSectionsInfo, parentWrapper, beforeOffset, afterOffset);
          myCodeChanged = isInserted || myCodeChanged;
          continue;
        }
      }

      ArrangementEntryWrapper<E> next = i < arranged.size() - 1 ? map.get(arranged.get(i + 1)) : null;
      context.changer.replace(arrangedWrapper, initialWrapper, previous, next, context);
      context.changer.insertSection(context, arranged.get(i), newSectionsInfo, arrangedWrapper, initialWrapper, parentWrapper);
      myCodeChanged = true;
    }
  }
@SuppressWarnings("unchecked")
  private <E extends ArrangementEntry> void doArrange(@NotNull List<? extends ArrangementEntryWrapper<E>> wrappers,
                                                      @NotNull Context<E> context)