summaryrefslogtreecommitdiff
path: root/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java')
-rw-r--r--java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java420
1 files changed, 420 insertions, 0 deletions
diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java
new file mode 100644
index 000000000000..a4ec46e44838
--- /dev/null
+++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/AtomicConversionRule.java
@@ -0,0 +1,420 @@
+/*
+ * User: anna
+ * Date: 18-Aug-2009
+ */
+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.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.TypeMigrationLabeler;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.concurrent.atomic.*;
+
+public class AtomicConversionRule extends TypeConversionRule {
+ private static final Logger LOG = Logger.getInstance("#" + AtomicConversionRule.class.getName());
+
+
+ @Override
+ public TypeConversionDescriptorBase findConversion(PsiType from,
+ PsiType to,
+ PsiMember member,
+ PsiExpression context,
+ TypeMigrationLabeler labeler) {
+ if (to instanceof PsiClassType && isAtomicTypeMigration(from, (PsiClassType)to, context)) {
+ return findDirectConversion(context, to, from);
+ }
+ else if (from instanceof PsiClassType && isAtomicTypeMigration(to, (PsiClassType)from, context)) {
+ return findReverseConversion(context);
+ }
+ return null;
+ }
+
+ private static boolean isAtomicTypeMigration(PsiType from, PsiClassType to, PsiExpression context) {
+ if (from == PsiType.INT && to.getCanonicalText().equals(AtomicInteger.class.getName())) {
+ return true;
+ }
+ if (from.equals(PsiType.INT.createArrayType()) && to.getCanonicalText().equals(AtomicIntegerArray.class.getName())) {
+ return true;
+ }
+ if (from == PsiType.LONG && to.getCanonicalText().equals(AtomicLong.class.getName())) {
+ return true;
+ }
+ if (from.equals(PsiType.LONG.createArrayType()) && to.getCanonicalText().equals(AtomicLongArray.class.getName())) {
+ return true;
+ }
+ if (from == PsiType.BOOLEAN && to.getCanonicalText().equals(AtomicBoolean.class.getName())) {
+ return true;
+ }
+ final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(to);
+ final PsiClass atomicClass = resolveResult.getElement();
+
+ if (atomicClass != null) {
+ final String typeQualifiedName = atomicClass.getQualifiedName();
+ if (!Comparing.strEqual(typeQualifiedName, AtomicReference.class.getName()) &&
+ !Comparing.strEqual(typeQualifiedName, AtomicReferenceArray.class.getName())) {
+ return false;
+ }
+ final PsiTypeParameter[] typeParameters = atomicClass.getTypeParameters();
+ if (typeParameters.length != 1) return false;
+ final PsiType toTypeParameterValue = resolveResult.getSubstitutor().substitute(typeParameters[0]);
+ if (toTypeParameterValue != null) {
+ if (from.getDeepComponentType() instanceof PsiPrimitiveType) {
+ final PsiPrimitiveType unboxedInitialType = PsiPrimitiveType.getUnboxedType(toTypeParameterValue);
+ if (unboxedInitialType != null) {
+ return TypeConversionUtil.areTypesConvertible(from.getDeepComponentType(), unboxedInitialType);
+ }
+ }
+ else {
+ return TypeConversionUtil.isAssignable(from.getDeepComponentType(), PsiUtil.captureToplevelWildcards(toTypeParameterValue, context));
+ }
+ }
+ }
+ return false;
+ }
+
+ @Nullable
+ public static TypeConversionDescriptor findDirectConversion(PsiElement context, PsiType to, PsiType from) {
+ final PsiClass toTypeClass = PsiUtil.resolveClassInType(to);
+ LOG.assertTrue(toTypeClass != null);
+ final String qualifiedName = toTypeClass.getQualifiedName();
+ if (qualifiedName != null) {
+ if (qualifiedName.equals(AtomicInteger.class.getName()) || qualifiedName.equals(AtomicLong.class.getName())) {
+
+ if (context instanceof PsiPostfixExpression) {
+ final IElementType operationSign = ((PsiPostfixExpression)context).getOperationTokenType();
+ if (operationSign == JavaTokenType.MINUSMINUS) {
+ return new TypeConversionDescriptor("$qualifier$--", "$qualifier$.getAndDecrement()");
+ }
+ if (operationSign == JavaTokenType.PLUSPLUS) {
+ return new TypeConversionDescriptor("$qualifier$++", "$qualifier$.getAndIncrement()");
+ }
+
+ }
+ else if (context instanceof PsiPrefixExpression) {
+ final IElementType operationSign = ((PsiPrefixExpression)context).getOperationTokenType();
+ if (operationSign == JavaTokenType.MINUSMINUS) {
+ return new TypeConversionDescriptor("--$qualifier$", "$qualifier$.decrementAndGet()");
+ }
+ if (operationSign == JavaTokenType.PLUSPLUS) {
+ return new TypeConversionDescriptor("++$qualifier$", "$qualifier$.incrementAndGet()");
+ }
+
+ }
+ else if (context instanceof PsiAssignmentExpression) {
+ final PsiJavaToken signToken = ((PsiAssignmentExpression)context).getOperationSign();
+ 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$))");
+ }
+ }
+ }
+ else if (qualifiedName.equals(AtomicIntegerArray.class.getName()) || qualifiedName.equals(AtomicLongArray.class.getName())) {
+ PsiElement parentExpression = context.getParent();
+ if (parentExpression instanceof PsiPostfixExpression) {
+ final IElementType operationSign = ((PsiPostfixExpression)parentExpression).getOperationTokenType();
+ if (operationSign == JavaTokenType.MINUSMINUS) {
+ return new TypeConversionDescriptor("$qualifier$[$idx$]--", "$qualifier$.getAndDecrement($idx$)",
+ (PsiExpression)parentExpression);
+ }
+ if (operationSign == JavaTokenType.PLUSPLUS) {
+ return new TypeConversionDescriptor("$qualifier$[$idx$]++", "$qualifier$.getAndIncrement($idx$)",
+ (PsiExpression)parentExpression);
+ }
+
+ }
+ else if (parentExpression instanceof PsiPrefixExpression) {
+ final IElementType operationSign = ((PsiPrefixExpression)parentExpression).getOperationTokenType();
+ if (operationSign == JavaTokenType.MINUSMINUS) {
+ return new TypeConversionDescriptor("--$qualifier$[$idx$]", "$qualifier$.decrementAndGet($idx$)",
+ (PsiExpression)parentExpression);
+ }
+ if (operationSign == JavaTokenType.PLUSPLUS) {
+ return new TypeConversionDescriptor("++$qualifier$[$idx$]", "$qualifier$.incrementAndGet($idx$)",
+ (PsiExpression)parentExpression);
+ }
+
+ }
+ else if (parentExpression instanceof PsiAssignmentExpression) {
+ final PsiJavaToken signToken = ((PsiAssignmentExpression)parentExpression).getOperationSign();
+ final IElementType operationSign = signToken.getTokenType();
+ final String sign = signToken.getText();
+ if (operationSign == JavaTokenType.PLUSEQ || operationSign == JavaTokenType.MINUSEQ) {
+ return new TypeConversionDescriptor("$qualifier$[$idx$] " + sign + " $val$", "$qualifier$.getAndAdd($idx$, " +
+ (operationSign == JavaTokenType.MINUSEQ
+ ? "-"
+ : "") +
+ "($val$))", (PsiExpression)parentExpression);
+ }
+ }
+ }
+ }
+ return from instanceof PsiArrayType
+ ? findDirectConversionForAtomicReferenceArray(context, to, from)
+ : findDirectConversionForAtomicReference(context, to, from);
+ }
+
+ @Nullable
+ private static TypeConversionDescriptor findDirectConversionForAtomicReference(PsiElement context, PsiType to, PsiType from) {
+ final PsiElement parent = context.getParent();
+ if (parent instanceof PsiAssignmentExpression) {
+ final IElementType operationSign = ((PsiAssignmentExpression)parent).getOperationTokenType();
+ if (operationSign == JavaTokenType.EQ) {
+ return new TypeConversionDescriptor("$qualifier$ = $val$", "$qualifier$.set($val$)", (PsiAssignmentExpression)parent);
+ }
+ }
+
+ if (context instanceof PsiReferenceExpression) {
+ final PsiExpression qualifierExpression = ((PsiReferenceExpression)context).getQualifierExpression();
+ final PsiExpression expression = context.getParent() instanceof PsiMethodCallExpression && qualifierExpression != null
+ ? qualifierExpression
+ : (PsiExpression)context;
+ return new TypeConversionDescriptor("$qualifier$", "$qualifier$.get()", expression);
+ }
+ else if (context instanceof PsiAssignmentExpression) {
+ final PsiJavaToken signToken = ((PsiAssignmentExpression)context).getOperationSign();
+ final IElementType operationSign = signToken.getTokenType();
+ final String sign = signToken.getText();
+ if (parent instanceof PsiExpressionStatement) {
+ if (operationSign == JavaTokenType.EQ) {
+ final PsiExpression lExpression = ((PsiAssignmentExpression)context).getLExpression();
+ if (lExpression instanceof PsiReferenceExpression) {
+ final PsiElement element = ((PsiReferenceExpression)lExpression).resolve();
+ if (element instanceof PsiVariable && ((PsiVariable)element).hasModifierProperty(PsiModifier.FINAL)) {
+ return wrapWithNewExpression(to, from, ((PsiAssignmentExpression)context).getRExpression(), element);
+ }
+ }
+ 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$") +
+ ")");
+ }
+ } //else should be a conflict
+ }
+ else if (context instanceof PsiPostfixExpression) {
+ final String sign = ((PsiPostfixExpression)context).getOperationSign().getText();
+ return new TypeConversionDescriptor("$qualifier$" + sign, "$qualifier$.getAndSet(" +
+ getBoxedWrapper(from, to, "$qualifier$.get() " + sign.charAt(0) + " 1") +
+ ")");
+ }
+ else if (context instanceof PsiPrefixExpression) {
+ final PsiJavaToken operationSign = ((PsiPrefixExpression)context).getOperationSign();
+ if (operationSign.getTokenType() == JavaTokenType.EXCL) {
+ return new TypeConversionDescriptor("!$qualifier$", "!$qualifier$.get()");
+ }
+ final String sign = operationSign.getText();
+ return new TypeConversionDescriptor(sign + "$qualifier$", "$qualifier$.set(" + //todo reject?
+ getBoxedWrapper(from, to, "$qualifier$.get() " + sign.charAt(0) + " 1") +
+ ")");
+ } else if (context instanceof PsiBinaryExpression) {
+ final String sign = ((PsiBinaryExpression)context).getOperationSign().getText();
+ return new TypeConversionDescriptor("$qualifier$" + sign + "$val$", "$qualifier$.get() " + sign + " $val$");
+ }
+
+ if (parent instanceof PsiVariable) {
+ return wrapWithNewExpression(to, from, null, parent);
+ }
+ return null;
+ }
+
+ public static TypeConversionDescriptor wrapWithNewExpression(PsiType to, PsiType from, @Nullable PsiExpression expression, PsiElement context) {
+ final String typeText = PsiDiamondTypeUtil.getCollapsedType(to, context);
+ final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(to);
+ final PsiClass atomicClass = resolveResult.getElement();
+ LOG.assertTrue(atomicClass != null);
+ final PsiTypeParameter[] typeParameters = atomicClass.getTypeParameters();
+ if (typeParameters.length == 1) {
+ final PsiType initial = resolveResult.getSubstitutor().substitute(typeParameters[0]);
+ final PsiPrimitiveType unboxedInitialType = PsiPrimitiveType.getUnboxedType(initial);
+ if (unboxedInitialType != null) {
+ LOG.assertTrue(initial != null);
+ if (from instanceof PsiPrimitiveType) {
+ final PsiClassType boxedFromType = ((PsiPrimitiveType)from).getBoxedType(atomicClass);
+ LOG.assertTrue(boxedFromType != null);
+ if (!TypeConversionUtil.isAssignable(initial, boxedFromType)) {
+ return new TypeConversionDescriptor("$val$", "new " + typeText + "((" + unboxedInitialType.getCanonicalText() + ")$val$)", expression);
+ }
+ }
+ }
+ }
+ return new TypeConversionDescriptor("$val$", "new " + typeText + "($val$)", expression);
+ }
+
+ @Nullable
+ private static TypeConversionDescriptor findDirectConversionForAtomicReferenceArray(PsiElement context, PsiType to, PsiType from) {
+ LOG.assertTrue(from instanceof PsiArrayType);
+ from = ((PsiArrayType)from).getComponentType();
+ final PsiElement parent = context.getParent();
+ final PsiElement parentParent = parent.getParent();
+
+ if (parent instanceof PsiAssignmentExpression) {
+ final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent;
+ final IElementType operationSign = assignmentExpression.getOperationTokenType();
+ final String sign = assignmentExpression.getOperationSign().getText();
+ if (context instanceof PsiArrayAccessExpression) {
+ if (parentParent instanceof PsiExpressionStatement) {
+ if (assignmentExpression.getLExpression() == context) {
+ if (operationSign == JavaTokenType.EQ) {
+ return new TypeConversionDescriptor("$qualifier$[$idx$] = $val$", "$qualifier$.set($idx$, $val$)", assignmentExpression);
+ }
+ else {
+ return new TypeConversionDescriptor("$qualifier$[$idx$]" + sign + "$val$",
+ "$qualifier$.set($idx$, " + getBoxedWrapper(from, to, "$qualifier$.get($idx$) " + sign.charAt(0) + " $val$") + ")",
+ assignmentExpression);
+ }
+ }
+ } //else should be a conflict
+ }
+ else {
+ final PsiExpression rExpression = assignmentExpression.getRExpression();
+ if (rExpression == context && operationSign == JavaTokenType.EQ) { //array = new T[l];
+ return wrapWithNewExpression(to, from, rExpression, context);
+ }
+ }
+ } else if (parent instanceof PsiVariable) {
+ if (((PsiVariable)parent).getInitializer() == context) {
+ return wrapWithNewExpression(to, from, (PsiExpression)context, context);
+ }
+ }
+
+ if (parentParent instanceof PsiExpressionStatement) {
+ if (parent instanceof PsiPostfixExpression) {
+ final String sign = ((PsiPostfixExpression)parent).getOperationSign().getText();
+ return new TypeConversionDescriptor("$qualifier$[$idx$]" + sign, "$qualifier$.getAndSet($idx$, " +
+ getBoxedWrapper(from, to,
+ "$qualifier$.get($idx$) " + sign.charAt(0) + " 1") +
+ ")", (PsiExpression)parent);
+ }
+ else if (parent instanceof PsiPrefixExpression) {
+ final String sign = ((PsiPrefixExpression)parent).getOperationSign().getText();
+ return new TypeConversionDescriptor(sign + "$qualifier$[$idx$]", "$qualifier$.set($idx$, " +
+ getBoxedWrapper(from, to,
+ "$qualifier$.get($idx$) " + sign.charAt(0) + " 1") +
+ ")", (PsiExpression)parent);
+ }
+ else if (parent instanceof PsiBinaryExpression) {
+ final String sign = ((PsiBinaryExpression)parent).getOperationSign().getText();
+ return new TypeConversionDescriptor("$qualifier$[$idx$]" + sign + "$val$", "$qualifier$.set($idx$, " +
+ getBoxedWrapper(from, to, "$qualifier$.get($idx$) " +
+ sign +
+ " $val$)") +
+ ")", (PsiExpression)parent);
+ }
+ }
+
+ if (context instanceof PsiArrayAccessExpression) {
+ return new TypeConversionDescriptor("$qualifier$[$idx$]", "$qualifier$.get($idx$)", (PsiExpression)context);
+ }
+ return null;
+ }
+
+ private static String getBoxedWrapper(final PsiType from, final PsiType to, @NotNull String arg) {
+ final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(to);
+ final PsiClass atomicClass = resolveResult.getElement();
+ LOG.assertTrue(atomicClass != null);
+ final PsiTypeParameter[] typeParameters = atomicClass.getTypeParameters();
+ if (typeParameters.length == 1) {
+ final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
+ LOG.assertTrue(substitutor.isValid());
+ final PsiType initial = substitutor.substitute(typeParameters[0]);
+ final PsiPrimitiveType unboxedInitialType = PsiPrimitiveType.getUnboxedType(initial);
+ if (unboxedInitialType != null) {
+ LOG.assertTrue(initial != null);
+ if (from instanceof PsiPrimitiveType) {
+ final PsiClassType boxedFromType = ((PsiPrimitiveType)from).getBoxedType(atomicClass);
+ LOG.assertTrue(boxedFromType != null);
+ return "new " + initial.getPresentableText() + "((" + unboxedInitialType.getCanonicalText() + ")(" + arg + "))";
+ }
+ }
+ }
+ return arg;
+ }
+
+ @Nullable
+ private static TypeConversionDescriptor findReverseConversion(PsiElement context) {
+ if (context instanceof PsiReferenceExpression) {
+ if (context.getParent() instanceof PsiMethodCallExpression) {
+ return findReverseConversionForMethodCall(context);
+ }
+ }
+ else if (context instanceof PsiNewExpression) {
+ return new TypeConversionDescriptor("new $type$($qualifier$)", "$qualifier$");
+ }
+ else if (context instanceof PsiMethodCallExpression) {
+ return findReverseConversionForMethodCall(((PsiMethodCallExpression)context).getMethodExpression());
+ }
+ return null;
+ }
+
+ @Nullable
+ private static TypeConversionDescriptor findReverseConversionForMethodCall(PsiElement context) {
+ final PsiElement resolved = ((PsiReferenceExpression)context).resolve();
+ if (resolved instanceof PsiMethod) {
+ final PsiMethod method = (PsiMethod)resolved;
+ final int parametersCount = method.getParameterList().getParametersCount();
+ final String resolvedName = method.getName();
+ if (Comparing.strEqual(resolvedName, "get")) {
+ return parametersCount == 0 ?
+ new TypeConversionDescriptor("$qualifier$.get()", "$qualifier$") :
+ new TypeConversionDescriptor("$qualifier$.get($idx$)", "$qualifier$[$idx$]");
+ }
+ else if (Comparing.strEqual(resolvedName, "set")) {
+ return parametersCount == 1 ?
+ new TypeConversionDescriptor("$qualifier$.set($val$)", "$qualifier$ = $val$") :
+ new TypeConversionDescriptor("$qualifier$.set($idx$, $val$)", "$qualifier$[$idx$] = $val$");
+ }
+ else if (Comparing.strEqual(resolvedName, "addAndGet")) {
+ return parametersCount == 1 ?
+ new TypeConversionDescriptor("$qualifier$.addAndGet($delta$)", "$qualifier$ + $delta$") :
+ new TypeConversionDescriptor("$qualifier$.addAndGet($idx$, $delta$)", "$qualifier$[$idx$] + $delta$");
+ }
+ else if (Comparing.strEqual(resolvedName, "incrementAndGet")) {
+ return parametersCount == 0 ?
+ new TypeConversionDescriptor("$qualifier$.incrementAndGet()", "++$qualifier$") :
+ new TypeConversionDescriptor("$qualifier$.incrementAndGet($idx$)", "++$qualifier$[$idx$]");
+ }
+ else if (Comparing.strEqual(resolvedName, "decrementAndGet")) {
+ return parametersCount == 0 ?
+ new TypeConversionDescriptor("$qualifier$.decrementAndGet()", "--$qualifier$") :
+ new TypeConversionDescriptor("$qualifier$.decrementAndGet($idx$)", "--$qualifier$[$idx$]");
+ }
+ else if (Comparing.strEqual(resolvedName, "getAndIncrement")) {
+ return parametersCount == 0 ?
+ new TypeConversionDescriptor("$qualifier$.getAndIncrement()", "$qualifier$++") :
+ new TypeConversionDescriptor("$qualifier$.getAndIncrement($idx$)", "$qualifier$[$idx$]++");
+ }
+ else if (Comparing.strEqual(resolvedName, "getAndDecrement")) {
+ return parametersCount == 0 ?
+ new TypeConversionDescriptor("$qualifier$.getAndDecrement()", "$qualifier$--") :
+ new TypeConversionDescriptor("$qualifier$.getAndDecrement($idx$)", "$qualifier$[$idx$]--");
+ }
+ else if (Comparing.strEqual(resolvedName, "getAndAdd")) {
+ return parametersCount == 1?
+ new TypeConversionDescriptor("$qualifier$.getAndAdd($val$)", "$qualifier$ += $val$") :
+ new TypeConversionDescriptor("$qualifier$.getAndAdd($idx$, $val$)", "$qualifier$[$idx$] += $val$");
+ }
+ else if (Comparing.strEqual(resolvedName, "getAndSet")) {
+ return parametersCount == 1 ?
+ new TypeConversionDescriptor("$qualifier$.getAndSet($val$)", "$qualifier$ = $val$") :
+ new TypeConversionDescriptor("$qualifier$.getAndSet($idx$, $val$)", "$qualifier$[$idx$] = $val$");
+ }
+ }
+ return null;
+ }
+
+}