mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-147586 (Replace StringBuilder with String does not keep final modifier)
This commit is contained in:
+355
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright 2003-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.siyeh.ig.style;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.TypeUtils;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class StringBufferReplaceableByStringInspectionBase extends BaseInspection {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("string.buffer.replaceable.by.string.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
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
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new StringBufferReplaceableByStringVisitor();
|
||||
}
|
||||
|
||||
private static class StringBufferReplaceableByStringVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(@NotNull PsiLocalVariable variable) {
|
||||
super.visitLocalVariable(variable);
|
||||
final PsiType type = variable.getType();
|
||||
if (!TypeUtils.typeEquals(CommonClassNames.JAVA_LANG_STRING_BUFFER, type) &&
|
||||
!TypeUtils.typeEquals(CommonClassNames.JAVA_LANG_STRING_BUILDER, type)) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression initializer = variable.getInitializer();
|
||||
if (!isNewStringBufferOrStringBuilder(initializer)) {
|
||||
return;
|
||||
}
|
||||
final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
|
||||
if (codeBlock == null) {
|
||||
return;
|
||||
}
|
||||
final ReplaceableByStringVisitor visitor = new ReplaceableByStringVisitor(variable);
|
||||
codeBlock.accept(visitor);
|
||||
if (!visitor.isReplaceable()) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
private static boolean isNewStringBufferOrStringBuilder(PsiExpression expression) {
|
||||
if (expression == null) {
|
||||
return false;
|
||||
}
|
||||
if (expression instanceof PsiNewExpression) {
|
||||
return true;
|
||||
}
|
||||
if (!isAppendCall(expression) || !(expression instanceof PsiMethodCallExpression)) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
|
||||
final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
|
||||
final PsiExpression qualifier = methodExpression.getQualifierExpression();
|
||||
return isNewStringBufferOrStringBuilder(qualifier);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isAppendCall(PsiElement element) {
|
||||
if (!(element instanceof PsiMethodCallExpression)) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element;
|
||||
final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
|
||||
@NonNls final String methodName = methodExpression.getReferenceName();
|
||||
if (!"append".equals(methodName)) {
|
||||
return false;
|
||||
}
|
||||
final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
if (arguments.length == 3) {
|
||||
return arguments[0].getType() instanceof PsiArrayType &&
|
||||
PsiType.INT.equals(arguments[1].getType()) && PsiType.INT.equals(arguments[2].getType());
|
||||
}
|
||||
return arguments.length == 1;
|
||||
}
|
||||
|
||||
private static boolean isToStringCall(PsiElement element) {
|
||||
if (!(element instanceof PsiMethodCallExpression)) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element;
|
||||
final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
|
||||
@NonNls final String methodName = methodExpression.getReferenceName();
|
||||
if (!"toString".equals(methodName)) {
|
||||
return false;
|
||||
}
|
||||
final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
return arguments.length == 0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static PsiExpression getCompleteExpression(PsiElement element) {
|
||||
PsiElement completeExpression = element;
|
||||
boolean found = false;
|
||||
while (true) {
|
||||
final PsiElement parent = completeExpression.getParent();
|
||||
if (!(parent instanceof PsiReferenceExpression)) {
|
||||
break;
|
||||
}
|
||||
final PsiElement grandParent = parent.getParent();
|
||||
if (isToStringCall(grandParent)) {
|
||||
found = true;
|
||||
} else if (!isAppendCall(grandParent)) {
|
||||
return null;
|
||||
}
|
||||
completeExpression = grandParent;
|
||||
if (found) {
|
||||
return (PsiExpression)completeExpression;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ReplaceableByStringVisitor extends JavaRecursiveElementWalkingVisitor {
|
||||
|
||||
private final PsiElement myParent;
|
||||
private final PsiVariable myVariable;
|
||||
private boolean myReplaceable = true;
|
||||
private boolean myPossibleSideEffect;
|
||||
private boolean myToStringFound;
|
||||
|
||||
ReplaceableByStringVisitor(@NotNull PsiVariable variable) {
|
||||
myVariable = variable;
|
||||
myParent = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class, PsiIfStatement.class, PsiLoopStatement.class);
|
||||
}
|
||||
|
||||
public boolean isReplaceable() {
|
||||
return myReplaceable && myToStringFound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (!myReplaceable) {
|
||||
return;
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAssignmentExpression(PsiAssignmentExpression expression) {
|
||||
super.visitAssignmentExpression(expression);
|
||||
if (expression.getTextOffset() > myVariable.getTextOffset() && !myToStringFound) {
|
||||
myPossibleSideEffect = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPostfixExpression(PsiPostfixExpression expression) {
|
||||
super.visitPostfixExpression(expression);
|
||||
if (expression.getTextOffset() > myVariable.getTextOffset() && !myToStringFound) {
|
||||
myPossibleSideEffect = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPrefixExpression(PsiPrefixExpression expression) {
|
||||
super.visitPrefixExpression(expression);
|
||||
if (expression.getTextOffset() > myVariable.getTextOffset() && !myToStringFound) {
|
||||
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 PsiExpressionList parent = PsiTreeUtil.getParentOfType(expression, PsiExpressionList.class, true, PsiStatement.class);
|
||||
if (parent == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement grandParent = parent.getParent();
|
||||
if (grandParent instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)grandParent;
|
||||
if (!isCallToStringBuilderMethod(methodCallExpression)) {
|
||||
return isArgumentOfStringBuilderMethod(methodCallExpression);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (grandParent instanceof PsiNewExpression) {
|
||||
final PsiLocalVariable variable = PsiTreeUtil.getParentOfType(grandParent, PsiLocalVariable.class, true, PsiExpressionList.class);
|
||||
if (!myVariable.equals(variable)) {
|
||||
return false;
|
||||
}
|
||||
final PsiNewExpression newExpression = (PsiNewExpression)grandParent;
|
||||
final PsiMethod constructor = newExpression.resolveMethod();
|
||||
if (constructor == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiClass aClass = constructor.getContainingClass();
|
||||
if (aClass == null) {
|
||||
return false;
|
||||
}
|
||||
final String name = aClass.getQualifiedName();
|
||||
return CommonClassNames.JAVA_LANG_STRING_BUFFER.equals(name) ||
|
||||
CommonClassNames.JAVA_LANG_STRING_BUILDER.equals(name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCallToStringBuilderMethod(PsiMethodCallExpression methodCallExpression) {
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
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();
|
||||
return CommonClassNames.JAVA_LANG_STRING_BUFFER.equals(name1) ||
|
||||
CommonClassNames.JAVA_LANG_STRING_BUILDER.equals(name1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
if (!myReplaceable || expression.getTextOffset() < myVariable.getTextOffset()) {
|
||||
return;
|
||||
}
|
||||
super.visitReferenceExpression(expression);
|
||||
final PsiExpression qualifier = expression.getQualifierExpression();
|
||||
if (qualifier != null) {
|
||||
return;
|
||||
}
|
||||
final PsiElement target = expression.resolve();
|
||||
if (!myVariable.equals(target)) {
|
||||
return;
|
||||
}
|
||||
if (myToStringFound) {
|
||||
myReplaceable = false;
|
||||
return;
|
||||
}
|
||||
final PsiElement element = PsiTreeUtil.getParentOfType(expression, PsiCodeBlock.class, PsiIfStatement.class, PsiLoopStatement.class);
|
||||
if (!myParent.equals(element)) {
|
||||
myReplaceable = false;
|
||||
return;
|
||||
}
|
||||
PsiElement parent = expression.getParent();
|
||||
while (true) {
|
||||
if (!(parent instanceof PsiReferenceExpression)) {
|
||||
myReplaceable = false;
|
||||
return;
|
||||
}
|
||||
final PsiElement grandParent = parent.getParent();
|
||||
if (!isAppendCall(grandParent)) {
|
||||
if (!isToStringCall(grandParent)) {
|
||||
myReplaceable = false;
|
||||
return;
|
||||
}
|
||||
myToStringFound = true;
|
||||
return;
|
||||
}
|
||||
if (myPossibleSideEffect) {
|
||||
myReplaceable = false;
|
||||
return;
|
||||
}
|
||||
parent = grandParent.getParent();
|
||||
if (parent instanceof PsiExpressionStatement) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-332
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2015 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,39 +19,23 @@ import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.PsiReplacementUtil;
|
||||
import com.siyeh.ig.psiutils.ParenthesesUtils;
|
||||
import com.siyeh.ig.psiutils.TypeUtils;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StringBufferReplaceableByStringInspection extends BaseInspection {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("string.buffer.replaceable.by.string.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
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);
|
||||
}
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class StringBufferReplaceableByStringInspection extends StringBufferReplaceableByStringInspectionBase {
|
||||
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
@@ -146,9 +130,11 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection {
|
||||
if (statement == null) {
|
||||
return;
|
||||
}
|
||||
final String modifier = CodeStyleSettingsManager.getSettings(project).GENERATE_FINAL_LOCALS ? "final " : "";
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
final PsiStatement newStatement =
|
||||
factory.createStatementFromText(CommonClassNames.JAVA_LANG_STRING + ' ' + variable.getName() + '=' + expression + ';', variable);
|
||||
factory.createStatementFromText(modifier + CommonClassNames.JAVA_LANG_STRING + ' ' + variable.getName() + '=' +
|
||||
expression + ';', variable);
|
||||
codeBlock.addBefore(newStatement, statement);
|
||||
}
|
||||
variable.delete();
|
||||
@@ -367,313 +353,4 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new StringBufferReplaceableByStringVisitor();
|
||||
}
|
||||
|
||||
private static class StringBufferReplaceableByStringVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(@NotNull PsiLocalVariable variable) {
|
||||
super.visitLocalVariable(variable);
|
||||
final PsiType type = variable.getType();
|
||||
if (!TypeUtils.typeEquals(CommonClassNames.JAVA_LANG_STRING_BUFFER, type) &&
|
||||
!TypeUtils.typeEquals(CommonClassNames.JAVA_LANG_STRING_BUILDER, type)) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression initializer = variable.getInitializer();
|
||||
if (!isNewStringBufferOrStringBuilder(initializer)) {
|
||||
return;
|
||||
}
|
||||
final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class);
|
||||
if (codeBlock == null) {
|
||||
return;
|
||||
}
|
||||
final ReplaceableByStringVisitor visitor = new ReplaceableByStringVisitor(variable);
|
||||
codeBlock.accept(visitor);
|
||||
if (!visitor.isReplaceable()) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
private static boolean isNewStringBufferOrStringBuilder(PsiExpression expression) {
|
||||
if (expression == null) {
|
||||
return false;
|
||||
}
|
||||
if (expression instanceof PsiNewExpression) {
|
||||
return true;
|
||||
}
|
||||
if (!isAppendCall(expression) || !(expression instanceof PsiMethodCallExpression)) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
|
||||
final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
|
||||
final PsiExpression qualifier = methodExpression.getQualifierExpression();
|
||||
return isNewStringBufferOrStringBuilder(qualifier);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAppendCall(PsiElement element) {
|
||||
if (!(element instanceof PsiMethodCallExpression)) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element;
|
||||
final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
|
||||
@NonNls final String methodName = methodExpression.getReferenceName();
|
||||
if (!"append".equals(methodName)) {
|
||||
return false;
|
||||
}
|
||||
final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
if (arguments.length == 3) {
|
||||
return arguments[0].getType() instanceof PsiArrayType &&
|
||||
PsiType.INT.equals(arguments[1].getType()) && PsiType.INT.equals(arguments[2].getType());
|
||||
}
|
||||
return arguments.length == 1;
|
||||
}
|
||||
|
||||
private static boolean isToStringCall(PsiElement element) {
|
||||
if (!(element instanceof PsiMethodCallExpression)) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element;
|
||||
final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
|
||||
@NonNls final String methodName = methodExpression.getReferenceName();
|
||||
if (!"toString".equals(methodName)) {
|
||||
return false;
|
||||
}
|
||||
final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
return arguments.length == 0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiExpression getCompleteExpression(PsiElement element) {
|
||||
PsiElement completeExpression = element;
|
||||
boolean found = false;
|
||||
while (true) {
|
||||
final PsiElement parent = completeExpression.getParent();
|
||||
if (!(parent instanceof PsiReferenceExpression)) {
|
||||
break;
|
||||
}
|
||||
final PsiElement grandParent = parent.getParent();
|
||||
if (isToStringCall(grandParent)) {
|
||||
found = true;
|
||||
} else if (!isAppendCall(grandParent)) {
|
||||
return null;
|
||||
}
|
||||
completeExpression = grandParent;
|
||||
if (found) {
|
||||
return (PsiExpression)completeExpression;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ReplaceableByStringVisitor extends JavaRecursiveElementWalkingVisitor {
|
||||
|
||||
private final PsiElement myParent;
|
||||
private final PsiVariable myVariable;
|
||||
private boolean myReplaceable = true;
|
||||
private boolean myPossibleSideEffect;
|
||||
private boolean myToStringFound;
|
||||
|
||||
ReplaceableByStringVisitor(@NotNull PsiVariable variable) {
|
||||
myVariable = variable;
|
||||
myParent = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class, PsiIfStatement.class, PsiLoopStatement.class);
|
||||
}
|
||||
|
||||
public boolean isReplaceable() {
|
||||
return myReplaceable && myToStringFound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (!myReplaceable) {
|
||||
return;
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAssignmentExpression(PsiAssignmentExpression expression) {
|
||||
super.visitAssignmentExpression(expression);
|
||||
if (expression.getTextOffset() > myVariable.getTextOffset() && !myToStringFound) {
|
||||
myPossibleSideEffect = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPostfixExpression(PsiPostfixExpression expression) {
|
||||
super.visitPostfixExpression(expression);
|
||||
if (expression.getTextOffset() > myVariable.getTextOffset() && !myToStringFound) {
|
||||
myPossibleSideEffect = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPrefixExpression(PsiPrefixExpression expression) {
|
||||
super.visitPrefixExpression(expression);
|
||||
if (expression.getTextOffset() > myVariable.getTextOffset() && !myToStringFound) {
|
||||
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 PsiExpressionList parent = PsiTreeUtil.getParentOfType(expression, PsiExpressionList.class, true, PsiStatement.class);
|
||||
if (parent == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement grandParent = parent.getParent();
|
||||
if (grandParent instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)grandParent;
|
||||
if (!isCallToStringBuilderMethod(methodCallExpression)) {
|
||||
return isArgumentOfStringBuilderMethod(methodCallExpression);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (grandParent instanceof PsiNewExpression) {
|
||||
final PsiLocalVariable variable = PsiTreeUtil.getParentOfType(grandParent, PsiLocalVariable.class, true, PsiExpressionList.class);
|
||||
if (!myVariable.equals(variable)) {
|
||||
return false;
|
||||
}
|
||||
final PsiNewExpression newExpression = (PsiNewExpression)grandParent;
|
||||
final PsiMethod constructor = newExpression.resolveMethod();
|
||||
if (constructor == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiClass aClass = constructor.getContainingClass();
|
||||
if (aClass == null) {
|
||||
return false;
|
||||
}
|
||||
final String name = aClass.getQualifiedName();
|
||||
return CommonClassNames.JAVA_LANG_STRING_BUFFER.equals(name) ||
|
||||
CommonClassNames.JAVA_LANG_STRING_BUILDER.equals(name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCallToStringBuilderMethod(PsiMethodCallExpression methodCallExpression) {
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
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();
|
||||
return CommonClassNames.JAVA_LANG_STRING_BUFFER.equals(name1) ||
|
||||
CommonClassNames.JAVA_LANG_STRING_BUILDER.equals(name1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
if (!myReplaceable || expression.getTextOffset() < myVariable.getTextOffset()) {
|
||||
return;
|
||||
}
|
||||
super.visitReferenceExpression(expression);
|
||||
final PsiExpression qualifier = expression.getQualifierExpression();
|
||||
if (qualifier != null) {
|
||||
return;
|
||||
}
|
||||
final PsiElement target = expression.resolve();
|
||||
if (!myVariable.equals(target)) {
|
||||
return;
|
||||
}
|
||||
if (myToStringFound) {
|
||||
myReplaceable = false;
|
||||
return;
|
||||
}
|
||||
final PsiElement element = PsiTreeUtil.getParentOfType(expression, PsiCodeBlock.class, PsiIfStatement.class, PsiLoopStatement.class);
|
||||
if (!myParent.equals(element)) {
|
||||
myReplaceable = false;
|
||||
return;
|
||||
}
|
||||
PsiElement parent = expression.getParent();
|
||||
while (true) {
|
||||
if (!(parent instanceof PsiReferenceExpression)) {
|
||||
myReplaceable = false;
|
||||
return;
|
||||
}
|
||||
final PsiElement grandParent = parent.getParent();
|
||||
if (!isAppendCall(grandParent)) {
|
||||
if (!isToStringCall(grandParent)) {
|
||||
myReplaceable = false;
|
||||
return;
|
||||
}
|
||||
myToStringFound = true;
|
||||
return;
|
||||
}
|
||||
if (myPossibleSideEffect) {
|
||||
myReplaceable = false;
|
||||
return;
|
||||
}
|
||||
parent = grandParent.getParent();
|
||||
if (parent instanceof PsiExpressionStatement) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user