【问题标题】:Automatic code simplification via refactoring [closed]通过重构自动简化代码 [关闭]
【发布时间】:2015-01-23 22:27:10
【问题描述】:

有没有通过重构自动简化java代码的工具?

Python 和 C 都有这样的工具:

但我不知道有任何此类 Java 程序。

在很多情况下,工具可以自动简化代码,例如:

  • 循环:for (String s: a) { b.add(s); }b.addAll(a);
  • 如果/返回:if (x) return true; else return false;return x;
  • 三元运算符:if (x) {result = a;} else {result = b;}result = x ? a : b;
  • 自动重构钻石运算符/异常多捕获/lambdas
  • 还有更多...

这种自动重构的优点是删除了大量样板代码行,使其更加简洁。

【问题讨论】:

  • 问题离题:要求我们推荐或查找书籍、工具、软件库、教程或其他场外资源的问题与 Stack Overflow 无关
  • 如果(x)返回真; → 返回 x; ???
  • @Ira 好点,这是 en 错误 :) 已编辑
  • 如果您需要其他具体建议,您应该将您的请求提交给 Stack Exchange 的软件推荐姐妹网站。 ——
  • 除了 Ira Baxter 的回答,我什么都没听说过。您的 IDE 可以做一些事情,但通常不会自动执行。有一些静态分析工具可以帮助向您展示需要更改的代码片段。也许IDE有一些插件?否则,您将需要某种解析器 + 很多规则。我听说Refaster 最终发布时会很适合这种东西。 Also, autorefactor.org looks like a hit.

标签: java automated-refactoring


【解决方案1】:

我是 Slanec 提到的AutoRefactor 的作者。 您展示的所有第一个重构都已实现,但以下尚未实现:

  • 自动重构钻石运算符/异常多捕获/lambdas
  • 还有更多...

请参阅open issues,包括 Java 7 重构。目前我只实现了与 Java 6 兼容的重构。

【讨论】:

  • 现在实现了以下内容:“自动重构为菱形运算符/异常多捕获”
【解决方案2】:

当然。查看Program Transformation Tools (PTS)。此类工具提供了一种定义语法的方法,使用该语法将源文本解析为 AST,并将 AST 漂亮地打印回文本。更重要的是,相同的语法用于读取 source-to-source 转换规则,允许您直接表达转换(或根据重写集表达复合转换)。这种转换使用表达的模式来匹配 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 必须满足的变量名n 和语法类别c
  • pattern_syntax_categorypattern_text 必须满足的语法类别,
  • replacement_syntax_categoryreplacement_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 可以用类似的方式表达规则。它们中的大多数不支持更深层次的语义事实,例如符号表或类型,尽管声称您可以自己编程。经验表明这是一项大量的工作,你真的希望它是正确的。 (谁希望他们的转换破坏代码,因为它在错误信息上运行?)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-23
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    • 1970-01-01
    相关资源
    最近更新 更多