java inspections: fix for replace concatenation in Appendable.append should use Strin...
authorDmitry Batkovich <dmitry.batkovich@jetbrains.com>
Thu, 11 Aug 2016 11:19:16 +0000 (14:19 +0300)
committerDmitry Batkovich <dmitry.batkovich@jetbrains.com>
Thu, 11 Aug 2016 11:19:55 +0000 (14:19 +0300)
java/java-analysis-impl/src/com/intellij/codeInspection/util/ChangeToAppendUtil.java
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeToAppendFix.java
plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/concatenation_inside_append/PrintWriterAppend.after.java [new file with mode: 0644]
plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/concatenation_inside_append/PrintWriterAppend.java [new file with mode: 0644]
plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/ReplaceWithChainedAppendFixTest.java

index 9327bdfbded1c588b865f754febdf00598d83944..d9dc5f08500b0f13b4bf9ba77e83b4615f92b3cd 100644 (file)
@@ -26,8 +26,9 @@ public class ChangeToAppendUtil {
     if (concatenation == null) return null;
     final PsiType type = appendable.getType();
     if (type == null) return null;
-    final StringBuilder result =
-      buildAppendExpression(concatenation, type.equalsToText("java.lang.Appendable"), new StringBuilder(appendable.getText()));
+    final boolean useStringValueOf = !type.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUFFER) &&
+                                     !type.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUILDER);
+    final StringBuilder result = buildAppendExpression(concatenation, useStringValueOf, new StringBuilder(appendable.getText()));
     if (result == null) return null;
     final PsiElementFactory factory = JavaPsiFacade.getElementFactory(appendable.getProject());
     return factory.createExpressionFromText(result.toString(), appendable);
index 513cb7895ecf913af49d36b4876608a61056ff8c..8974dd10291a77defd97493169828ece39ac8254 100644 (file)
@@ -24,6 +24,7 @@ import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.project.Project;
 import com.intellij.psi.*;
 import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.InheritanceUtil;
 import com.intellij.util.IncorrectOperationException;
 import org.jetbrains.annotations.NotNull;
 
@@ -35,6 +36,7 @@ public class ChangeToAppendFix implements IntentionAction {
   private final IElementType myTokenType;
   private final PsiType myLhsType;
   private final PsiAssignmentExpression myAssignmentExpression;
+  private volatile TypeInfo myTypeInfo;
 
   public ChangeToAppendFix(@NotNull IElementType eqOpSign, @NotNull PsiType lType, @NotNull PsiAssignmentExpression assignmentExpression) {
     myTokenType = eqOpSign;
@@ -47,9 +49,8 @@ public class ChangeToAppendFix implements IntentionAction {
   public String getText() {
     return QuickFixBundle.message("change.to.append.text",
                                   ChangeToAppendUtil.buildAppendExpression(myAssignmentExpression.getRExpression(),
-                                                                           myLhsType.equalsToText("java.lang.Appendable"),
-                                                                           new StringBuilder(
-                                                                             myAssignmentExpression.getLExpression().getText())));
+                                                                           getTypeInfo().myUseStringValueOf,
+                                                                           new StringBuilder(myAssignmentExpression.getLExpression().getText())));
   }
 
   @NotNull
@@ -63,9 +64,7 @@ public class ChangeToAppendFix implements IntentionAction {
     return JavaTokenType.PLUSEQ == myTokenType &&
            myAssignmentExpression.isValid() &&
            PsiManager.getInstance(project).isInProject(myAssignmentExpression) &&
-           (myLhsType.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUILDER) ||
-            myLhsType.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUFFER) ||
-            myLhsType.equalsToText("java.lang.Appendable"));
+           getTypeInfo().myAppendable;
   }
 
   @Override
@@ -81,4 +80,33 @@ public class ChangeToAppendFix implements IntentionAction {
     if (appendExpression == null) return;
     myAssignmentExpression.replace(appendExpression);
   }
+
+  @NotNull
+  private TypeInfo getTypeInfo() {
+    if (myTypeInfo != null) return myTypeInfo;
+    myTypeInfo = calculateTypeInfo();
+    return myTypeInfo;
+  }
+
+  @NotNull
+  private TypeInfo calculateTypeInfo() {
+    if (myLhsType.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUILDER) ||
+        myLhsType.equalsToText(CommonClassNames.JAVA_LANG_STRING_BUFFER)) {
+      return new TypeInfo(true, false);
+    }
+    if (InheritanceUtil.isInheritor(myLhsType, "java.lang.Appendable")) {
+      return new TypeInfo(true, true);
+    }
+    return new TypeInfo(false, false);
+  }
+
+  private static class TypeInfo {
+    private final boolean myAppendable;
+    private final boolean myUseStringValueOf;
+
+    TypeInfo(boolean appendable, boolean useStringValueOf) {
+      myAppendable = appendable;
+      myUseStringValueOf = useStringValueOf;
+    }
+  }
 }
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/concatenation_inside_append/PrintWriterAppend.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/concatenation_inside_append/PrintWriterAppend.after.java
new file mode 100644 (file)
index 0000000..0a1ce4d
--- /dev/null
@@ -0,0 +1,10 @@
+package com.siyeh.igfixes.performance.concatenation_inside_append;
+
+import java.io.PrintWriter;
+
+class PrintWriterAppend {
+
+  void foo(PrintWriter printWriter, int year, int season) {
+    printWriter.append("this is intellij idea ").append(String.valueOf(year)).append(".").append(String.valueOf(season)).append(" version");
+  }
+}
\ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/concatenation_inside_append/PrintWriterAppend.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/concatenation_inside_append/PrintWriterAppend.java
new file mode 100644 (file)
index 0000000..3c8d5da
--- /dev/null
@@ -0,0 +1,10 @@
+package com.siyeh.igfixes.performance.concatenation_inside_append;
+
+import java.io.PrintWriter;
+
+class PrintWriterAppend {
+
+  void foo(PrintWriter printWriter, int year, int season) {
+    printWriter.app<caret>end("this is intellij idea " + year + "." + season + " version");
+  }
+}
\ No newline at end of file
index 594833e059a1681d4ae2fcb876593c6b6044219e..7c93c8b14d7c3f75deeba22908a26a9f776f61d0 100644 (file)
@@ -34,4 +34,16 @@ public class ReplaceWithChainedAppendFixTest extends IGQuickFixesTestCase {
 
   public void testUnresolvedMethod() { doTest(); }
 
+  public void testPrintWriterAppend() {
+    myFixture.addClass("package java.lang;" +
+                       "public interface Appendable {}");
+    myFixture.addClass("package java.io;" +
+                       "public class PrintWriter extends java.lang.Appendable {" +
+                       "@Override" +
+                       "public PrintWriter append(CharSequence csq) throws IOException {" +
+                       " return null;" +
+                       "}}");
+    doTest();
+  }
+
 }