Java: handle reassigned parameters better (IDEA-256096)

for "Convert to instance method" refactoring

GitOrigin-RevId: 957b0b0cecf93f6ff849d4105ed864bc6ba99c8f
This commit is contained in:
Bas Leijdekkers
2024-07-10 19:17:56 +00:00
committed by intellij-monorepo-bot
parent 610358505b
commit 90930f2998
5 changed files with 56 additions and 4 deletions
@@ -20,7 +20,6 @@ import com.intellij.refactoring.actions.BaseRefactoringAction;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.MethodUtils;
import com.siyeh.ig.psiutils.VariableAccessUtils;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -75,7 +74,6 @@ public class ConvertToInstanceMethodHandler implements RefactoringActionHandler,
boolean classTypesFound = false;
boolean resolvableClassesFound = false;
for (final PsiParameter parameter : parameters) {
if (VariableAccessUtils.variableIsAssigned(parameter, parameter.getDeclarationScope())) continue;
final PsiType type = parameter.getType();
if (type instanceof PsiClassType classType) {
classTypesFound = true;
@@ -27,6 +27,7 @@ import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.MultiMap;
import com.siyeh.ig.psiutils.VariableAccessUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,6 +39,7 @@ public final class ConvertToInstanceMethodProcessor extends BaseRefactoringProce
private static final Logger LOG = Logger.getInstance(ConvertToInstanceMethodProcessor.class);
private PsiMethod myMethod;
private @Nullable PsiParameter myTargetParameter;
private final boolean myParameterIsReassigned;
private PsiClass myTargetClass;
private Map<PsiTypeParameter, PsiTypeParameter> myTypeParameterReplacements;
private static final Key<PsiTypeParameter> BIND_TO_TYPE_PARAMETER = Key.create("REPLACEMENT");
@@ -52,6 +54,8 @@ public final class ConvertToInstanceMethodProcessor extends BaseRefactoringProce
super(project);
myMethod = method;
myTargetParameter = targetParameter;
myParameterIsReassigned = targetParameter != null &&
VariableAccessUtils.variableIsAssigned(myTargetParameter, myTargetParameter.getDeclarationScope());
LOG.assertTrue(method.hasModifierProperty(PsiModifier.STATIC));
if (myTargetParameter != null) {
LOG.assertTrue(myTargetParameter.getDeclarationScope() == myMethod);
@@ -215,7 +219,7 @@ public final class ConvertToInstanceMethodProcessor extends BaseRefactoringProce
if (usage instanceof MethodCallUsageInfo) {
processMethodCall(((MethodCallUsageInfo)usage).getMethodCall());
}
else if (usage instanceof ParameterUsageInfo) {
else if (usage instanceof ParameterUsageInfo && !myParameterIsReassigned) {
processParameterUsage((ParameterUsageInfo)usage);
}
else if (usage instanceof ImplementingClassUsageInfo) {
@@ -227,7 +231,20 @@ public final class ConvertToInstanceMethodProcessor extends BaseRefactoringProce
}
prepareTypeParameterReplacement();
if (myTargetParameter != null) myTargetParameter.delete();
if (myTargetParameter != null) {
if (myParameterIsReassigned) {
PsiDeclarationStatement statement =
JavaPsiFacade.getElementFactory(myProject).createVariableDeclarationStatement(myTargetParameter.getName(),
myTargetParameter.getType(),
createThisExpression());
PsiCodeBlock body = myMethod.getBody();
assert body != null;
PsiElement first = body.getFirstBodyElement();
assert first != null;
first.getParent().addBefore(statement, first);
}
myTargetParameter.delete();
}
ChangeContextUtil.encodeContextInfo(myMethod, true);
PsiMethod result;
if (!myTargetClass.isInterface()) {
@@ -0,0 +1,17 @@
class X {
static Node <caret>skipForward2(Node node, Predicate<Node> skipWhile) {
while (skipWhile.test(node)) {
Node next = node.nextNode();
if (next == null) break;
node = next;
}
return node;
}
class Node {
Node nextNode() {
return null;
}
}
}
@@ -0,0 +1,19 @@
class X {
class Node {
Node skipForward2(Predicate<Node> skipWhile) {
Node node = this;
while (skipWhile.test(node)) {
Node next = node.nextNode();
if (next == null) break;
node = next;
}
return node;
}
Node nextNode() {
return null;
}
}
}
@@ -19,6 +19,7 @@ public class ConvertToInstance8MethodTest extends ConvertToInstanceMethodTest {
public void testThisInsteadOfNoQualifier() { doTest(0); }
public void testMethodReferenceAcceptableBySecondSearch() { doTest(0); }
public void testConvertToInstanceMethodOfTheSameClass() { doTest(0); }
public void testReassignedParameter() { doTest(0); }
public void testStaticMethodOfInterfaceWithNonAccessibleInheritor() { doTest(0, null, "I i", "this / new I()"); }
public void testEnum() { doTest(0, null, "E e"); }
public void testAnonymousClass() { doTest(0, null, "X x"); }