2017-07-26 40 views
1

是否有一個命令行工具,可以自動修復非格式化但仍看似簡單的CheckStyle問題在Java源代碼,如:自動修復非格式化,但簡單的CheckStyle發出

  • 避免內嵌條件語句
  • 讓「XXX 「靜態方法

我知道有各種工具來fix formatting和有些IDE具有相當先進quick fixers但到目前爲止,我找不到任何可以對源代碼摺疊遞歸運行呃或者被集成到一個提交鉤子中。

+0

看來Eclipse也可以修復一些Checkstyle問題:https://stackoverflow.com/a/8417213/1694043。讓Eclipse可以爲整個項目執行此操作,或者隔離此功能並從獨立工具運行此功能。 –

回答

1

聽起來像一個很好的挑戰,但我也無法找到一個可以做到這一點的自動工具。正如您已經描述的那樣,有很多選項可以更改代碼格式。對於其他小問題,您可以從命令行運行Checkstyle並過濾出可修復的警告。用於解析和更改Java源代碼的庫可以幫助實際進行更改,例如JavaParser。也許您可以使用JavaParser等Java源代碼操作工具在相對較少的時間內編寫定製工具。

(有喜歡ANTLR其他工具可以用來;更多的想法堆棧溢出這樣的問題:Java: parse java source code, extract methodsRoasterJavaPoet一些庫不分析方法的身體,這使得它們不太適用於這種情況。 。)

作爲一個非常簡單的例子,假設我們有一個其中的Checkstyle產生兩個消息(具有簡約checkstyle-checks.xml的Checkstyle配置文件,它僅僅檢查FinalParametersFinalLocalVariable)一個小的Java類:

// Example.java: 

package q45326752; 

public class Example { 
    public static void main(String[] arguments) { 
     System.out.println("Hello Checkstyle..."); 

     int perfectNumber = 1 + 2 + 3; 

     System.out.println("Perfect number: " + perfectNumber); 
    } 
} 


Checkstyle warnings: 

java -jar checkstyle-8.0-all.jar -c checkstyle-checks.xml Example.java 
[ERROR] Example.java:4:29: Parameter arguments should be final. [FinalParameters] 
[ERROR] Example.java:7:13: Variable 'perfectNumber' should be declared final. [FinalLocalVariable] 

使用JavaParser,這兩個警告可以像這樣自動修復(代碼試圖展示這個想法;一些部分現在已被忽略):

// AutomaticCheckstyleFix.java: 

package q45326752; 

import com.github.javaparser.JavaParser; 
import com.github.javaparser.ast.*; 
import com.github.javaparser.ast.body.*; 
import com.github.javaparser.ast.expr.*; 
import com.github.javaparser.ast.stmt.*; 

import java.io.File; 
import java.io.FileNotFoundException; 

public class AutomaticCheckstyleFix { 
    private MethodDeclaration bestMatchMethod; 
    private int bestMatchMethodLineNumber; 
    private Statement statementByLineNumber; 

    public static void main(final String[] arguments) { 
     final String filePath = "q45326752\\input\\Example.java"; 

     try { 
      new AutomaticCheckstyleFix().fixSimpleCheckstyleIssues(new File(filePath)); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void fixSimpleCheckstyleIssues(File file) throws FileNotFoundException { 
     CompilationUnit javaClass = JavaParser.parse(file); 
     System.out.println("Original Java class:\n\n" + javaClass); 
     System.out.println(); 
     System.out.println(); 

     // Example.java:4:29: Parameter arguments should be final. [FinalParameters] 
     MethodDeclaration methodIssue1 = getMethodByLineNumber(javaClass, 4); 
     if (methodIssue1 != null) { 
      methodIssue1.getParameterByName("arguments") 
        .ifPresent(parameter -> parameter.setModifier(Modifier.FINAL, true)); 
     } 

     // Example.java:7:13: Variable 'perfectNumber' should be declared final. 
     // [FinalLocalVariable] 
     Statement statementIssue2 = getStatementByLineNumber(javaClass, 7); 
     if (statementIssue2 instanceof ExpressionStmt) { 
      Expression expression = ((ExpressionStmt) statementIssue2).getExpression(); 
      if (expression instanceof VariableDeclarationExpr) { 
       ((VariableDeclarationExpr) expression).addModifier(Modifier.FINAL); 
      } 
     } 

     System.out.println("Modified Java class:\n\n" + javaClass); 
    } 

    private MethodDeclaration getMethodByLineNumber(CompilationUnit javaClass, 
                int issueLineNumber) { 
     bestMatchMethod = null; 

     javaClass.getTypes().forEach(type -> type.getMembers().stream() 
       .filter(declaration -> declaration instanceof MethodDeclaration) 
       .forEach(method -> { 
        if (method.getTokenRange().isPresent()) { 
         int methodLineNumber = method.getTokenRange().get() 
           .getBegin().getRange().begin.line; 
         if (bestMatchMethod == null 
           || (methodLineNumber < issueLineNumber 
           && methodLineNumber > bestMatchMethodLineNumber)) { 
          bestMatchMethod = (MethodDeclaration) method; 
          bestMatchMethodLineNumber = methodLineNumber; 
         } 
        } 
       }) 
     ); 

     return bestMatchMethod; 
    } 

    private Statement getStatementByLineNumber(CompilationUnit javaClass, 
               int issueLineNumber) { 
     statementByLineNumber = null; 

     MethodDeclaration method = getMethodByLineNumber(javaClass, issueLineNumber); 
     if (method != null) { 
      method.getBody().ifPresent(blockStmt 
        -> blockStmt.getStatements().forEach(statement 
        -> statement.getTokenRange().ifPresent(tokenRange -> { 
       if (tokenRange.getBegin().getRange().begin.line == issueLineNumber) { 
        statementByLineNumber = statement; 
       } 
      }))); 
     } 

     return statementByLineNumber; 
    } 
} 

另一種方法可能是創建新的Checkstyle插件,基於您嘗試創建自動修復的插件。也許你有足夠的信息可用,不僅可以給出警告,而且還可以生成修正後的修正版本。

就我個人而言,我會毫不猶豫地在提交時自動解決問題。當有許多簡單的修復工作時,自動化是值得歡迎的,但我想在提交之前檢查這些更改。像這樣運行一個工具並檢查更改可能是解決很多簡單問題的快速方法。

一些檢查,我認爲可以自動修復: