8

我是 Perl 新手,目前的任务是整理和维护一个庞大且非常混乱的 Perl 项目。我正在使用 perl-critic 来帮助我检测代码中的问题(并教我最佳实践)。

现有代码中有编码人员创建了无法访问的代码的地方。例如,他们添加了 '&& 0' 作为注释掉一些代码分支的懒惰方式:

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

我希望 perl 或 Critic 会在这种情况下警告我有关无法访问的代码(条件具有评估为 false 的常量值),但事实并非如此。

有没有我可以使用的工具或脚本可以可靠地检测到这种事情?

显然,我可以在源代码中搜索 '&& 0',但是除了将 '&& 0' 附加到 if 语句之外,编码器还可以通过多种方式创建无法访问的代码。

4

2 回答 2

9

使用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 最后出现,则必须检查它之前的所有条件。它们可能会产生仍然会发生的副作用。此外,&&强制标量上下文,因此它可以更改评估条件时调用的代码的行为。

这并不能解释为什么块本身没有被编译掉,抱歉。我的猜测是它看起来太复杂了。

于 2014-04-28T08:47:54.933 回答
5

根据 choroba 的回答,B::Deparse 将能够向您展示代码明显无法访问以至于 Perl 编译器将其优化掉的情况。但是,在一般情况下是不可能检测到的。以下代码包含一个有效无法访问的块。

use 5.006;

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

因为$]是一个变量,它返回当前运行的 Perl 版本,该版本保证至少为 5.006 use。但是你需要一些非常聪明的技术来使用源代码的静态分析来解决这个问题。(顺便说一句,虽然这是不寻常的事情,但可以$]在运行时更改 的值——参见Acme::Futuristic::Perl——在这种情况下,代码将变得可访问。)

如果您的代码有一个不错的测试套件,Devel::Cover可能会很有用。您将环境变量设置PERL5OPT-MDevel::Cover,然后运行您的测试套件(注意它的运行速度会比平时慢一点),然后运行cover将生成漂亮 HTML 报告的命令。该报告将突出显示哪些子程序未执行,哪些分支从未使用过等。

于 2014-04-28T10:45:51.523 回答