如何检测(真实)和其他重构问题?

时间:2014-04-11 13:00:35

标签: refactoring automated-refactoring

在java中很常见,当使用"现代" IDE,内联变量值并执行大量重构,例如,可以转换此源代码

boolean test = true;
//...
if(test) {
    //...
}

进入此代码

if(true) {
    //...
}

显然,这段代码可以简化,但Eclipse不会为我执行简化。

那么,有没有办法(使用Eclipse或 - 甚至更好 - maven)可以检测并(可能)简化代码? (如果这样的工具能够检测到其他错误的构造,比如空的for循环,那么显然会更好......)

1 个答案:

答案 0 :(得分:0)

你想要的是Program Transformation system(PTS)。

这些工具可以读取源代码,构建编译器数据结构(几乎总是至少包含AST),执行自定义分析和修改编译器数据结构,然后从那些文件中重新生成源文本(用于修改后的程序)修改过的数据结构。

许多PTS将允许您直接以源到源的形式表达对代码的更改作为规则,用语言语法,元变量等表示。这种规则语言的要点是让您表达复杂代码转换更容易。

我们的DMS软件再造工具包就是这样的PTS。您可以使用包含布尔常量的布尔表达式使用以下简单规则轻松简化代码:

default domain Java~v7;

simplify_not_true(): primary -> primary
     " ! true" -> "false";

simplify_not_false(): primary -> primary
     " ! false" -> "true";

simplify_not_not(x: primary): primary -> primary
     " ! ! \x " ->  "\x";

simplify_and_right_true(x: term): conjunction -> conjunction ;
   " \x && true " ->  "\x";

simplify_and_left_true(x: term): conjunction -> conjunction ;
   " true && \x " ->  "\x";

simplify_and_left_false(x: term): conjunction -> conjunction ;
   " false && \x " ->  "false";

simplify_and_right_false(x: term): conjunction -> conjunction ;
   " \x && false " ->  "false"
   if no_side_effects_or_exceptions(x);  -- note additional semantic check here

simplify_or_right_false(x: term): disjunction -> disjunction ;
   " \x || false " ->  "\x";

simplify_or_left_false(x: term): disjunction -> disjunction ;
   " false || \x " ->  "\x";

simplify_or_right_true(x: term): disjunction -> disjunction ;
   " \x || true " ->  "true"
   if no_side_effects_or_exceptions(x);

simplify_or_left_true(x: term): disjunction -> disjunction ;
   " true || \x " ->  "true";

(语法名称“term”,“primary”,“conj”,“disjunction”直接来自用于驱动Java源代码解析的BNF。)

这些规则将采用涉及已知布尔常量的布尔表达式, 并简化它们有时简化为“真实”或“虚假”。

要消除表达式为布尔常量的if-condition,可以写下这些:

 simplify_if_true(b: block): statement -> statement
    " if (true) \b" -> " \b ";

 simplify_if_false(b: block): statement -> statement
    " if (false) \b" -> ";"  -- null statement

与布尔简化一起,这两条规则将摆脱明显真实或明显错误条件的条件。

做你想做的事情有点复杂,因为你希望将信息从程序中的一个地方传播到另一个可能“远离”的地方。为此,您需要进行数据流分析,显示值可从其分配中获得的位置:

default domain Java~v7;

rule propagate_constant_variables(i:IDENTIFIER): term -> term
     " \i " -> construct_reaching_constant()
     if constant_reaches(i);

此规则取决于提供数据流事实和自定义的内置分析 接口函数“constant_reaches”检查此数据。 (DMS有C,C ++,Java和COBOL的支持,并支持其他语言;据我所知,维基百科文章中提到的其他PTS都没有这些流程事实可用)。它还依赖于自定义构造函数“contruct_reaching_constant”来构建包含到达常量的原始树节点。这些将在DMS的底层元编程语言中编码,并且需要几十行代码。类似地,前面讨论的特殊条件是“no_side_effects_or_exceptions”;这可能要复杂得多,因为关于副作用的问题可能需要对整个程序进行分析。

像Clang这样的工具可以在某种程度上转换C ++代码,但是Clang没有像PTS那样重写规则,它实际上是一个带有额外钩子的编译器。