look for conflicts when replacing 'for' with its initialization (IDEA-CR-20896)

This commit is contained in:
peter
2017-05-11 17:43:42 +02:00
parent 78dfecb7b2
commit 88bdc032be
3 changed files with 60 additions and 30 deletions
@@ -31,6 +31,7 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.DeclarationSearchUtils;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import com.siyeh.ig.psiutils.SideEffectChecker;
@@ -174,32 +175,57 @@ public class SimplifyBooleanExpressionFix extends LocalQuickFixOnPsiElement {
removeFollowingStatements(orig, (PsiCodeBlock)parent);
}
if (statement instanceof PsiBlockStatement && parent instanceof PsiCodeBlock &&
!DeclarationSearchUtils.containsConflictingDeclarations(((PsiBlockStatement)statement).getCodeBlock(), (PsiCodeBlock)parent)) {
// See IDEADEV-24277
// Code block can only be inlined into another (parent) code block.
// Code blocks, which are if or loop statement branches should not be inlined.
PsiCodeBlock codeBlock = ((PsiBlockStatement)statement).getCodeBlock();
PsiJavaToken lBrace = codeBlock.getLBrace();
PsiJavaToken rBrace = codeBlock.getRBrace();
if (lBrace == null || rBrace == null) return;
final PsiElement[] children = codeBlock.getChildren();
if (children.length > 2) {
final PsiElement added =
parent.addRangeBefore(
children[1],
children[children.length - 2],
orig);
final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(orig.getManager());
codeStyleManager.reformat(added);
if (parent instanceof PsiCodeBlock) {
if (statement instanceof PsiBlockStatement &&
!DeclarationSearchUtils.containsConflictingDeclarations(((PsiBlockStatement)statement).getCodeBlock(), (PsiCodeBlock)parent)) {
inlineBlockStatements(orig, (PsiBlockStatement)statement, parent);
return;
}
if (hasConflictingDeclarations(statement, (PsiCodeBlock)parent)) {
orig.replace(wrapWithCodeBlock(statement));
return;
}
orig.delete();
}
else {
orig.replace(statement);
orig.replace(statement);
}
private static boolean hasConflictingDeclarations(@Nullable PsiStatement statement, PsiCodeBlock parent) {
return statement instanceof PsiDeclarationStatement &&
ContainerUtil.exists(((PsiDeclarationStatement)statement).getDeclaredElements(), e -> isConflictingLocalVariable(parent, e));
}
private static boolean isConflictingLocalVariable(PsiCodeBlock parent, PsiElement declaration) {
if (!(declaration instanceof PsiLocalVariable)) return false;
String name = ((PsiLocalVariable)declaration).getName();
return name != null && PsiResolveHelper.SERVICE.getInstance(declaration.getProject()).resolveAccessibleReferencedVariable(name, parent) != null;
}
private static PsiCodeBlock wrapWithCodeBlock(PsiStatement replacement) {
PsiCodeBlock newBlock = JavaPsiFacade.getElementFactory(replacement.getProject()).createCodeBlock();
newBlock.add(replacement);
return newBlock;
}
private static void inlineBlockStatements(@NotNull PsiStatement orig, @NotNull PsiBlockStatement statement, PsiElement parent) {
// See IDEADEV-24277
// Code block can only be inlined into another (parent) code block.
// Code blocks, which are if or loop statement branches should not be inlined.
PsiCodeBlock codeBlock = statement.getCodeBlock();
PsiJavaToken lBrace = codeBlock.getLBrace();
PsiJavaToken rBrace = codeBlock.getRBrace();
if (lBrace == null || rBrace == null) return;
final PsiElement[] children = codeBlock.getChildren();
if (children.length > 2) {
final PsiElement added =
parent.addRangeBefore(
children[1],
children[children.length - 2],
orig);
final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(orig.getManager());
codeStyleManager.reformat(added);
}
orig.delete();
}
private static boolean blockAlwaysReturns(@NotNull PsiStatement statement) {
@@ -1,8 +1,9 @@
class Test {
public static void test() {
for(int i = <error descr="Cannot resolve method 'launchMissiles()'">launchMissiles</error>(); (<warning descr="Condition is always false">fa<caret>lse</warning>);) {
System.out.println("Hello");
public static void test() {
for(int i = <error descr="Cannot resolve method 'launchMissiles()'">launchMissiles</error>(); (<warning descr="Condition is always false">fa<caret>lse</warning>);) {
System.out.println("Hello");
}
int i = 1;
}
}
}
@@ -1,6 +1,9 @@
class Test {
public static void test() {
int i = launchMissiles();
}
public static void test() {
{
int i = launchMissiles();
}
int i = 1;
}
}