summaryrefslogtreecommitdiff
path: root/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/ThreadLocalConversionRule.java
diff options
context:
space:
mode:
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.java231
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