Java: Don't offer "Invert If Condition" if the code structure is broken (IDEA-177291)

This commit is contained in:
Pavel Dolgov
2018-06-07 15:22:27 +03:00
parent 59f0240c26
commit cac4bf41ff
5 changed files with 64 additions and 9 deletions
@@ -10,6 +10,7 @@ import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.controlFlow.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtilRt;
@@ -17,6 +18,7 @@ import com.intellij.util.IncorrectOperationException;
import com.siyeh.ig.psiutils.BoolUtils;
import com.siyeh.ig.psiutils.CommentTracker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
@@ -41,17 +43,32 @@ public class InvertIfConditionAction extends PsiElementBaseIntentionAction {
.filter(prefixExpr -> PsiUtil.skipParenthesizedExprDown(prefixExpr.getOperand()) == null)
.first() != null) return false;
if (element instanceof PsiKeyword) {
PsiKeyword keyword = (PsiKeyword) element;
if ((keyword.getTokenType() == JavaTokenType.IF_KEYWORD || keyword.getTokenType() == JavaTokenType.ELSE_KEYWORD)
&& keyword.getParent() == ifStatement) {
return true;
if (element.getParent() != ifStatement) {
return false;
}
final IElementType tokenType = ((PsiKeyword)element).getTokenType();
if (tokenType != JavaTokenType.IF_KEYWORD && tokenType != JavaTokenType.ELSE_KEYWORD) {
return false;
}
}
else {
final TextRange condTextRange = condition.getTextRange();
if (condTextRange == null || !condTextRange.contains(offset)) {
return false;
}
}
final TextRange condTextRange = condition.getTextRange();
if (condTextRange == null) return false;
if (!condTextRange.contains(offset)) return false;
PsiElement block = findCodeBlock(ifStatement);
return block != null;
if (block == null) {
return false;
}
if (PsiUtil.skipParenthesizedExprDown(ifStatement.getCondition()) == null) {
return true;
}
// check that the code structure isn't broken completely
ControlFlow localFlow = buildControlFlow(block);
int startThenOffset = getThenOffset(localFlow, ifStatement);
int afterIfOffset = localFlow.getEndOffset(ifStatement);
return startThenOffset >= 0 && afterIfOffset >= 0;
}
@Override
@@ -150,7 +167,11 @@ public class InvertIfConditionAction extends PsiElementBaseIntentionAction {
return null;
}
private static ControlFlow buildControlFlow(PsiElement element) {
@NotNull
private static ControlFlow buildControlFlow(@Nullable PsiElement element) {
if (element == null) {
return ControlFlow.EMPTY;
}
try {
return ControlFlowFactory.getInstance(element.getProject()).getControlFlow(element, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false);
}
@@ -1623,6 +1623,7 @@ public class ControlFlowUtil {
* Push an arc of the graph (oldOffset -> newOffset)
*/
void push(int oldOffset, int newOffset) {
LOG.assertTrue(oldOffset >= 0, "negative offset is pushed to walk-through stack");
if (size >= newOffsets.length) {
oldOffsets = ArrayUtil.realloc(oldOffsets, size * 3 / 2);
newOffsets = ArrayUtil.realloc(newOffsets, size * 3 / 2);
@@ -0,0 +1,10 @@
// "Invert 'if' condition" "false"
class C {
boolean foo() {
{
if (tr<caret>ue) continue;
if (false) return false;
}
return true;
}
}
@@ -0,0 +1,10 @@
// "Invert 'if' condition" "false"
class C {
boolean foo() {
{
<caret>if (true) continue;
if (false) return false;
}
return true;
}
}
@@ -0,0 +1,13 @@
// "Invert 'if' condition" "false"
class P {
Object x;
static final String Y = "y";
public P foo(P a, P b) {
if (x <caret>instanceof String) Baz
a.bar(b, P.Y);
return a;
}
void bar(P p, String s) { }
}