diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java index 8f2f35a86fa8..bd89a643a121 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.typeMigration; +import com.intellij.codeInsight.generation.GetterSetterPrototypeProvider; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; @@ -22,10 +23,7 @@ import com.intellij.psi.*; import com.intellij.psi.impl.PsiSubstitutorImpl; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.psi.util.*; import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; @@ -83,7 +81,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { break; case TypeInfection.LEFT_INFECTED: - myLabeler.migrateExpressionType(rExpression, ltype, myStatement, TypeConversionUtil.isAssignable(ltype, rtype), true); + myLabeler.migrateExpressionType(rExpression, ltype, myStatement, TypeConversionUtil.isAssignable(ltype, rtype) && !isSetter(expression), true); break; case TypeInfection.RIGHT_INFECTED: @@ -178,7 +176,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { } @Override - public void visitReturnStatement(PsiReturnStatement statement) { // has to change method return type corresponding to new value type + public void visitReturnStatement(final PsiReturnStatement statement) { // has to change method return type corresponding to new value type super.visitReturnStatement(statement); final PsiElement method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, PsiLambdaExpression.class); @@ -191,9 +189,8 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { } final PsiType returnType = ((PsiMethod)method).getReturnType(); final PsiType valueType = myTypeEvaluator.evaluateType(value); - if (returnType != null && valueType != null) { - if (!myLabeler.addMigrationRoot(method, valueType, myStatement, TypeConversionUtil.isAssignable(returnType, valueType), true, true) + if (!myLabeler.addMigrationRoot(method, valueType, myStatement, TypeConversionUtil.isAssignable(returnType, valueType) && !isGetter(value, method), true, true) && TypeMigrationLabeler.typeContainsTypeParameters(returnType)) { value.accept(this); } @@ -594,4 +591,41 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { return (left.isChanged() ? 1 : 0) + (right.isChanged() ? 2 : 0); } } + + private static boolean isSetter(PsiAssignmentExpression expression) { + final PsiExpression lExpression = expression.getLExpression(); + if (lExpression instanceof PsiReferenceExpression) { + final PsiElement resolved = ((PsiReferenceExpression)lExpression).resolve(); + if (resolved instanceof PsiField) { + PsiField field = (PsiField) resolved; + final NavigatablePsiElement containingMethod = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, PsiLambdaExpression.class); + if (containingMethod instanceof PsiMethod) { + final PsiMethod setter = PropertyUtil.findPropertySetter(field.getContainingClass(), field.getName(), field.hasModifierProperty(PsiModifier.STATIC), false); + if (containingMethod.isEquivalentTo(setter)) { + return true; + } + } + } + } + return false; + } + + private static boolean isGetter(PsiExpression returnValue, PsiElement containingMethod) { + if (returnValue instanceof PsiReferenceExpression) { + final PsiElement resolved = ((PsiReferenceExpression)returnValue).resolve(); + if (resolved instanceof PsiField) { + PsiField field = (PsiField)resolved; + final boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); + final PsiMethod[] getters = GetterSetterPrototypeProvider.findGetters(field.getContainingClass(), field.getName(), isStatic); + if (getters != null) { + for (PsiMethod getter : getters) { + if (containingMethod.isEquivalentTo(getter)) { + return true; + } + } + } + } + } + return false; + } } diff --git a/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java b/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java index 0cd0d3a2b70a..7e834323a992 100644 --- a/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java +++ b/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java @@ -906,6 +906,14 @@ public class TypeMigrationTest extends TypeMigrationTestBase { doTestFirstParamType("meth", myFactory.createTypeFromText("java.lang.String", null), myFactory.createTypeFromText("java.lang.Long", null)); } + public void testAssignableGetter() { + doTestFieldType("foo", "Test", PsiType.LONG, PsiType.INT); + } + + public void testAssignableSetter() { + doTestFieldType("foo", "Test", PsiType.INT, PsiType.LONG); + } + private void doTestForeachParameter(final PsiType rootType, final PsiType migrationType) { start(new RulesProvider() { @Override diff --git a/java/typeMigration/testData/refactoring/typeMigration/assignableGetter/after/Test.items b/java/typeMigration/testData/refactoring/typeMigration/assignableGetter/after/Test.items new file mode 100644 index 000000000000..f44e69adc365 --- /dev/null +++ b/java/typeMigration/testData/refactoring/typeMigration/assignableGetter/after/Test.items @@ -0,0 +1,15 @@ +Types: +PsiField:foo : int +PsiLocalVariable:someNumber1 : int +PsiMethod:getFoo : int +PsiMethodCallExpression:someClass.getFoo() : int +PsiParameter:foo : int +PsiReferenceExpression:foo : int +PsiReferenceExpression:foo : int +PsiReferenceExpression:someNumber1 : int +PsiReferenceExpression:this.foo : int + +Conversions: + +New expression type changes: +Fails: diff --git a/java/typeMigration/testData/refactoring/typeMigration/assignableGetter/after/test.java b/java/typeMigration/testData/refactoring/typeMigration/assignableGetter/after/test.java new file mode 100644 index 000000000000..e43fa243bdc7 --- /dev/null +++ b/java/typeMigration/testData/refactoring/typeMigration/assignableGetter/after/test.java @@ -0,0 +1,20 @@ +public class Test { + + private int foo; + + public int getFoo() { + return foo; + } + + public void setFoo(int foo) { + this.foo = foo; + } + + static void m(Test someClass) { + long someNumber = someClass.getFoo(); + System.out.println(someNumber + 10); + + int someNumber1 = 1123; + someClass.setFoo(someNumber1); + } +} \ No newline at end of file diff --git a/java/typeMigration/testData/refactoring/typeMigration/assignableGetter/before/test.java b/java/typeMigration/testData/refactoring/typeMigration/assignableGetter/before/test.java new file mode 100644 index 000000000000..a0b1fdbf08b1 --- /dev/null +++ b/java/typeMigration/testData/refactoring/typeMigration/assignableGetter/before/test.java @@ -0,0 +1,20 @@ +public class Test { + + private long foo; + + public long getFoo() { + return foo; + } + + public void setFoo(long foo) { + this.foo = foo; + } + + static void m(Test someClass) { + long someNumber = someClass.getFoo(); + System.out.println(someNumber + 10); + + long someNumber1 = 1123; + someClass.setFoo(someNumber1); + } +} \ No newline at end of file diff --git a/java/typeMigration/testData/refactoring/typeMigration/assignableSetter/after/Test.items b/java/typeMigration/testData/refactoring/typeMigration/assignableSetter/after/Test.items new file mode 100644 index 000000000000..c0dea7db9d5b --- /dev/null +++ b/java/typeMigration/testData/refactoring/typeMigration/assignableSetter/after/Test.items @@ -0,0 +1,17 @@ +Types: +PsiField:foo : long +PsiLocalVariable:someNumber : long +PsiMethod:getFoo : long +PsiMethodCallExpression:someClass.getFoo() : long +PsiParameter:foo : long +PsiReferenceExpression:foo : long +PsiReferenceExpression:foo : long +PsiReferenceExpression:someNumber : long +PsiReferenceExpression:this.foo : long + +Conversions: +someNumber + 10 -> $ +someNumber1 -> $ + +New expression type changes: +Fails: diff --git a/java/typeMigration/testData/refactoring/typeMigration/assignableSetter/after/test.java b/java/typeMigration/testData/refactoring/typeMigration/assignableSetter/after/test.java new file mode 100644 index 000000000000..5f3ff12db81a --- /dev/null +++ b/java/typeMigration/testData/refactoring/typeMigration/assignableSetter/after/test.java @@ -0,0 +1,20 @@ +public class Test { + + private long foo; + + public long getFoo() { + return foo; + } + + public void setFoo(long foo) { + this.foo = foo; + } + + static void m(Test someClass) { + long someNumber = someClass.getFoo(); + System.out.println(someNumber + 10); + + int someNumber1 = 1123; + someClass.setFoo(someNumber1); + } +} \ No newline at end of file diff --git a/java/typeMigration/testData/refactoring/typeMigration/assignableSetter/before/test.java b/java/typeMigration/testData/refactoring/typeMigration/assignableSetter/before/test.java new file mode 100644 index 000000000000..7350a2b81c86 --- /dev/null +++ b/java/typeMigration/testData/refactoring/typeMigration/assignableSetter/before/test.java @@ -0,0 +1,20 @@ +public class Test { + + private int foo; + + public int getFoo() { + return foo; + } + + public void setFoo(int foo) { + this.foo = foo; + } + + static void m(Test someClass) { + int someNumber = someClass.getFoo(); + System.out.println(someNumber + 10); + + int someNumber1 = 1123; + someClass.setFoo(someNumber1); + } +} \ No newline at end of file diff --git a/java/typeMigration/testData/refactoring/typeMigration/t135/after/Test.items b/java/typeMigration/testData/refactoring/typeMigration/t135/after/Test.items index a08bb312435a..a6ee8ea72d8b 100644 --- a/java/typeMigration/testData/refactoring/typeMigration/t135/after/Test.items +++ b/java/typeMigration/testData/refactoring/typeMigration/t135/after/Test.items @@ -1,5 +1,6 @@ Types: PsiField:foo : int +PsiMethod:getFoo : int PsiParameter:foo : int PsiReferenceExpression:foo : int PsiReferenceExpression:foo : int diff --git a/java/typeMigration/testData/refactoring/typeMigration/t135/after/test.java b/java/typeMigration/testData/refactoring/typeMigration/t135/after/test.java index dbd11376c10b..13272a661a05 100644 --- a/java/typeMigration/testData/refactoring/typeMigration/t135/after/test.java +++ b/java/typeMigration/testData/refactoring/typeMigration/t135/after/test.java @@ -2,7 +2,7 @@ class Test { private int foo; private long bar; - public long getFoo() { + public int getFoo() { return foo; }