[java-intentions] Disable 'convert to if' when if-condition refers to the variable

Also: fix for var types
Fixes IDEA-374029 "Make effectively final" generates uncompilable code

GitOrigin-RevId: 17932aefe036dec167aabaf2066c4cdff11947da
This commit is contained in:
Tagir Valeev
2025-06-17 13:31:39 +00:00
committed by intellij-monorepo-bot
parent 09e6d7f595
commit 0d5ea1d59e
5 changed files with 81 additions and 1 deletions
@@ -6,6 +6,7 @@ import com.intellij.java.JavaBundle;
import com.intellij.psi.*;
import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.ExpressionUtils;
@@ -24,11 +25,16 @@ import java.util.Objects;
final class MoveInitializerToIfBranchFixer implements EffectivelyFinalFixer {
@Override
public boolean isAvailable(@NotNull PsiLocalVariable var) {
if (var.getTypeElement().isInferredType() &&
!PsiTypesUtil.isDenotableType(var.getType(), var)) {
return false;
}
PsiExpression initializer = var.getInitializer();
Branched branched = extractInitMode(var);
// Do not add too many branches
return branched != null && branched.numberOfNonInitializedBranches() <= 3 &&
canReorder(initializer, branched);
canReorder(initializer, branched) &&
branched.conditions().noneMatch(cond -> VariableAccessUtils.variableIsUsed(var, cond));
}
@Override
@@ -38,6 +44,10 @@ final class MoveInitializerToIfBranchFixer implements EffectivelyFinalFixer {
PsiStatement statement = JavaPsiFacade.getElementFactory(var.getProject())
.createStatementFromText(var.getName() + "=" + initializer.getText() + ";", null);
branched.addInitializer(statement);
PsiTypeElement typeElement = var.getTypeElement();
if (typeElement.isInferredType()) {
PsiTypesUtil.replaceWithExplicitType(typeElement);
}
initializer.delete();
}
@@ -0,0 +1,12 @@
// "Make 'x' effectively final by moving initializer to the 'if' statement" "true-preview"
class Abc {
void test() {
int x;
if (Math.random() > 0.5) {
x = 10;
} else {
x = 5;
}
Runnable r = () -> System.out.println(x);
}
}
@@ -0,0 +1,31 @@
// "Make 'companies' effectively final by moving initializer to the 'if' statement" "false"
import java.util.List;
class Abc {
private void method(X x, List<Integer> list) {
var companies = x.getCompanies();
if (companies.isEmpty()) {
companies = List.of(x.getCompanyId());
}
list.forEach(w -> something(comp<caret>anies));
}
private void something(List<Integer> companies) {
}
static public class X {
private int companyId;
private List<Integer> companies;
public int getCompanyId() {
return companyId;
}
public List<Integer> getCompanies() {
return companies;
}
}
}
@@ -0,0 +1,10 @@
// "Make 'x' effectively final by moving initializer to the 'if' statement" "true-preview"
class Abc {
void test() {
var x = 5;
if (Math.random() > 0.5) {
x = 10;
}
Runnable r = () -> System.out.println(<caret>x);
}
}
@@ -0,0 +1,17 @@
// "Make 'x' effectively final by moving initializer to the 'if' statement" "false"
class Abc {
interface A{}
interface B{
void m();
}
void test(Object obj) {
var x = (A & B) obj;
if (Math.random() > 0.5) {
x = null;
}
Runnable r = () -> {
if (<caret>x != null) x.m();
};
}
}