Подтвердить что ты не робот

Очистка патологически-вложенного "if {} else {if {} else {if {...}}}"

В настоящее время я испытываю несчастье работать над кодом Somebody Else С#, который действительно испортил мой разум. Я понятия не имею, как человек до меня поддерживал этот код, поскольку его различные патологии разрушили среду IDE, компилятор, среду выполнения...

Проблема, с которой я столкнулся сегодня, включает в себя 15-мегабайтный исходный файл, который показывает истинно умопомрачительную степень патологического гнездования. Код:

if(var == 0) {
  // do stuff
}
else {
  if(var == 1) {
    // do stuff
  }
  else {
    if(var == 2) {
      // do stuff, identical word for word to the `var == 1` case
    }
    else {
      // etc.
    }
  }
}

В лучшем случае это спорный стилистический выбор. Однако это сочетается с другой патологией кода: некоторые из этих блоков почти тысяча уровней глубиной. (Самое глубокое, что мне мешало измерять, было более 700.) Я искренне надеюсь, что человек, передо мной, как один из их заключительных действий, прежде чем быть насильственно отделенным от этого кода, провел инструмент моделирования, который привел к мерзостям передо мной. Я не могу представить, что они могли бы написать этот код так, как сейчас, тем более что каждое третье или четвертое редактирование кода приводит к сбою IDE. (И иногда удаляет мою копию исходного файла в качестве бонуса.)

Я написал простой инструмент, основанный на регулярном выражении, чтобы попытаться сконденсировать более простые случаи, но, похоже, выполняет половину процесса, а затем повреждает этот конкретный код. (Я не уверен, что это терпит неудачу, потому что этот код также время от времени использует условные обозначения препроцессора или потому, что самый длинный из совпадений будет почти 10 МБ, а совпадение регулярных выражений Lua просто не может справиться.) Я надеюсь, что там широко используемый инструмент или метод, который может изменить эту проблему. Мне уже пришлось использовать астиль, чтобы очистить некоторые другие стилистические "проблемы" кода. Опция --remove-brackets для астиля почти делает то, что я хочу, но требует, чтобы оператор в скобках был единственным выражением в одной строке, что здесь очень не так... (И просто чтобы пересечь мои "т", Я проверил: астиль не создала эту конкретную проблему.)

Изменить: более глубокое рассмотрение кода проблемы обнаруживает такие вещи:

#if OneThing
int num2296 = otherThing();
#endif
#if AnotherThing
int num44 = otherThing()
int num45 = 0;
#endif
int num72 = 0;
#if OneThing
int num45 = 0; // note: multiple equivalent declarations of num45
#endif
#if OneThing
for(int num2297 = 0; num2297 < num2296; ++num2297) {
  num45 = doSomething(num2297);
#endif
#if AnotherThing
for(int num43 = 0; num43 < num44; ++num43) {
  num45 = doSomething(num43);
#endif
  if(somethingElse(num45)) {
    ++num72;
  }
} // note: only one closing brace for the two protected by #ifs

Две версии этого кода скомпилированы для разных целей: одна с OneThing определена и одна с AnotherThing определена. Однако большинство различий между ними - это просто имена переменных, логически идентичные. (Большинство, не все.)

Случаи, подобные скобе в конце вышеприведенного фрагмента, объясняют, почему мой простой инструмент ломался. Это также все больше похоже на безопасность работы по дизайну и меньше похоже на невиновную некомпетентность. (Если код был один раз в точке, где имя переменной, подобное num2276, было бы сгенерировано декомпилятором, в данный момент это не так.)

К сожалению, это означает, что автоматизированный инструмент, вероятно, не будет вырезать его в одиночку. Мне просто нужно проскользнуть, медленно отменив ущерб, нанесенный последнему программисту. Я оставляю этот вопрос здесь на случай, когда есть чудесный инструмент, который, я не знаю, могу преобразовать обе версии в SSA и идентифицировать и свернуть их логические эквивалентности, а затем преобразовать их обратно...

4b9b3361

Ответ 1

Вы можете использовать Roslyn для перезаписи кода. Это не очень хороший подход для изменения исходного кода в виде текста. С Roslyn вы можете изменить его как дерево синтаксиса.

Может, это поможет вам сгладить все?

if (a)
 if (b) F2()
 else F3();
else
 F4();

Может стать:

if (a && b) F2();
else if (a && !b) F3();
else F4();

Таким образом, исходный код становится плоским списком, и это более очевидно, при каких условиях вводится ветвь.