在java代码库中自动为所有if / else / for / while等添加花括号

我希望减少大型遗留Java代码库中声纳违规的数量,似乎“快速获胜”将更新所有这些条件语句以具有大括号。 这似乎是一件容易的事情,我不明白为什么它不容易自动化。

有没有人知道可以像这样执行批量操作的工具? 或者为什么做这样的事情可能是一个坏主意,然后我花时间自己写点什么? 如果我自己写一个什么是最好的工具? 理想情况下,这是一种Java语言感知的东西,所以我不必处理格式化案例等。

顺便说一句,这条规则是不可协商的,所以这确实是最好的方法。

最简单的方法是使用Eclipse并在整个项目中单击“ Clean-up 。 在Clean-up配置文件配置中,选择Code style选项卡。 在那里,您可以选择Use blocks in if/while/for/do statementsAlways

首先在检查设置中启用Control flow statement without braces

IntelliJ Idea – >运行代码检查 – >快速修复(至少在商业版中有效)

虽然建议对遗留代码保持谨慎,但检测遗留代码中的错误也是一件好事……或者至少使错误更容易被发现。

让我们来看看Brian Agnew的疑难案例:

 // Case #1 if (x) doMethodA(); doMethodB(); 

实际上,就JLS和Java编译器而言,这意味着

 if (x) doMethodA(); doMethodB(); 

因此,当变换器将代码重写为:

 if (x) { doMethodA(); } doMethodB(); 

它没有改变代码的含义,但它正在纠正一个可能导致某人误读代码的问题,并且错过代码中已经存在的潜在错误; 即如果第二次通话应该是有条件的……

 // Case #2 if (x) // doMethodA(); doMethodB(); 

再一次,当重写时,你应该得到:

  if (x) { // doMethodA(); doMethodB(); } 

这意味着与原始相同的东西。 此外,这很可能反映了程序员的意图……如果要相信缩进。 但考虑一下:

 // Case #2a if (x) // doMethodA(); doMethodB(); 

当我们重写为

 if (x) { // doMethodA(); doMethodB(); } 

代码的实际含义不会改变,不正确的缩进不再会误导。 如果程序员决定取消注释第一个调用,他可能没有意识到之前的注释已经产生了意想不到的后果。 (证据是在我们已经“修复”的原始缩进中。)但是有一个潜在的解决方案; 见下文。


如果我们假设代码转换工具在正确理解Java的语法和语义的情况下运行,那么它将不会破坏任何尚未破坏的东西,并且它(在某种程度上)会使任何现有的破坏对某些人更明显阅读代码。 对我来说,这是一个零风险的胜利,即使对于遗留代码也是如此。

现在,如果我们使变压器更智能,它可以检测到一些原始压痕表明可能存在错误的情况(如上面的情况#1和#2a)并标记它们以进行更密切的代码检查。

这让我感到非常危险。 你有全面的unit testing覆盖率吗?

我可以看到一些立即困难的案例,例如

 if (x) doMethodA(); doMethodB(); 

 if (x) // doMethodA(); doMethodB(); 

是两个想到的,不能天真地处理(你应该有语言意识来解决这些问题)。 我不会尝试自动执行这样的任务,除非你有语言感知和可靠的工具,而是强制执行一个策略,当你因为其他原因更改代码时修改代码,并且可以在那个阶段通过unit testing断言代码覆盖在更改代码之前。

罗伯特在评论中说:“@ iira我也有兴趣听到这种真正的语言识别工具!”

对不起,挑逗。 为了挑逗的原因,检查我的生物。

Untease:请参见http://www.semanticdesigns/Products/DMS/DMSToolkit.html作为基础引擎,以及http://www.semanticdesigns.com/Products/FrontEnds/JavaFrontEnd.html 。 该对构成了一个完全语言感知的源到源程序转换系统。

可以使用具有两个源到源转换规则的DMS完成此任务:

  rule curlies_for_then_statement:(c:expression, s: statement}: statement->statement " if (\c) \s " -> "if (\c) { \s } "; rule curlies_for_else_statement:(c:expression, b: block, s: statement}: statement->statement " if (\c) \b else \s " -> "if (\c) \b else { \s } "; 

这是可靠的,因为DMS完全是从forms语法(在这种情况下是Java)中驱动的,并且不是在原始文本上操作,而是在抽象语法树上操作; 这也使得独立于布局。 (理解“阻止”,“表达”和“语句”是语法非终结符的规则可能很有用。

虽然它可能是一个快速的声纳胜利,但你正在做一些危险的事情。 建议的方法是仅在必须重新访问该代码时修复遗留代码。 这些一揽子方法可能会导致非常微妙的错误。 由于策略已经改变,您的管理团队需要了解这是一项艰巨的任务,并且应该保证所有未来的代码都是按照标准开发的。

如果您首先在编辑器设置中设置正确的编码样式,Intellij 2017将使用重新格式代码支持此function。

 File -> Settings -> Editor -> Code Style -> Java -> Wrapping and Braces 

编辑器设置Intellij