QuickFixの作り方

わかってはいるが,この手のコードは地味だよなぁ。

QuickFixの指定は,こんな具合にProblemDescriptorに与えるだけ。

ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
    arg0,
    "この値は,Java識別子でなければなりません。",
    myQuickFix,         // ← 選択可能なQuickFixを与える
    ProblemHighlightType.GENERIC_ERROR_OR_WARNING);

LocalInspectionToolのインスタンスのライフサイクルがどうなってるのか知らんのだが,サンプルではQuickFixをインスタンス変数に保持していたので,そのまま真似た。


QuickFix本体は,こんな感じ(Inspectiorの内部クラスにしてんのはたまたま)。

private static class MyQuickFix implements LocalQuickFix {
  @NotNull
  public String getName() {
    return "正規化する";
  }

  @NotNull
  public String getFamilyName() {
    return getName();
  }

  public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
    try {
      PsiLiteralExpression expression = (PsiLiteralExpression) descriptor.getPsiElement();
      String value = (String) expression.getValue();
      if (value != null) {
        value = value.replaceAll("??s", "");
        value = value.replaceAll("??p{Punct}", "_");

        PsiElementFactory factory = PsiManager.getInstance(project).getElementFactory();
        PsiExpression newExpression = factory.createExpressionFromText('"' + value + '"', null);

        expression.replace(newExpression);
      }
    }
    catch (IncorrectOperationException e) {
      LOG.error(e);
    }
  }
}

このQuickFixは,PsiLiteralExpressionの値から,空白の除去と記号文字をアンダースコアに置換し,エディタに反映させる(コード見りゃなんとなく,感じはわかる)。
QuickFixの結果反映は,処理対象であるPsiElementに対して,正したPsiElementに置き換える(replace)んだが,正しいPsiElementの生成方法が,ちょっとユニーク。

PsiExpression newExpression = factory.createExpressionFromText('"' + value + '"', null);

今回の例ではわかりづらいんだが,PsiElementFactory.createExpressionFromText()に,元ネタとなる式を与えて,新たなPsiElementを生成するみたい。サンプルにあった「a == b」を「a.equals(b)」に修正するQuickFixの場合,こんな感じで正しいPsiElementを生成している。

PsiExpression newExpression = factory.createExpressionFromText("a.equals(b)", null);

こうなってくると,次に気になるのはファイル生成系のQuickFixの作り方だよなぁ。