move operator assignment check for object to javac quirks inspection with fix (IDEA-154209)

This commit is contained in:
Anna.Kozlova
2016-04-06 17:15:12 +02:00
parent 400f80a507
commit 56a3a1ffa4
7 changed files with 123 additions and 51 deletions
@@ -436,8 +436,7 @@ public class HighlightUtil extends HighlightUtilBase {
if (rExpression == null) return null;
final PsiType rType = rExpression.getType();
HighlightInfo errorResult = null;
if (!TypeConversionUtil.isBinaryOperatorApplicable(opSign, lType, rType, true) ||
PsiType.getJavaLangObject(containingFile.getManager(), assignment.getResolveScope()).equals(lType)) {
if (!TypeConversionUtil.isBinaryOperatorApplicable(opSign, lType, rType, true)) {
String operatorText = operationSign.getText().substring(0, operationSign.getText().length() - 1);
String message = JavaErrorMessages.message("binary.operator.not.applicable", operatorText,
JavaHighlightUtil.formatType(lType),
@@ -16,16 +16,21 @@
package com.intellij.codeInspection.compiler;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
import com.intellij.codeInspection.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.patterns.ElementPattern;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.siyeh.ig.PsiReplacementUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
@@ -73,6 +78,28 @@ public class JavacQuirksInspectionVisitor extends JavaElementVisitor {
}
}
@Override
public void visitAssignmentExpression(PsiAssignmentExpression assignment) {
super.visitAssignmentExpression(assignment);
final PsiType lType = assignment.getLExpression().getType();
PsiJavaToken operationSign = assignment.getOperationSign();
IElementType eqOpSign = operationSign.getTokenType();
IElementType opSign = TypeConversionUtil.convertEQtoOperation(eqOpSign);
if (opSign == null) return;
final PsiExpression rExpression = assignment.getRExpression();
if (rExpression == null) return;
if (JavaSdkVersion.JDK_1_6.equals(JavaVersionService.getInstance().getJavaSdkVersion(assignment)) &&
PsiType.getJavaLangObject(assignment.getManager(), assignment.getResolveScope()).equals(lType)) {
String operatorText = operationSign.getText().substring(0, operationSign.getText().length() - 1);
String message = JavaErrorMessages.message("binary.operator.not.applicable", operatorText,
JavaHighlightUtil.formatType(lType),
JavaHighlightUtil.formatType(rExpression.getType()));
myHolder.registerProblem(assignment, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
new ReplaceAssignmentOperatorWithAssignmentFix(operationSign.getText()));
}
}
@Override
public void visitIdentifier(PsiIdentifier identifier) {
super.visitIdentifier(identifier);
@@ -83,4 +110,34 @@ public class JavacQuirksInspectionVisitor extends JavaElementVisitor {
myHolder.registerProblem(identifier, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
}
}
private static class ReplaceAssignmentOperatorWithAssignmentFix implements LocalQuickFix {
private final String myOperationSign;
public ReplaceAssignmentOperatorWithAssignmentFix(String operationSign) {
myOperationSign = operationSign;
}
@Nls
@NotNull
@Override
public String getName() {
return "Replace ''" + myOperationSign + "'' with ''=''";
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return "Replace Operator Assignment with Assignment";
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
if (element instanceof PsiAssignmentExpression) {
PsiReplacementUtil.replaceOperatorAssignmentWithAssignmentExpression((PsiAssignmentExpression)element);
}
}
}
}
@@ -44,7 +44,7 @@ public class a {
ia[~i | (i+=(!b?2:i))] -= i + 3.3;
// Object += String
<error descr="Operator '+' cannot be applied to 'java.lang.Object', 'java.lang.String'">o += o + "string"</error>;
o += o + "string";
return 0;
}
@@ -0,0 +1,7 @@
class Test {
{
Object o = "";
<warning descr="Operator '+' cannot be applied to 'java.lang.Object', 'java.lang.String'">o += ""</warning>;
System.out.println(o);
}
}
@@ -61,4 +61,8 @@ public class LightAdvHighlightingJdk6Test extends LightDaemonAnalyzerTestCase {
public void testUnreachableAssignments() { doTest(false, false); }
public void testCompileTypeConstantsAccessibleFromStaticFieldInitializers() { doTest(false, false);}
public void testInheritUnrelatedConcreteMethodsWithSameSignature() { doTest(false, false);}
public void testAssignmentFromStringToObject() {
doTest(true, false);
}
}
@@ -26,6 +26,8 @@ import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.util.FileTypeUtils;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.psi.util.TypeConversionUtil;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -148,4 +150,48 @@ public class PsiReplacementUtil {
getElementText(child, elementToReplace, replacement, out);
}
}
public static void replaceOperatorAssignmentWithAssignmentExpression(@NotNull PsiAssignmentExpression assignmentExpression) {
final PsiJavaToken sign = assignmentExpression.getOperationSign();
final PsiExpression lhs = assignmentExpression.getLExpression();
final PsiExpression rhs = assignmentExpression.getRExpression();
final String operator = sign.getText();
final String newOperator = operator.substring(0, operator.length() - 1);
final String lhsText = lhs.getText();
final String rhsText = (rhs == null) ? "" : rhs.getText();
final boolean parentheses = ParenthesesUtils.areParenthesesNeeded(sign, rhs);
final String cast = getCastString(lhs, rhs);
final StringBuilder newExpression = new StringBuilder(lhsText);
newExpression.append('=').append(cast);
if (!cast.isEmpty()) {
newExpression.append('(');
}
newExpression.append(lhsText).append(newOperator);
if (parentheses) {
newExpression.append('(').append(rhsText).append(')');
}
else {
newExpression.append(rhsText);
}
if (!cast.isEmpty()) {
newExpression.append(')');
}
replaceExpression(assignmentExpression, newExpression.toString());
}
private static String getCastString(PsiExpression lhs, PsiExpression rhs) {
if (lhs == null || rhs == null) {
return "";
}
final PsiType lType = lhs.getType();
PsiType rType = rhs.getType();
if (TypeConversionUtil.isNumericType(rType)) {
rType = TypeConversionUtil.binaryNumericPromotion(lType, rType);
}
if (lType == null || rType == null ||
TypeConversionUtil.isAssignable(lType, rType) || !TypeConversionUtil.areTypesConvertible(lType, rType)) {
return "";
}
return '(' + lType.getCanonicalText() + ')';
}
}
@@ -15,11 +15,11 @@
*/
package com.siyeh.ipp.opassign;
import com.intellij.psi.*;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.PsiAssignmentExpression;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiJavaToken;
import com.siyeh.IntentionPowerPackBundle;
import com.siyeh.ig.PsiReplacementUtil;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import com.siyeh.ipp.base.MutablyNamedIntention;
import com.siyeh.ipp.base.PsiElementPredicate;
import org.jetbrains.annotations.NotNull;
@@ -42,47 +42,6 @@ public class ReplaceOperatorAssignmentWithAssignmentIntention extends MutablyNam
@Override
protected void processIntention(@NotNull PsiElement element) {
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)element;
final PsiJavaToken sign = assignmentExpression.getOperationSign();
final PsiExpression lhs = assignmentExpression.getLExpression();
final PsiExpression rhs = assignmentExpression.getRExpression();
final String operator = sign.getText();
final String newOperator = operator.substring(0, operator.length() - 1);
final String lhsText = lhs.getText();
final String rhsText = (rhs == null) ? "" : rhs.getText();
final boolean parentheses = ParenthesesUtils.areParenthesesNeeded(sign, rhs);
final String cast = getCastString(lhs, rhs);
final StringBuilder newExpression = new StringBuilder(lhsText);
newExpression.append('=').append(cast);
if (!cast.isEmpty()) {
newExpression.append('(');
}
newExpression.append(lhsText).append(newOperator);
if (parentheses) {
newExpression.append('(').append(rhsText).append(')');
}
else {
newExpression.append(rhsText);
}
if (!cast.isEmpty()) {
newExpression.append(')');
}
PsiReplacementUtil.replaceExpression(assignmentExpression, newExpression.toString());
}
private static String getCastString(PsiExpression lhs, PsiExpression rhs) {
if (lhs == null || rhs == null) {
return "";
}
final PsiType lType = lhs.getType();
PsiType rType = rhs.getType();
if (TypeConversionUtil.isNumericType(rType)) {
rType = TypeConversionUtil.binaryNumericPromotion(lType, rType);
}
if (lType == null || rType == null ||
TypeConversionUtil.isAssignable(lType, rType) || !TypeConversionUtil.areTypesConvertible(lType, rType)) {
return "";
}
return '(' + lType.getCanonicalText() + ')';
PsiReplacementUtil.replaceOperatorAssignmentWithAssignmentExpression((PsiAssignmentExpression)element);
}
}