From 42764d22ffeaa8d2bd16cc8d52b0f9cc3a6df38b Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Tue, 30 Aug 2016 18:58:18 +0300 Subject: [PATCH] IDEA-70913 smart step into should not propose methods from both branches in conditional expressions --- .../actions/JavaSmartStepIntoHandler.java | 60 +++++++++++++++---- .../debugger/impl/DebuggerUtilsEx.java | 10 ++++ .../debugger/ui/breakpoints/Breakpoint.java | 11 +--- 3 files changed, 59 insertions(+), 22 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java index 707612ab4bce..883b0b8427c6 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java @@ -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 targets = ApplicationManager.getApplication().runReadAction( - (Computable>)() -> findSmartStepTargets(position, suspendContext)); + (Computable>)() -> 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 findSmartStepTargets(final SourcePosition position, @Nullable SuspendContextImpl suspendContext) { + protected List 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) { diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java index 14a8a1994abd..6d34c7f0dc69 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java @@ -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); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java index cfee49e7c399..c76b62fb1f68 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java @@ -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

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

implements DebuggerBundle.message("error.failed.evaluating.breakpoint.condition", getCondition(), ex.getMessage()) ); } - return true; } protected String calculateEventClass(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException {