How to detect if(true) and other refactoring issues?

大憨熊 提交于 2019-12-11 08:47:56

问题


It is common in java, when using "modern" IDEs, to inline variable values and perform heavy refactoring that can, as an example, transform this source code

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

Into this code

if(true) {
    //...
}

Obviously, this code can be simplified, but Eclipse won't perform that simplification for me.

So, is there any way (using Eclipse or - even better - maven) that can detect and (possibly) simplify that code ? (it would be obviously way better if such a tool was able to detect other wrong constructs like empty for loops, ...)


回答1:


What you want is a Program Transformation system (PTS).

These are tools that read source code, build compiler data structures (almost always including at least an AST), carry out customized analysis and modification of the compiler data structures, and then regenerate source text (for the modified program) from those modified data structures.

Many of the PTS will allow you express changes to code directly in source-to-source form as rules, expressed in terms of the language syntax, metavariables, etc. The point of such a rule language is to let you express complex code transformations more easily.

Our DMS Software Reengineering Toolkit is such a PTS. You can easily simplify code with boolean expressions containing boolean constants with the following simple rules:

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";

(The grammar names "term", "primary", "conjunction", "disjunction" are directly from the BNF used to drive Java source code parsing.)

These rules together will take boolean expressions involving known boolean constants, and simplify them down sometimes to simply "true" or "false".

To eliminate if-conditionals whose expressions are boolean constants one would write these:

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

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

Together with boolean simplification, these two rules would get rid of conditionals for obviously true or obviously false conditionals.

To do what you want is bit more complicated, because you wish to propagate information from one place in the program, to another place possibly "far away". For that you need what amounts to a data flow analysis, showing where values can reach from their assignments:

default domain Java~v7;

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

This rule depends on a built-in analysis providing data flow facts and a custom interface function "constant_reaches" that inspects this data. (DMS has this for C, C++, Java and COBOL and support for doing it for other languages; to my knowledge, none of the other PTS mentioned in the Wikipedia article have these flow facts available). It also depends on a custom contructor "contruct_reaching_constant" to build a primitive tree node containing a reaching constant. These would be coded in DMS's underlying metaprogramming langauge and require a few tens of lines of code. Similarly the special condition discussed earlier "no_side_effects_or_exceptions"; this can be a lot more complex as the question about side effects may require an analysis of the full program.

There are tools such a Clang that can transform C++ code to some extent, but Clang does not have rewrite rules as PTS do, it is really a compiler with additional hooks.



来源:https://stackoverflow.com/questions/23013306/how-to-detect-iftrue-and-other-refactoring-issues

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!