java convert to atomic intention: assignment conversion fix IDEA-161639

This commit is contained in:
Dmitry Batkovich
2016-09-23 15:22:26 +03:00
parent b1ff2b019e
commit 23731ae9ad
4 changed files with 85 additions and 14 deletions
@@ -7,7 +7,6 @@ import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
@@ -21,15 +20,14 @@ import com.intellij.refactoring.typeMigration.TypeConversionDescriptor;
import com.intellij.refactoring.typeMigration.TypeEvaluator;
import com.intellij.refactoring.typeMigration.TypeMigrationReplacementUtil;
import com.intellij.refactoring.typeMigration.rules.AtomicConversionRule;
import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Query;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.*;
@@ -160,7 +158,8 @@ public class ConvertFieldToAtomicIntention extends PsiElementBaseIntentionAction
try {
for (PsiReference reference : refs) {
PsiElement psiElement = reference.getElement();
PsiElement refElement = reference.getElement();
PsiElement psiElement = refElement;
if (psiElement instanceof PsiExpression) {
final PsiElement parent = psiElement.getParent();
if (parent instanceof PsiExpression && !(parent instanceof PsiReferenceExpression || parent instanceof PsiPolyadicExpression)) {
@@ -168,14 +167,14 @@ public class ConvertFieldToAtomicIntention extends PsiElementBaseIntentionAction
}
if (psiElement instanceof PsiBinaryExpression) {
PsiBinaryExpression binary = (PsiBinaryExpression)psiElement;
if (isBinaryOperatorApplicable(binary.getOperationTokenType(), binary.getLOperand(), binary.getROperand(), true)) {
if (isBinaryOpApplicable(binary.getOperationTokenType(), binary.getLOperand(), binary.getROperand(), refElement, toType)) {
continue;
}
}
else if (psiElement instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignment = (PsiAssignmentExpression)psiElement;
final IElementType opSign = TypeConversionUtil.convertEQtoOperation(assignment.getOperationTokenType());
if (opSign != null && isBinaryOperatorApplicable(opSign, assignment.getLExpression(), assignment.getRExpression(), true)) {
if (isBinaryOpApplicable(opSign, assignment.getLExpression(), assignment.getRExpression(), refElement, toType)) {
continue;
}
}
@@ -227,4 +226,15 @@ public class ConvertFieldToAtomicIntention extends PsiElementBaseIntentionAction
public boolean startInWriteAction() {
return true;
}
private static boolean isBinaryOpApplicable(@Nullable IElementType opSign,
@NotNull PsiExpression lExpr,
@Nullable PsiExpression rExpr,
@NotNull PsiElement varElement,
@NotNull PsiType migrationType) {
if (opSign == null || rExpr == null) return false;
PsiType lType = lExpr == varElement ? migrationType : lExpr.getType();
PsiType rType = rExpr == varElement ? migrationType : rExpr.getType();
return isBinaryOperatorApplicable(opSign, lType, rType, true);
}
}
@@ -7,13 +7,16 @@ package com.intellij.refactoring.typeMigration.rules;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.PsiDiamondTypeUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.typeMigration.TypeConversionDescriptor;
import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase;
import com.intellij.refactoring.typeMigration.TypeEvaluator;
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -114,9 +117,22 @@ public class AtomicConversionRule extends TypeConversionRule {
final IElementType operationSign = signToken.getTokenType();
final String sign = signToken.getText();
if (operationSign == JavaTokenType.PLUSEQ || operationSign == JavaTokenType.MINUSEQ) {
return new TypeConversionDescriptor("$qualifier$ " + sign + " $val$", "$qualifier$.getAndAdd(" +
(operationSign == JavaTokenType.MINUSEQ ? "-" : "") +
"($val$))");
return new TypeConversionDescriptor("$qualifier$ " + sign + " $val$",
"$qualifier$.addAndGet(" + (operationSign == JavaTokenType.MINUSEQ ? "-($val$))" : "$val$)")) {
@Override
public PsiExpression replace(PsiExpression expression, TypeEvaluator evaluator) {
final PsiMethodCallExpression result = (PsiMethodCallExpression)super.replace(expression, evaluator);
final PsiExpression argument = result.getArgumentList().getExpressions()[0];
if (argument instanceof PsiPrefixExpression) {
final PsiExpression operand = ((PsiPrefixExpression)argument).getOperand();
final PsiExpression striped = ParenthesesUtils.stripParentheses(operand);
if (striped != null && operand != striped) {
operand.replace(striped);
}
}
return result;
}
};
}
}
}
@@ -198,11 +214,22 @@ public class AtomicConversionRule extends TypeConversionRule {
return new TypeConversionDescriptor("$qualifier$ = $val$", "$qualifier$.set($val$)");
}
else {
return new TypeConversionDescriptor("$qualifier$" + sign + "$val$", "$qualifier$.set(" +
getBoxedWrapper(from, to, "$qualifier$.get() " +
sign.charAt(0) +
" $val$") +
")");
if (PsiUtil.isLanguageLevel8OrHigher(context)) {
final String name =
JavaCodeStyleManager.getInstance(context.getProject()).suggestUniqueVariableName("v", context, false);
return new TypeConversionDescriptor("$qualifier$" + sign + "$val$", "$qualifier$.updateAndGet("
+ name + " -> " + name + " " + sign.charAt(0) + " $val$)"); }
else {
if (context.getParent() instanceof PsiStatement) {
return new TypeConversionDescriptor("$qualifier$" + sign + "$val$", "$qualifier$.set(" +
getBoxedWrapper(from, to, "$qualifier$.get() " +
sign.charAt(0) +
" $val$") +
")");
} else {
return null;
}
}
}
} //else should be a conflict
}
@@ -0,0 +1,18 @@
import java.util.concurrent.atomic.AtomicLong;
// "Convert to atomic" "true"
class A {
final AtomicLong x = new AtomicLong(0);
public void testAtomicLong() {
x.getAndIncrement();
x.getAndDecrement();
x.addAndGet(2);
x.addAndGet(-2);
x.updateAndGet(v -> v * 3);
x.updateAndGet(v -> v / 3);
x.updateAndGet(v -> v % 3);
x.updateAndGet(v -> v & 3);
x.updateAndGet(v -> v | 3);
}
}
@@ -0,0 +1,16 @@
// "Convert to atomic" "true"
class A {
long <caret>x = 0;
public void testAtomicLong() {
x++;
x--;
x+=2;
x-=2;
x*=3;
x/=3;
x%=3;
x&=3;
x|=3;
}
}