10
3

概要

大規模なリファクタリングを安全に行うため、Google製のJava静的解析ツールであるError Proneにて、自作のRefaster templateに対してPatch作成機能を利用したソースコードの一括置換を試みました。

本記事では、その手順をまとめています。

実行手順

1. Refaster Templateクラスを作成する

例: Apache Commons DbUtilsDbUtils#closeQuietlyの呼び出しの効率化を題材とします。

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import org.apache.commons.dbutils.DbUtils;

import com.google.errorprone.refaster.annotation.AfterTemplate;
import com.google.errorprone.refaster.annotation.BeforeTemplate;

public class UseCloseQuietly {
	@BeforeTemplate
	public void calledCloseQueitly3Times(Connection conn, PreparedStatement ps, ResultSet rs) {
		DbUtils.closeQuietly(rs);
		DbUtils.closeQuietly(ps);
		DbUtils.closeQuietly(conn);
	}

	@AfterTemplate
	public void optimizedMethod(Connection conn, PreparedStatement ps, ResultSet rs) {
		DbUtils.closeQuietly(conn, ps, rs);
	}
}

ただし、(おそらく) @BeforeTemplate の構文木が複雑になる場合(if文やtry-catchが多く含まれている場合など)は、後述のrefasterファイルによるPatchを生成できませんでした。小分けにすると動作することもあったので、現状ではサポートしているケースが限られているのだと考えています。

2. refasterファイルを生成する

error_prone_refasterや参照しているライブラリのjarファイルをクラスパスに含めた状態で、javacコマンドを実行します。(要: Java 11)

すると、 myrule.refaster ファイルが生成されます。

javac \
  -cp "error_prone_refaster-2.26.1.jar;commons-dbutils-1.8.1.jar" \
  "-Xplugin:RefasterRuleCompiler --out myrule.refaster" \
  UseCloseQuietly.java

3. Gradleプロジェクトに適用する

  1. 生成されたmyrule.refasterを対象のGradleプロジェクトに配置する
  2. gradle-errorprone-pluginを利用するため、build.gradleに下記の内容を追記する
  3. gradle clean compileJava を実行すると、 error-prone.patch が生成される
  4. patch -p0 -u -i error-prone.patch を実行し、パッチを適用する
plugins {
  id("net.ltgt.errorprone") version "3.1.0"
}
 
import net.ltgt.gradle.errorprone.CheckSeverity

compileJava {
  options.errorprone.checks = ['Refaster': CheckSeverity.ERROR]
  options.errorprone.errorproneArgs = ['-XepPatchChecks:refaster:' + buildscript.sourceFile.getParent() + '/myrule.refaster',
   '-XepPatchLocation:' + buildscript.sourceFile.getParent()]
  options.errorprone.checkOptions = ['Refaster': 'NamePattern=.*']
}

dependencies {
  errorprone("com.google.errorprone:error_prone_core:2.26.1")
}

なお、-XepPatchLocation:IN_PLACE と設定すれば、修正を直接適用できます。

参考: Can Error Prone Auto-Apply Suggested Fixes?

結果

対象プロジェクトのソースコードに対して、下記のような変更が一括で適用されます。
変数名が異なっていても問題なく置換されますし、必要なimport文も自動で生成されます。
(余計な空行があるのはご愛嬌…別途、コードフォーマッターを適用しましょう)

		} finally {
-			DbUtils.closeQuietly(rs);
-			DbUtils.closeQuietly(ps);
-			DbUtils.closeQuietly(conn);
+			DbUtils.closeQuietly(conn, ps, rs);
+
+
		}
10
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
3