diff --git a/platform/testRunner/src/com/intellij/execution/testframework/autotest/AdjustAutotestDelayActionGroup.java b/platform/testRunner/src/com/intellij/execution/testframework/autotest/AdjustAutotestDelayActionGroup.java index cb5b437e7865..c6536cdb0f61 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/autotest/AdjustAutotestDelayActionGroup.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/autotest/AdjustAutotestDelayActionGroup.java @@ -20,6 +20,7 @@ import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -45,27 +46,29 @@ public class AdjustAutotestDelayActionGroup extends ActionGroup { public AnAction[] getChildren(@Nullable AnActionEvent e) { final AnAction[] actions = new AnAction[MAX_DELAY]; for (int i = 0; i < MAX_DELAY; i++) { - actions[i] = new SetAutoTestDelayAction(i + 1); + actions[i] = new SetAutoTestDelayAction(myEnvironment.getProject(), i + 1); } return actions; } private static class SetAutoTestDelayAction extends ToggleAction { private final int myDelay; + @NotNull private final Project myProject; - public SetAutoTestDelayAction(int delay) { + public SetAutoTestDelayAction(@NotNull Project project, int delay) { super(delay + "s"); + myProject = project; myDelay = delay * 1000; } @Override public boolean isSelected(AnActionEvent e) { - return AutoTestManager.getInstance(e.getProject()).getDelay() == myDelay; + return AutoTestManager.getInstance(myProject).getDelay() == myDelay; } @Override public void setSelected(AnActionEvent e, boolean state) { - AutoTestManager.getInstance(e.getProject()).setDelay(myDelay); + AutoTestManager.getInstance(myProject).setDelay(myDelay); } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/StringBufferReplaceableByStringBuilderInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/StringBufferReplaceableByStringBuilderInspection.java index 33b1a947acc8..0584f1057e7a 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/StringBufferReplaceableByStringBuilderInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/StringBufferReplaceableByStringBuilderInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; @@ -31,8 +32,6 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.HashSet; import java.util.Set; public class StringBufferReplaceableByStringBuilderInspection extends BaseInspection { @@ -151,8 +150,8 @@ public class StringBufferReplaceableByStringBuilderInspection extends BaseInspec private static class StringBufferReplaceableByStringBuilderVisitor extends BaseInspectionVisitor { - private static final Set excludes = new HashSet(Arrays.asList(CommonClassNames.JAVA_LANG_STRING_BUILDER, - CommonClassNames.JAVA_LANG_STRING_BUFFER)); + private static final Set excludes = ContainerUtil.newHashSet(CommonClassNames.JAVA_LANG_STRING_BUILDER, + CommonClassNames.JAVA_LANG_STRING_BUFFER); @Override public void visitDeclarationStatement(PsiDeclarationStatement statement) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java index 7e096d987ffa..d3edd0956d4e 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; @@ -31,7 +32,6 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; public class StringBufferReplaceableByStringInspection extends BaseInspection { @@ -257,7 +257,7 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { private final PsiVariable myVariable; private final StringBuilder myBuilder; - private final List expressions = new ArrayList(); + private final List expressions = ContainerUtil.newArrayList(); private boolean myProblem = false; public StringBuildingVisitor(@NotNull PsiVariable variable, StringBuilder builder) { @@ -425,8 +425,9 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { private static class ReplaceableByStringVisitor extends JavaRecursiveElementVisitor { private final PsiElement myParent; - private PsiVariable myVariable; + private final PsiVariable myVariable; private boolean myReplaceable = true; + private boolean myPossibleSideEffect = false; private boolean myToStringFound = false; public ReplaceableByStringVisitor(@NotNull PsiVariable variable) { @@ -450,7 +451,7 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { public void visitAssignmentExpression(PsiAssignmentExpression expression) { super.visitAssignmentExpression(expression); if (expression.getTextOffset() > myVariable.getTextOffset() && !myToStringFound) { - myReplaceable = false; + myPossibleSideEffect = true; } } @@ -458,7 +459,7 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { public void visitPostfixExpression(PsiPostfixExpression expression) { super.visitPostfixExpression(expression); if (expression.getTextOffset() > myVariable.getTextOffset() && !myToStringFound) { - myReplaceable = false; + myPossibleSideEffect = true; } } @@ -466,10 +467,77 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { public void visitPrefixExpression(PsiPrefixExpression expression) { super.visitPrefixExpression(expression); if (expression.getTextOffset() > myVariable.getTextOffset() && !myToStringFound) { - myReplaceable = false; + myPossibleSideEffect = true; } } + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (expression.getTextOffset() < myVariable.getTextOffset() || myToStringFound) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + myPossibleSideEffect = true; + return; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + myPossibleSideEffect = true; + return; + } + final String name = aClass.getQualifiedName(); + if (CommonClassNames.JAVA_LANG_STRING_BUFFER.equals(name) || + CommonClassNames.JAVA_LANG_STRING_BUILDER.equals(name)) { + return; + } + if (isArgumentOfStringBuilderMethod(expression)) { + return; + } + myPossibleSideEffect = true; + } + + private boolean isArgumentOfStringBuilderMethod(PsiMethodCallExpression expression) { + final PsiElement parent = expression.getParent(); + if (!(parent instanceof PsiExpressionList)) { + return false; + } + final PsiElement grandParent = parent.getParent(); + if (!(grandParent instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)grandParent; + final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); + PsiExpression qualifier = methodExpression.getQualifierExpression(); + while (qualifier instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression callExpression = (PsiMethodCallExpression)qualifier; + final PsiReferenceExpression methodExpression1 = callExpression.getMethodExpression(); + qualifier = methodExpression1.getQualifierExpression(); + } + if (qualifier instanceof PsiReferenceExpression) { + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier; + final PsiElement target = referenceExpression.resolve(); + if (!myVariable.equals(target)) { + return false; + } + } + final PsiMethod method = methodCallExpression.resolveMethod(); + if (method == null) { + return false; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return false; + } + final String name1 = aClass.getQualifiedName(); + if (CommonClassNames.JAVA_LANG_STRING_BUFFER.equals(name1) || + CommonClassNames.JAVA_LANG_STRING_BUILDER.equals(name1)) { + return true; + } + return false; + } + @Override public void visitReferenceExpression(PsiReferenceExpression expression) { if (!myReplaceable || expression.getTextOffset() < myVariable.getTextOffset()) { @@ -508,6 +576,10 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { myToStringFound = true; return; } + if (myPossibleSideEffect) { + myReplaceable = false; + return; + } parent = grandParent.getParent(); if (parent instanceof PsiExpressionStatement) { return; diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_buffer_replaceable_by_string/StringBufferReplaceableByString.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_buffer_replaceable_by_string/StringBufferReplaceableByString.java index 10a389fa9032..266c094e5383 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_buffer_replaceable_by_string/StringBufferReplaceableByString.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_buffer_replaceable_by_string/StringBufferReplaceableByString.java @@ -39,12 +39,12 @@ public class StringBufferReplaceableByString { public void assignment(int p) { StringBuilder b = new StringBuilder(); - b.append(p); p++; + b.append(p); System.out.println(b.toString()); StringBuilder c = new StringBuilder(); - c.append(p); p = 2; + c.append(p); System.out.println(c.toString()); StringBuilder d = new StringBuilder(); @@ -79,4 +79,38 @@ public class StringBufferReplaceableByString { data.append(String.format("%02d:%02d", Math.abs(hours), min)); return data.toString(); } + + class HighlightStaticImport { + + void example1() { + System.out.println(); + final StringBuilder builder = new StringBuilder(); + builder.append(foo1()); + b(); // side effect + builder.append(foo1()); + bar(builder.toString()); + System.out.println(); + } + + void example2() { + final StringBuilder builder = new StringBuilder(); + builder.append(foo1()); + b(); // side effect, but has no effect on builder anymore + bar(builder.toString()); + } + + String s; + + void b() { + s = "asdf"; + } + + private void bar(String s) { + + } + + private String foo1() { + return null; + } + } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_buffer_replaceable_by_string/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_buffer_replaceable_by_string/expected.xml index 9d6c57a431fb..73ad82fabbdb 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_buffer_replaceable_by_string/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/string_buffer_replaceable_by_string/expected.xml @@ -36,4 +36,11 @@ <code>StringBuilder d</code> can be replaced with 'String' #loc + + StringBufferReplaceableByString.java + 96 + 'StringBuffer' can be replaced with 'String' + <code>StringBuilder builder</code> can be replaced with 'String' #loc + + \ No newline at end of file diff --git a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/EclipseImportMap.properties b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/EclipseImportMap.properties index a963714660d1..9c79740be0f5 100644 --- a/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/EclipseImportMap.properties +++ b/plugins/eclipse/src/org/jetbrains/idea/eclipse/importer/EclipseImportMap.properties @@ -33,7 +33,7 @@ org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=Java: #org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration= #org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases= #org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation= -org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=Java:ALIGN_GROUP_FIELD_DECLARATIONS +#org.eclipse.jdt.core.formatter.alignment_for_multiple_fields= org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=Java:ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION #org.eclipse.jdt.core.formatter.alignment_for_conditional_expression= org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=Java:SPACE_BEFORE_FOR_PARENTHESES @@ -65,7 +65,7 @@ org.eclipse.jdt.core.formatter.blank_lines_before_package=Java:BLANK_LINES_BEFOR #org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call= org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=Java:SPACE_BEFORE_COMMA #org.eclipse.jdt.core.formatter.blank_lines_before_member_type= -#org.eclipse.jdt.core.formatter.align_type_members_on_columns= +org.eclipse.jdt.core.formatter.align_type_members_on_columns=Java:ALIGN_GROUP_FIELD_DECLARATIONS #org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant= org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=Java:SPACE_WITHIN_FOR_PARENTHESES org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=Java:SPACE_BEFORE_METHOD_PARENTHESES