diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 92894cd75ab9..4639e93c509b 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1045,6 +1045,7 @@ inner.class.may.be.static.problem.descriptor=Inner class #ref may b string.buffer.must.have.initial.capacity.problem.descriptor=#ref without initial capacity #loc string.buffer.replaceable.by.string.builder.problem.descriptor=StringBuffer #ref may be declared as ''StringBuilder'' #loc string.buffer.replaceable.by.string.problem.descriptor={0} #ref can be replaced with ''String'' #loc +new.string.buffer.replaceable.by.string.problem.descriptor=#ref can be replaced with 'String' #loc string.replaceable.by.string.buffer.problem.descriptor=Non-constant String #ref should probably be declared as ''StringBuilder'' #loc collections.must.have.initial.capacity.problem.descriptor=#ref without initial capacity #loc string.concatenation.in.loops.problem.descriptor=String concatenation #ref in loop #loc diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java index 9d56ab1b5c69..38eed03f36cd 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java @@ -39,13 +39,17 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { @Override @NotNull public String buildErrorString(Object... infos) { - final String typeText = ((PsiType)infos[0]).getPresentableText(); + final PsiElement element = (PsiElement)infos[0]; + if (element instanceof PsiNewExpression) { + return InspectionGadgetsBundle.message("new.string.buffer.replaceable.by.string.problem.descriptor"); + } + final String typeText = ((PsiType)infos[1]).getPresentableText(); return InspectionGadgetsBundle.message("string.buffer.replaceable.by.string.problem.descriptor", typeText); } @Override protected InspectionGadgetsFix buildFix(Object... infos) { - final String typeText = ((PsiType)infos[0]).getCanonicalText(); + final String typeText = ((PsiType)infos[1]).getCanonicalText(); return new StringBufferReplaceableByStringFix(CommonClassNames.JAVA_LANG_STRING_BUILDER.equals(typeText)); } @@ -72,6 +76,13 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { final PsiElement element = descriptor.getPsiElement(); final PsiElement parent = element.getParent(); if (!(parent instanceof PsiVariable)) { + if (parent instanceof PsiNewExpression) { + final PsiNewExpression newExpression = (PsiNewExpression)parent; + final PsiExpression stringBuilderExpression = getCompleteExpression(newExpression); + final StringBuilder stringExpression = buildStringExpression(stringBuilderExpression, new StringBuilder()); + replaceExpression(stringBuilderExpression, stringExpression.toString()); + return; + } return; } final PsiVariable variable = (PsiVariable)parent; @@ -83,18 +94,18 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { if (initializer == null) { return; } + final StringBuilder stringExpression = buildStringExpression(initializer, new StringBuilder()); + if (stringExpression == null) { + return; + } final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); final PsiClassType javaLangString = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_STRING, variable.getResolveScope()); final PsiTypeElement typeElement = factory.createTypeElement(javaLangString); - final StringBuilder newInitializer = buildReplacementInitializer(initializer, new StringBuilder()); - if (newInitializer == null) { - return; - } + replaceExpression(initializer, stringExpression.toString()); originalTypeElement.replace(typeElement); - replaceExpression(initializer, newInitializer.toString()); } - private static StringBuilder buildReplacementInitializer(PsiExpression initializer, StringBuilder result) { + private static StringBuilder buildStringExpression(PsiExpression initializer, StringBuilder result) { if (initializer instanceof PsiNewExpression) { final PsiNewExpression newExpression = (PsiNewExpression)initializer; final PsiExpressionList argumentList = newExpression.getArgumentList(); @@ -116,18 +127,20 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)initializer; final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); final PsiExpression qualifier = methodExpression.getQualifierExpression(); - result = buildReplacementInitializer(qualifier, result); + result = buildStringExpression(qualifier, result); if (result == null) { return null; } - final PsiExpressionList argumentList = methodCallExpression.getArgumentList(); - final PsiExpression[] arguments = argumentList.getExpressions(); - if (arguments.length != 1) { - return null; + if (!"toString".equals(methodExpression.getReferenceName())) { + final PsiExpressionList argumentList = methodCallExpression.getArgumentList(); + final PsiExpression[] arguments = argumentList.getExpressions(); + if (arguments.length != 1) { + return null; + } + final PsiExpression argument = arguments[0]; + result.append('+'); + result.append(argument.getText()); } - final PsiExpression argument = arguments[0]; - result.append('+'); - result.append(argument.getText()); } else { return null; } @@ -176,7 +189,22 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { if (variableIsModified(variable, codeBlock)) { return; } - registerVariableError(variable, type); + registerVariableError(variable, variable, type); + } + + @Override + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + final PsiType type = expression.getType(); + if (!TypeUtils.typeEquals(CommonClassNames.JAVA_LANG_STRING_BUFFER, type) && + !TypeUtils.typeEquals(CommonClassNames.JAVA_LANG_STRING_BUILDER, type)) { + return; + } + final PsiExpression completeExpression = getCompleteExpression(expression); + if (completeExpression == null) { + return; + } + registerNewExpressionError(expression, expression, type); } public static boolean variableIsModified(PsiVariable variable, PsiElement context) { @@ -210,4 +238,32 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { return "append".equals(methodName); } } + + private static PsiExpression getCompleteExpression(PsiNewExpression expression) { + PsiElement completeExpression = expression; + boolean found = false; + while (true) { + final PsiElement parent = completeExpression.getParent(); + if (!(parent instanceof PsiReferenceExpression)) { + break; + } + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)parent; + final String name = referenceExpression.getReferenceName(); + if (!"append".equals(name)) { + if (!"toString".equals(name)) { + return null; + } + found = true; + } + final PsiElement grandParent = parent.getParent(); + if (!(grandParent instanceof PsiMethodCallExpression)) { + break; + } + completeExpression = grandParent; + if (found) { + return (PsiExpression) completeExpression; + } + } + 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 fbc4c4e90c9d..601059cf5a26 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 @@ -27,4 +27,11 @@ 'StringBuffer' can be replaced with 'String' <code>StringBuffer buffer</code> can be replaced with 'String' #loc + + + StringBufferReplaceableByString.java + 25 + 'StringBuffer' can be replaced with 'String' + <code>StringBuilder</code> can be replaced with 'String' #loc + \ No newline at end of file