MoveIntoIfBranchesAction: conflict detection improved

GitOrigin-RevId: bf8c3d050e5cfa51e71d6e34921ab2c2036b8e5e
This commit is contained in:
Tagir Valeev
2020-06-15 13:51:35 +07:00
committed by intellij-monorepo-bot
parent f46f7b77b9
commit 8a7d1000b1
4 changed files with 47 additions and 7 deletions

View File

@@ -15,6 +15,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.ControlFlowUtils;
import com.siyeh.ig.psiutils.VariableAccessUtils;
import one.util.streamex.MoreCollectors;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
@@ -61,18 +62,17 @@ public class MoveIntoIfBranchesAction implements IntentionAction {
afterLast.add(e);
}
}
if (afterLast.isEmpty()) return false;
Set<PsiNamedElement> declared = StreamEx.of(statements).select(PsiDeclarationStatement.class)
.flatArray(PsiDeclarationStatement::getDeclaredElements).select(PsiNamedElement.class).toSet();
List<String> declaredInIf = StreamEx.of(ifStatement.getThenBranch(), ifStatement.getElseBranch()).flatArray(ControlFlowUtils::unwrapBlock)
.select(PsiDeclarationStatement.class).flatArray(PsiDeclarationStatement::getDeclaredElements)
.select(PsiNamedElement.class).map(PsiNamedElement::getName).nonNull().toList();
if (afterLast.isEmpty() && declaredInIf.isEmpty()) return false;
Set<PsiVariable> declared = StreamEx.of(statements).flatCollection(VariableAccessUtils::findDeclaredVariables).toSet();
if (declared.isEmpty()) return false;
if (SyntaxTraverser.psiTraverser().withRoots(afterLast).filter(PsiJavaCodeReferenceElement.class)
.filter(ref -> declared.contains(ref.resolve())).first() != null) {
return true;
}
return StreamEx.of(ifStatement.getThenBranch(), ifStatement.getElseBranch()).flatArray(ControlFlowUtils::unwrapBlock)
.select(PsiDeclarationStatement.class).flatArray(PsiDeclarationStatement::getDeclaredElements)
.select(PsiNamedElement.class).map(PsiNamedElement::getName).nonNull()
.anyMatch(name -> ContainerUtil.exists(declared, d -> name.equals(d.getName())));
return ContainerUtil.exists(declaredInIf, name -> ContainerUtil.exists(declared, d -> name.equals(d.getName())));
}
@Override

View File

@@ -0,0 +1,10 @@
// "Move up into 'if' statement branches" "false"
class X {
void test(int x) {
if (x > 0) System.out.println(">0"); else {
int y = 3;
}
<selection>{int y = x * 2;
System.out.println(y);}</selection>
}
}

View File

@@ -0,0 +1,9 @@
// "Move up into 'if' statement branches" "false"
class X {
void test(int x, Object obj) {
if (x > 0) System.out.println(">0"); else {
int y = 3;
}
<selection>if (obj instanceof String y) {}</selection>
}
}

View File

@@ -489,6 +489,27 @@ public class VariableAccessUtils {
return !TypeConversionUtil.boxingConversionApplicable(variableType, initializationType);
}
/**
* @param statement statement to scan
* @return list of variables declared inside given element that could conflict with other declarations on statement level.
* I.e. all local and pattern declarations declared inside, except declarations from the local/anonymous classes.
*/
public static List<PsiVariable> findDeclaredVariables(@NotNull PsiStatement statement) {
List<PsiVariable> variables = new ArrayList<>();
statement.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitClass(final PsiClass aClass) {}
@Override
public void visitVariable(PsiVariable variable) {
variables.add(variable);
super.visitVariable(variable);
}
});
return variables;
}
private static boolean isFinalChain(PsiReferenceExpression reference) {
while (true) {
PsiElement element = reference.resolve();