Развитие механизма CFG

Развитие механизма CFG

Мы закончили подготовку MVP нашего нового механизма, покрыли его тестами и решили перейти к более интересным вещам, например, посмотреть, какие существующие проверки кода 1с можно улучшить с помощью новых возможностей.

Напомним, что CFG или "Граф потока управления" представляет собой, как ни странно, граф показывающий все возможные пути выполнения программы/метода. Например, следующий код 1с:

Процедура Тест()
  Если Condition Тогда
    doInFirstCondition();
    Если NestedCondition Тогда
      doInNestedCondition();
    КонецЕсли;
  ИначеЕсли ConditionTwo() Тогда
    doInSecondCondition();
  Иначе
    doInElseBranch();
    Если ElseCondition Тогда
      doInElseNested();
    КонецЕсли;
  КонецЕсли;
  doAfterIf();
КонецПроцедуры

можно представить в виде такой структуры:

Первым почетным добровольцем выступила проверка "Функция должна заканчиваться возвратом".

Как она работает сейчас? Очень просто: проверяет что последним выражением в функции является "Возврат" или "ВызватьИсключение".

Напомним, что если в функции не указан явный "Возврат", то она вернет "Неопределено", что может привести к трудно диагностируемым ошибкам и неконтролируемому поведению.

Данный подход отлично работает в большинстве случаев, но пасует перед более хитрыми вариантами, например:

Функция Тест()
  Если Условие Тогда
    Возврат Истина;
  Иначе
    Возврат Ложь;
  КонецЕсли;
КонецФункции

как мы видим, разработчик позаботился о том, чтобы при любом варианте развития событий функция возвращала конкретное значение, без использования "общего" возврата, но диагностика такой случай "не понимает", что приводит к появлению FP (ложного срабатывания).

Однако, данная проблема отлично решается с помощью нашего нового механизма CFG. Теперь, диагностика проверяет не просто последнее выражение функции, а все возможные точки выхода из функции, и смотрит, являются ли эти точки выхода выражением "Возврат" или "ВызватьИсключение".

Запустив анализ типового проекта 1с с новым вариантом диагностики, мы нашли очень интересные случаи, например, такой:

код типовой функции был изменен для наглядности, общая структура метода осталась неизменной

Функция Тест()
  Если Операция = Перечисления.Операции.Операция1 Тогда

    Если ТипЗнч(ДокументСсылка) = Тип("ДокументСсылка.Док1") Тогда

      Если ВыборкаПоФайлам = Неопределено Тогда
        Возврат "Сообщение");
      Иначе
        Возврат "Сообщение");
      КонецЕсли;

    Иначе

      Если ВыборкаПоФайлам = Неопределено Тогда
        Возврат "Сообщение");
      Иначе
        Возврат "Сообщение");
      КонецЕсли; 

    КонецЕсли;

   ИначеЕсли Операция = Перечисления.Операции.Операция2 Тогда
     // !!!
     Если ТипЗнч(ДокументСсылка) = Тип("ДокументСсылка.Док2") Тогда
       Возврат "Сообщение";
     КонецЕсли;
     // !!!

   ИначеЕсли Операция = Перечисления.Операции.Операция3 Тогда
     Возврат "Сообщение";  
   Иначе 
     Возврат Строка(Операция);
   КонецЕсли; 

КонецФункции

Как мы видим из примера, разработчик позаботился о том, чтобы покрыть почти все кейсы. Кроме одного, отмеченного восклицательными знаками.

Если функция попадет во второе "ИначеЕсли" и вложенное условие окажется ложным, то функция вернет "Неопределено", вместо строки.

Возможно, так и задумано, но чаще всего это невнимательность разработчика, который дорабатывал уже существующее условие.

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

Релиз нашего плагина с новым механизмом CFG уже не за горами, stay tuned!