diff options
Diffstat (limited to 'java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/ThreadLocalConversionRule.java')
-rw-r--r-- | java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/ThreadLocalConversionRule.java | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/ThreadLocalConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/ThreadLocalConversionRule.java new file mode 100644 index 000000000000..2fb305147d02 --- /dev/null +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/ThreadLocalConversionRule.java @@ -0,0 +1,231 @@ +/* + * 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; + +public class ThreadLocalConversionRule extends TypeConversionRule { + private static final Logger LOG = Logger.getInstance("#" + ThreadLocalConversionRule.class.getName()); + + + @Override + public TypeConversionDescriptorBase findConversion(PsiType from, + PsiType to, + PsiMember member, + PsiExpression context, + TypeMigrationLabeler labeler) { + if (to instanceof PsiClassType && isThreadLocalTypeMigration(from, (PsiClassType)to, context)) { + return findDirectConversion(context, to, from, labeler); + } + return null; + } + + private static boolean isThreadLocalTypeMigration(PsiType from, PsiClassType to, PsiExpression context) { + final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(to); + final PsiClass threadLocalClass = resolveResult.getElement(); + + if (threadLocalClass != null) { + final String typeQualifiedName = threadLocalClass.getQualifiedName(); + if (!Comparing.strEqual(typeQualifiedName, ThreadLocal.class.getName())) { + return false; + } + final PsiTypeParameter[] typeParameters = threadLocalClass.getTypeParameters(); + if (typeParameters.length != 1) return !PsiUtil.isLanguageLevel5OrHigher(context); + final PsiType toTypeParameterValue = resolveResult.getSubstitutor().substitute(typeParameters[0]); + if (toTypeParameterValue != null) { + if (from instanceof PsiPrimitiveType) { + final PsiPrimitiveType unboxedInitialType = PsiPrimitiveType.getUnboxedType(toTypeParameterValue); + if (unboxedInitialType != null) { + return TypeConversionUtil.areTypesConvertible(from, unboxedInitialType); + } + } + else { + return TypeConversionUtil.isAssignable(from, PsiUtil.captureToplevelWildcards(toTypeParameterValue, context)); + } + } + return !PsiUtil.isLanguageLevel5OrHigher(context); + } + return false; + } + + @Nullable + public static TypeConversionDescriptor findDirectConversion(PsiElement context, PsiType to, PsiType from, TypeMigrationLabeler labeler) { + final PsiClass toTypeClass = PsiUtil.resolveClassInType(to); + LOG.assertTrue(toTypeClass != null); + + if (context instanceof PsiArrayAccessExpression) { + return new TypeConversionDescriptor("$qualifier$[$val$]", "$qualifier$.get()[$val$]"); + } + 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(" + toBoxed("$val$", from, context)+")", (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$", toPrimitive("$qualifier$.get()", from, context), expression); + } + else if (context instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)context; + final String sign = binaryExpression.getOperationSign().getText(); + return new TypeConversionDescriptor("$qualifier$" + sign + "$val$", toPrimitive("$qualifier$.get()", from, context) + " " + sign + " $val$"); + } + + if (parent instanceof PsiExpressionStatement) { + if (context instanceof PsiPostfixExpression) { + final PsiPostfixExpression postfixExpression = (PsiPostfixExpression)context; + final String sign = postfixExpression.getOperationSign().getText(); + + return new TypeConversionDescriptor("$qualifier$" + sign, "$qualifier$.set(" + + getBoxedWrapper(from, to, toPrimitive("$qualifier$.get()", from, context) + " " + sign.charAt(0) + " 1", + labeler, context, postfixExpression.getOperand().getText() + + sign.charAt(0) + + " 1") + + ")"); + } + else if (context instanceof PsiPrefixExpression) { + final PsiPrefixExpression prefixExpression = (PsiPrefixExpression)context; + final PsiJavaToken operationSign = ((PsiPrefixExpression)context).getOperationSign(); + if (operationSign.getTokenType() == JavaTokenType.EXCL) { + return new TypeConversionDescriptor("!$qualifier$", "!$qualifier$.get()"); + } + final String sign = operationSign.getText(); + final PsiExpression operand = prefixExpression.getOperand(); + return new TypeConversionDescriptor(sign + "$qualifier$", "$qualifier$.set(" + + getBoxedWrapper(from, to, toPrimitive("$qualifier$.get()", from, context) + " " + sign.charAt(0) + " 1", + labeler, context, operand != null ? operand.getText() + + sign.charAt(0) + + " 1" : null) + + ")"); + } + else if (context instanceof PsiAssignmentExpression) { + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)context; + final PsiJavaToken signToken = assignmentExpression.getOperationSign(); + final IElementType operationSign = signToken.getTokenType(); + final String sign = signToken.getText(); + final PsiExpression lExpression = assignmentExpression.getLExpression(); + if (operationSign == JavaTokenType.EQ) { + 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()); + } + } + return new TypeConversionDescriptor("$qualifier$ = $val$", "$qualifier$.set(" + + toBoxed("$val$", from, context) + + ")"); + } + else { + final PsiExpression rExpression = assignmentExpression.getRExpression(); + return new TypeConversionDescriptor("$qualifier$" + sign + "$val$", "$qualifier$.set(" + + getBoxedWrapper(from, to, toPrimitive("$qualifier$.get()", from, context) + + " " + sign.charAt(0) + + " $val$", labeler, context, + rExpression != null + ? lExpression + .getText() + + sign.charAt(0) + + rExpression.getText() + : null) + + ")"); + } + } + } + return null; + } + + public static TypeConversionDescriptor wrapWithNewExpression(PsiType to, PsiType from, PsiExpression initializer) { + final String boxedTypeName = from instanceof PsiPrimitiveType ? ((PsiPrimitiveType)from).getBoxedTypeName() : from.getCanonicalText(); + return new TypeConversionDescriptor("$qualifier$", "new " + + to.getCanonicalText() + + "() {\n" + + "@Override \n" + + "protected " + + boxedTypeName + + " initialValue() {\n" + + " return " + + (PsiUtil.isLanguageLevel5OrHigher(initializer) + ? initializer.getText() + : (from instanceof PsiPrimitiveType ? "new " + + ((PsiPrimitiveType)from).getBoxedTypeName() + + "(" + + initializer.getText() + + ")" : initializer.getText())) + + ";\n" + + "}\n" + + "}", initializer); + } + + private static String toPrimitive(String replaceByArg, PsiType from, PsiElement context) { + return PsiUtil.isLanguageLevel5OrHigher(context) + ? replaceByArg + : from instanceof PsiPrimitiveType ? "((" + + ((PsiPrimitiveType)from).getBoxedTypeName() + + ")" + + replaceByArg + + ")." + + from.getCanonicalText() + + "Value()" : "((" + from.getCanonicalText() + ")" + replaceByArg + ")"; + } + + private static String toBoxed(String replaceByArg, PsiType from, PsiElement context) { + return PsiUtil.isLanguageLevel5OrHigher(context) + ? replaceByArg + : from instanceof PsiPrimitiveType ? "new " + ((PsiPrimitiveType)from).getBoxedTypeName() + + "(" + + replaceByArg + + ")" + : replaceByArg; + } + + private static String getBoxedWrapper(final PsiType from, + final PsiType to, + @NotNull String arg, + TypeMigrationLabeler labeler, + PsiElement context, + @Nullable String tryType) { + if (from instanceof PsiPrimitiveType) { + final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(to); + final PsiClass threadLocalClass = resolveResult.getElement(); + LOG.assertTrue(threadLocalClass != null); + final PsiTypeParameter[] typeParameters = threadLocalClass.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 (tryType != null) { + final PsiType exprType = labeler.getTypeEvaluator().evaluateType( + JavaPsiFacade.getElementFactory(threadLocalClass.getProject()).createExpressionFromText(tryType, context)); + if (exprType != null && unboxedInitialType.isAssignableFrom(exprType)) { + return toBoxed(arg, from, context); + } + } + return "new " + initial.getCanonicalText() + "((" + unboxedInitialType.getCanonicalText() + ")(" + arg + "))"; + } + } + } + return toBoxed(arg, from, context); + } + + +}
\ No newline at end of file |