我是Perl的新手,目前的任务是整理和维护一个庞大而混乱的Perl项目。我使用perl-critic来帮助我检测代码中的问题(同时也教我最佳实践)。
现有的代码有一些地方,编码器在那里创建了无法访问的代码。例如,他们添加了"&;"0"作为注释掉某些代码分支的懒惰方式:
if ($req->param('donut') && 0) {
unreachable code...
} else {
always branches to here...
}
我曾希望perl或Critic会警告我在这种情况下无法访问的代码(条件有一个常数值,计算结果为false),但事实并非如此。
有没有一个工具或脚本可以让我可靠地检测到这种事情?
显然我可以搜索'&;"0",但除了附加"&;0"转换为if语句。
使用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排在最后,那么必须检查它之前的所有条件。它们可能会产生副作用,这种情况仍将发生。此外,&&
强制使用标量上下文,因此它可以更改在评估条件时调用的代码的行为。
抱歉,这并不能解释为什么块本身没有被编译掉。我的猜测是它看起来太复杂了。
根据choroba的回答,B::Deparse将能够向您展示代码明显无法访问的情况,以至于Perl编译器对其进行了优化。但是,在一般情况下,这是不可能检测到的。以下代码包含一个实际上无法访问的块。
use 5.006;
if ($] < 5) { ... }
因为$]
是一个返回当前运行的Perl版本的变量,use
行保证该版本至少为5.006。但您需要一些非常聪明的技术来通过对源代码的静态分析来解决这个问题。(顺便说一句,尽管这是一件不同寻常的事情,但在运行时更改$]
的值是可能的——请参阅Acme::Futuristic::Perl——在这种情况下,代码将变得可访问。)
如果你的代码有一个不错的测试套件,Devel::Cover可能会很有用。您将环境变量PERL5OPT
设置为-MDevel::Cover
,然后运行测试套件(注意它的运行速度会比平时慢一点),然后运行命令cover
,它将生成一个漂亮的HTML报告。此报告将突出显示哪些子任务没有执行,哪些分支从未使用过,等等。