通过重构自动简化代码
Automatic code simplification via refactoring
是否有通过重构自动 java 代码简化的工具?
Python 和 C:
有这样的工具
- Automatically simplifying/refactoring Python code (e.g. for loops -> list comprehension)?
- Is there a tool to test the conciseness of c program?)
但我不知道 Java 有任何此类程序。
在很多情况下,工具可以自动简化代码,例如:
- 循环:
for (String s: a) { b.add(s); }
→b.addAll(a);
- if/return:
if (x) return true; else return false;
→ return x;
- 三元运算符:
if (x) {result = a;} else {result = b;}
→ result = x ? a : b;
- 自动重构为菱形运算符/异常多捕获/lambdas
- 还有很多...
这种自动重构的优点是删除了大量样板代码行,使其更加简洁。
当然可以。查看 Program Transformation Tools (PTS)。这些工具提供了一种定义语法的方法,使用该语法将源文本解析为 AST,并将漂亮打印的 AST 解析回文本。更重要的是,相同的语法用于读取 源到源 转换规则,允许您直接表达转换(或根据重写集表达复合转换)。这种转换使用表达的模式来匹配 AST,并修改 AST;这些基于结构的转换不会被布局或空格混淆。
例如,我们的 DMS Software Reengineering Toolkit 允许您以 形式编写规则,如果您看到这个,请将其替换为那个 ,采用一般形式:
rule rule_name(pattern_variables)
: pattern_syntax_category -> replacement_syntax_category
= metaquote pattern_text_in_specified_language metaquote
=> metaquote replacement_text_in_specified_language metaquote
if condition_over_bound_pattern_variables;
哪里
- rule是引入规则的语法,
- rule_name 给规则起一个名字以区别于其他规则,
- pattern_variables 是模式对 n:c 的列表
变量名 n 和语法类别 c 其中 n 必须满足,
- pattern_syntax_category是pattern_text必须满足的语法范畴,
- replacement_syntax_category 是 replacement_text 必须满足的语法类别。通常,在此处给出的所有示例中,
与 pattern_syntax_category 相同;当使用重写规则在语言之间进行翻译时,这些规则通常会有所不同,因为语言中的语法类别不同。
- metaquote 是 " 字符,它将规则语言语法与模式或替换语言语法分开
- pattern_text_in_specified_language 是源语言的格式良好的片段,包含模式变量 n 写为 \n ;模式的任何匹配都会将模式变量绑定到子树。如果 \n 在模式中出现两次,则两个实例必须相同。
- replacement_text_in_specified_language 是目标语言的格式正确的片段。找到的模式被替换替换,替换中的任何模式变量被绑定模式变量值替换
- if是引入条件的语法
- condition_over_bound_pattern_variables 是在找到模式匹配后模式变量必须满足的约束。这通常用于检查必须满足的上下文条件。
DMS 将允许您编写和应用以下示例转换(包括 OP 的一些示例):
default domain Java~v8; -- specify v8 dialect of Java to manipulate
rule reduce_strength_squared(e: term):
:product -> product
= "\e ^ 2 " ==> "\e * \e "
if no_side_effects(e);
rule optimize_divide_by_self(e: term):
:product -> product
= " \e / \e " => " 1 " if is_not_zero(e);
rule accumulate_string(n: IDENTIFIER, a: expression, b: left_hand_side)
: statement -> statement
= "for (String \s: \a) { \b.add(\s); }"
=> "\b.addAll(\a);";
rule eliminate_useless_if(x: expression, s: statement)
: statement -> statement
= "if (\x) \s; else \s; " -- generalizes OP's example
=> "\s;";
rule left_factor_ternary(x: expression; t: left_hand_side; a: expression; b:expression)
: statement -> statement
= "if (\x) { \t = \a;} else {\t = \b;} "
=> "\t = \x ? \a : \b ";
rule convert_to_diamond( T1: qualified_path, T2: qualified_path,
C: qualified_path,
i: IDENTIFIER, a: arglist)
:statement -> statement
= "\T1<\T2> \i = new \C<\T2>(\a);"
=> "\T1<\T2> \i = new \C<>(\a);"
rule merge_multi_catch( b:body, i1: IDENTIFIER, e1: qualified_path,
i2: IDENTIFIER, eh: body )
:statement -> statement
= "try { \b }
catch ( \i1: \e1 ) { \eh }
catch ( \i2: \e1 ) { \eh }";
=> "try { \b }
catch ( \i1, \i2: \e1 ) { \eh }";
更复杂的转换是可能的,包括那些影响相距甚远甚至跨越源文件边界的程序部分的转换。这些通常需要一些额外的元编程(此处未讨论),并且通常需要对上下文进行一些额外的检查,例如,标识符的类型是否正确等。[DMS 具有 Java 的完整符号表来支持这一点]。
其他PTS可以用类似的方式表达规则。它们中的大多数不支持更深层次的语义事实,例如符号表或类型,尽管声称您可以自己对它们进行编程。经验表明这是一项 很多 的工作,您真的希望它是正确的。 (谁希望他们的转换破坏代码,因为它是在错误的信息上运行?)。
我是 Slanec 提到的 AutoRefactor 的作者。
您展示的所有第一个重构都已实现,但以下尚未实现:
- automatic refactor to diamond operator / exception multi catch / lambdas
- lots more...
查看 open issues,包括 Java 7 个重构。目前我只实现了 Java 6 个兼容的重构。
是否有通过重构自动 java 代码简化的工具?
Python 和 C:
有这样的工具- Automatically simplifying/refactoring Python code (e.g. for loops -> list comprehension)?
- Is there a tool to test the conciseness of c program?)
但我不知道 Java 有任何此类程序。
在很多情况下,工具可以自动简化代码,例如:
- 循环:
for (String s: a) { b.add(s); }
→b.addAll(a);
- if/return:
if (x) return true; else return false;
→return x;
- 三元运算符:
if (x) {result = a;} else {result = b;}
→result = x ? a : b;
- 自动重构为菱形运算符/异常多捕获/lambdas
- 还有很多...
这种自动重构的优点是删除了大量样板代码行,使其更加简洁。
当然可以。查看 Program Transformation Tools (PTS)。这些工具提供了一种定义语法的方法,使用该语法将源文本解析为 AST,并将漂亮打印的 AST 解析回文本。更重要的是,相同的语法用于读取 源到源 转换规则,允许您直接表达转换(或根据重写集表达复合转换)。这种转换使用表达的模式来匹配 AST,并修改 AST;这些基于结构的转换不会被布局或空格混淆。
例如,我们的 DMS Software Reengineering Toolkit 允许您以 形式编写规则,如果您看到这个,请将其替换为那个 ,采用一般形式:
rule rule_name(pattern_variables)
: pattern_syntax_category -> replacement_syntax_category
= metaquote pattern_text_in_specified_language metaquote
=> metaquote replacement_text_in_specified_language metaquote
if condition_over_bound_pattern_variables;
哪里
- rule是引入规则的语法,
- rule_name 给规则起一个名字以区别于其他规则,
- pattern_variables 是模式对 n:c 的列表 变量名 n 和语法类别 c 其中 n 必须满足,
- pattern_syntax_category是pattern_text必须满足的语法范畴,
- replacement_syntax_category 是 replacement_text 必须满足的语法类别。通常,在此处给出的所有示例中, 与 pattern_syntax_category 相同;当使用重写规则在语言之间进行翻译时,这些规则通常会有所不同,因为语言中的语法类别不同。
- metaquote 是 " 字符,它将规则语言语法与模式或替换语言语法分开
- pattern_text_in_specified_language 是源语言的格式良好的片段,包含模式变量 n 写为 \n ;模式的任何匹配都会将模式变量绑定到子树。如果 \n 在模式中出现两次,则两个实例必须相同。
- replacement_text_in_specified_language 是目标语言的格式正确的片段。找到的模式被替换替换,替换中的任何模式变量被绑定模式变量值替换
- if是引入条件的语法
- condition_over_bound_pattern_variables 是在找到模式匹配后模式变量必须满足的约束。这通常用于检查必须满足的上下文条件。
DMS 将允许您编写和应用以下示例转换(包括 OP 的一些示例):
default domain Java~v8; -- specify v8 dialect of Java to manipulate
rule reduce_strength_squared(e: term):
:product -> product
= "\e ^ 2 " ==> "\e * \e "
if no_side_effects(e);
rule optimize_divide_by_self(e: term):
:product -> product
= " \e / \e " => " 1 " if is_not_zero(e);
rule accumulate_string(n: IDENTIFIER, a: expression, b: left_hand_side)
: statement -> statement
= "for (String \s: \a) { \b.add(\s); }"
=> "\b.addAll(\a);";
rule eliminate_useless_if(x: expression, s: statement)
: statement -> statement
= "if (\x) \s; else \s; " -- generalizes OP's example
=> "\s;";
rule left_factor_ternary(x: expression; t: left_hand_side; a: expression; b:expression)
: statement -> statement
= "if (\x) { \t = \a;} else {\t = \b;} "
=> "\t = \x ? \a : \b ";
rule convert_to_diamond( T1: qualified_path, T2: qualified_path,
C: qualified_path,
i: IDENTIFIER, a: arglist)
:statement -> statement
= "\T1<\T2> \i = new \C<\T2>(\a);"
=> "\T1<\T2> \i = new \C<>(\a);"
rule merge_multi_catch( b:body, i1: IDENTIFIER, e1: qualified_path,
i2: IDENTIFIER, eh: body )
:statement -> statement
= "try { \b }
catch ( \i1: \e1 ) { \eh }
catch ( \i2: \e1 ) { \eh }";
=> "try { \b }
catch ( \i1, \i2: \e1 ) { \eh }";
更复杂的转换是可能的,包括那些影响相距甚远甚至跨越源文件边界的程序部分的转换。这些通常需要一些额外的元编程(此处未讨论),并且通常需要对上下文进行一些额外的检查,例如,标识符的类型是否正确等。[DMS 具有 Java 的完整符号表来支持这一点]。
其他PTS可以用类似的方式表达规则。它们中的大多数不支持更深层次的语义事实,例如符号表或类型,尽管声称您可以自己对它们进行编程。经验表明这是一项 很多 的工作,您真的希望它是正确的。 (谁希望他们的转换破坏代码,因为它是在错误的信息上运行?)。
我是 Slanec 提到的 AutoRefactor 的作者。 您展示的所有第一个重构都已实现,但以下尚未实现:
- automatic refactor to diamond operator / exception multi catch / lambdas
- lots more...
查看 open issues,包括 Java 7 个重构。目前我只实现了 Java 6 个兼容的重构。