Как обнаружить недостижимый код в условном Perl, который всегда оценивается как ложный?

Я новичок в Perl, и в настоящее время мне поручено привести в порядок и поддерживать большой и довольно грязный проект Perl. Я использую Perl-критик, чтобы помочь мне обнаружить проблемы в коде (а также научить меня передовым методам).

В существующем коде есть места, где кодер создал недоступный код. Например, они добавили '&& 0' как ленивый способ закомментировать некоторые ветви кода:

if ($req->param('donut') && 0) {
    unreachable code... 
} else {
    always branches to here...
}

Я надеялся, что Perl или Critic предупредят меня о недостижимом коде в таких случаях (когда у условного выражения есть постоянное значение, равное false), но это не так.

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

Очевидно, что я мог бы искать '&& 0' в исходном коде, но существует несколько способов, которыми кодировщик мог создать недоступный код, кроме добавления '&& 0' в оператор if.

2 ответа

Используя B:: Deparse, вы можете обнаружить недоступный код в некоторых ситуациях:

perl -MO=Deparse -e 'if (0 && $x) {print 1} else {print 2}'
do {
    print 2
};
-e syntax OK

Это не так просто, если 0 не первое условие:

perl -MO=Deparse -e 'if ($x && 0) {print 1} else {print 2}'
if ($x and 0) {
    print 1;
}
else {
    print 2;
}
-e syntax OK

Почему это отличается? Хорошо, если 0 идет последним, все условия перед ним должны быть проверены. У них могут быть побочные эффекты, которые все еще будут происходить. Также, && форсирует скалярный контекст, поэтому он может изменить поведение кода, вызываемого при оценке условия.

Это не объясняет, почему сам блок не компилируется, извините. Я думаю, это будет слишком сложно.

Согласно ответу Чоробы, B::Deparse сможет показать вам случаи, когда код так явно недоступен, что компилятор Perl оптимизирует его. Но в общем случае это невозможно обнаружить. Следующий код включает в себя фактически недоступный блок.

use 5.006;

if ($] < 5) { ... }

Так как $] переменная, которая возвращает текущую работающую версию Perl, которая гарантированно будет не ниже 5.006 use линия. Но вам понадобятся довольно умные методы, чтобы понять это с помощью статического анализа исходного кода. (Помимо этого, хотя это и необычная вещь, можно изменить $] во время выполнения - см. Acme::Futuristic::Perl - в этом случае код станет доступным.)

Если у вас есть достойный набор тестов для вашего кода, Devel:: Cover может быть полезен. Вы устанавливаете переменную среды PERL5OPT в -MDevel::Cover, затем запустите ваш набор тестов (обратите внимание, что он будет работать немного медленнее, чем обычно), затем выполните команду cover который создаст симпатичный HTML-отчет. В этом отчете будет указано, какие подпрограммы не были выполнены, какие ветви никогда не использовались и т. Д.

Другие вопросы по тегам