IDEA-70913 smart step into should not propose methods from both branches in conditional expressions

This commit is contained in:
Egor.Ushakov
2016-08-30 19:02:07 +03:00
parent 81ca03ffd8
commit 42764d22ff
3 changed files with 59 additions and 22 deletions
@@ -16,8 +16,13 @@
package com.intellij.debugger.actions;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.jdi.MethodBytecodeUtil;
@@ -36,6 +41,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.util.DocumentUtil;
import com.intellij.util.Range;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.OrderedSet;
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
import com.sun.jdi.Location;
@@ -68,7 +74,7 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
@Override
public void threadAction(@NotNull SuspendContextImpl suspendContext) {
List<SmartStepTarget> targets = ApplicationManager.getApplication().runReadAction(
(Computable<List<SmartStepTarget>>)() -> findSmartStepTargets(position, suspendContext));
(Computable<List<SmartStepTarget>>)() -> findSmartStepTargets(position, suspendContext, getDebuggerContext()));
DebuggerUIUtil.invokeLater(() -> {
if (targets.isEmpty()) {
doStepInto(session, Registry.is("debugger.single.smart.step.force"), null);
@@ -93,7 +99,9 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
throw new IllegalStateException("Should not be used");
}
protected List<SmartStepTarget> findSmartStepTargets(final SourcePosition position, @Nullable SuspendContextImpl suspendContext) {
protected List<SmartStepTarget> findSmartStepTargets(final SourcePosition position,
@Nullable SuspendContextImpl suspendContext,
@NotNull DebuggerContextImpl debuggerContext) {
final int line = position.getLine();
if (line < 0) {
return Collections.emptyList(); // the document has been changed
@@ -174,38 +182,64 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
@Override
public void visitField(PsiField field) {
TextRange range = field.getTextRange();
if (lineRange.intersects(range)) {
//textRange.set(textRange.get().union(range));
if (checkTextRange(field, false)) {
super.visitField(field);
}
}
@Override
public void visitMethod(PsiMethod method) {
TextRange range = method.getTextRange();
if (lineRange.intersects(range)) {
//textRange.set(textRange.get().union(range));
if (checkTextRange(method, false)) {
super.visitMethod(method);
}
}
@Override
public void visitStatement(PsiStatement statement) {
TextRange range = statement.getTextRange();
if (lineRange.intersects(range)) {
textRange.set(textRange.get().union(range));
if (checkTextRange(statement, true)) {
super.visitStatement(statement);
}
}
@Override
public void visitConditionalExpression(PsiConditionalExpression expression) {
PsiExpression condition = expression.getCondition();
condition.accept(this);
ThreeState conditionRes = ThreeState.UNSURE;
if (!DebuggerUtils.hasSideEffects(condition)) {
try {
ExpressionEvaluator evaluator = EvaluatorBuilderImpl.getInstance().build(condition, position);
conditionRes = ThreeState.fromBoolean(DebuggerUtilsEx.evaluateBoolean(evaluator, debuggerContext.createEvaluationContext()));
}
catch (EvaluateException e) {
LOG.info(e);
}
}
PsiExpression thenExpression = expression.getThenExpression();
if (conditionRes != ThreeState.NO && thenExpression != null) {
thenExpression.accept(this);
}
PsiExpression elseExpression = expression.getElseExpression();
if (conditionRes != ThreeState.YES && elseExpression != null) {
elseExpression.accept(this);
}
}
@Override
public void visitExpression(PsiExpression expression) {
checkTextRange(expression, true);
super.visitExpression(expression);
}
boolean checkTextRange(PsiElement expression, boolean expand) {
TextRange range = expression.getTextRange();
if (lineRange.intersects(range)) {
textRange.set(textRange.get().union(range));
if (expand) {
textRange.set(textRange.get().union(range));
}
return true;
}
super.visitExpression(expression);
return false;
}
public void visitExpressionList(PsiExpressionList expressionList) {
@@ -25,6 +25,8 @@ import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.*;
import com.intellij.debugger.engine.evaluation.*;
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilder;
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
import com.intellij.debugger.engine.evaluation.expression.UnBoxingEvaluator;
import com.intellij.debugger.engine.requests.RequestManagerImpl;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.debugger.requests.Requestor;
@@ -865,6 +867,14 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils {
return PsiParameter.EMPTY_ARRAY;
}
public static boolean evaluateBoolean(ExpressionEvaluator evaluator, EvaluationContextImpl context) throws EvaluateException {
Object value = UnBoxingEvaluator.unbox(evaluator.evaluate(context), context);
if (!(value instanceof BooleanValue)) {
throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.expected"));
}
return ((BooleanValue)value).booleanValue();
}
public static boolean intersects(@NotNull TextRange range, @NotNull PsiElement elem) {
TextRange elemRange = elem.getTextRange();
return elemRange != null && elemRange.intersects(range);
@@ -25,8 +25,8 @@ import com.intellij.debugger.engine.*;
import com.intellij.debugger.engine.evaluation.*;
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
import com.intellij.debugger.engine.evaluation.expression.UnBoxingEvaluator;
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.debugger.requests.ClassPrepareRequestor;
@@ -371,13 +371,7 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
return EvaluatorBuilderImpl.build(getCondition(), contextPsiElement, contextSourcePosition, project);
}
});
Object value = UnBoxingEvaluator.unbox(evaluator.evaluate(context), context);
if (!(value instanceof BooleanValue)) {
throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.expected"));
}
if (!((BooleanValue)value).booleanValue()) {
return false;
}
return DebuggerUtilsEx.evaluateBoolean(evaluator, context);
}
catch (EvaluateException ex) {
if (ex.getCause() instanceof VMDisconnectedException) {
@@ -387,7 +381,6 @@ public abstract class Breakpoint<P extends JavaBreakpointProperties> implements
DebuggerBundle.message("error.failed.evaluating.breakpoint.condition", getCondition(), ex.getMessage())
);
}
return true;
}
protected String calculateEventClass(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException {