mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-70251 smart step into displays in popup methods that have already been executed
This commit is contained in:
@@ -16,19 +16,34 @@
|
||||
package com.intellij.debugger.actions;
|
||||
|
||||
import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerSession;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.MethodBytecodeUtil;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.TextEditor;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.DocumentUtil;
|
||||
import com.intellij.util.Range;
|
||||
import com.intellij.util.containers.OrderedSet;
|
||||
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
|
||||
import com.sun.jdi.Location;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -39,6 +54,8 @@ import java.util.Stack;
|
||||
* Date: 22.11.11
|
||||
*/
|
||||
public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
|
||||
private static final Logger LOG = Logger.getInstance(JavaSmartStepIntoHandler.class);
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(final SourcePosition position) {
|
||||
final PsiFile file = position.getFile();
|
||||
@@ -46,8 +63,37 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doSmartStep(SourcePosition position, DebuggerSession session, TextEditor fileEditor) {
|
||||
session.getProcess().getManagerThread().schedule(new DebuggerContextCommandImpl(session.getContextManager().getContext()) {
|
||||
@Override
|
||||
public void threadAction(@NotNull SuspendContextImpl suspendContext) {
|
||||
List<SmartStepTarget> targets = ApplicationManager.getApplication().runReadAction(
|
||||
(Computable<List<SmartStepTarget>>)() -> findSmartStepTargets(position, suspendContext));
|
||||
DebuggerUIUtil.invokeLater(() -> {
|
||||
if (targets.isEmpty()) {
|
||||
doStepInto(session, Registry.is("debugger.single.smart.step.force"), null);
|
||||
}
|
||||
else {
|
||||
handleTargets(position, session, fileEditor, targets);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Priority getPriority() {
|
||||
return Priority.NORMAL;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<SmartStepTarget> findSmartStepTargets(final SourcePosition position) {
|
||||
@Override
|
||||
public List<SmartStepTarget> findSmartStepTargets(SourcePosition position) {
|
||||
throw new IllegalStateException("Should not be used");
|
||||
}
|
||||
|
||||
protected List<SmartStepTarget> findSmartStepTargets(final SourcePosition position, @Nullable SuspendContextImpl suspendContext) {
|
||||
final int line = position.getLine();
|
||||
if (line < 0) {
|
||||
return Collections.emptyList(); // the document has been changed
|
||||
@@ -82,7 +128,7 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
|
||||
}
|
||||
element = parent;
|
||||
}
|
||||
while(true);
|
||||
while (true);
|
||||
|
||||
//noinspection unchecked
|
||||
final List<SmartStepTarget> targets = new OrderedSet<>();
|
||||
@@ -222,10 +268,42 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
|
||||
|
||||
Range<Integer> lines =
|
||||
new Range<>(doc.getLineNumber(textRange.get().getStartOffset()), doc.getLineNumber(textRange.get().getEndOffset()));
|
||||
for (SmartStepTarget target : targets) {
|
||||
target.setCallingExpressionLines(lines);
|
||||
targets.forEach(t -> t.setCallingExpressionLines(lines));
|
||||
|
||||
if (!targets.isEmpty()) {
|
||||
StackFrameProxyImpl frameProxy = suspendContext != null ? suspendContext.getFrameProxy() : null;
|
||||
if (frameProxy != null) {
|
||||
try {
|
||||
Location location = frameProxy.location();
|
||||
MethodBytecodeUtil.visit(location.declaringType(), location.method(), location.codeIndex(), new MethodVisitor(Opcodes.ASM5) {
|
||||
boolean myLineMatch = false;
|
||||
|
||||
@Override
|
||||
public void visitLineNumber(int line, Label start) {
|
||||
myLineMatch = lines.isWithin(line - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||
if (myLineMatch) {
|
||||
targets.removeIf(t -> {
|
||||
if (t instanceof MethodSmartStepTarget) {
|
||||
return DebuggerUtilsEx.methodMatches(((MethodSmartStepTarget)t).getMethod(),
|
||||
owner.replace("/", "."), name, desc, suspendContext.getDebugProcess());
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
|
||||
return targets;
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
+6
-1
@@ -17,6 +17,7 @@ package com.intellij.debugger.actions;
|
||||
|
||||
import com.intellij.debugger.DebuggerManagerEx;
|
||||
import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.MethodFilter;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerSession;
|
||||
@@ -51,8 +52,12 @@ public class JvmSmartStepIntoActionHandler extends DebuggerActionHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
doStepInto(session, Registry.is("debugger.single.smart.step.force"), null);
|
||||
}
|
||||
|
||||
static void doStepInto(DebuggerSession session, boolean force, MethodFilter filter) {
|
||||
session.sessionResumed();
|
||||
session.stepInto(Registry.is("debugger.single.smart.step.force"), null);
|
||||
session.stepInto(force, filter);
|
||||
}
|
||||
|
||||
public boolean isEnabled(@NotNull final Project project, final AnActionEvent event) {
|
||||
|
||||
@@ -57,21 +57,22 @@ public abstract class JvmSmartStepIntoHandler {
|
||||
* @return false to continue for another handler or for default action (step into)
|
||||
*/
|
||||
public boolean doSmartStep(SourcePosition position, final DebuggerSession session, TextEditor fileEditor) {
|
||||
final List<SmartStepTarget> targets = findSmartStepTargets(position);
|
||||
return handleTargets(position, session, fileEditor, findSmartStepTargets(position));
|
||||
}
|
||||
|
||||
protected final boolean handleTargets(SourcePosition position,
|
||||
DebuggerSession session,
|
||||
TextEditor fileEditor,
|
||||
List<SmartStepTarget> targets) {
|
||||
if (!targets.isEmpty()) {
|
||||
final SmartStepTarget firstTarget = targets.get(0);
|
||||
SmartStepTarget firstTarget = targets.get(0);
|
||||
if (targets.size() == 1) {
|
||||
session.sessionResumed();
|
||||
session.stepInto(Registry.is("debugger.single.smart.step.force"), createMethodFilter(firstTarget));
|
||||
doStepInto(session, Registry.is("debugger.single.smart.step.force"), firstTarget);
|
||||
}
|
||||
else {
|
||||
final Editor editor = fileEditor.getEditor();
|
||||
final PsiMethodListPopupStep popupStep = new PsiMethodListPopupStep(editor, targets, new PsiMethodListPopupStep.OnChooseRunnable() {
|
||||
public void execute(SmartStepTarget chosenTarget) {
|
||||
session.sessionResumed();
|
||||
session.stepInto(true, createMethodFilter(chosenTarget));
|
||||
}
|
||||
});
|
||||
Editor editor = fileEditor.getEditor();
|
||||
PsiMethodListPopupStep popupStep =
|
||||
new PsiMethodListPopupStep(editor, targets, chosenTarget -> doStepInto(session, true, chosenTarget));
|
||||
ListPopupImpl popup = new ListPopupImpl(popupStep);
|
||||
DebuggerUIUtil.registerExtraHandleShortcuts(popup, XDebuggerActions.STEP_INTO, XDebuggerActions.SMART_STEP_INTO);
|
||||
popup.setAdText(DebuggerUIUtil.getSelectionShortcutsAdText(XDebuggerActions.STEP_INTO, XDebuggerActions.SMART_STEP_INTO));
|
||||
@@ -95,6 +96,10 @@ public abstract class JvmSmartStepIntoHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void doStepInto(DebuggerSession session, boolean force, SmartStepTarget target) {
|
||||
JvmSmartStepIntoActionHandler.doStepInto(session, force, createMethodFilter(target));
|
||||
}
|
||||
|
||||
private static void highlightTarget(PsiMethodListPopupStep popupStep, SmartStepTarget target) {
|
||||
final PsiElement highlightElement = target.getHighlightElement();
|
||||
if (highlightElement != null) {
|
||||
|
||||
@@ -918,6 +918,23 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean methodMatches(@NotNull PsiMethod psiMethod,
|
||||
String className,
|
||||
String name,
|
||||
String signature,
|
||||
DebugProcessImpl process) {
|
||||
PsiClass containingClass = psiMethod.getContainingClass();
|
||||
try {
|
||||
return containingClass != null && Objects.equals(containingClass.getQualifiedName(), className) &&
|
||||
JVMNameUtil.getJVMMethodName(psiMethod).equals(name) &&
|
||||
JVMNameUtil.getJVMSignature(psiMethod).getName(process).equals(signature);
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
LOG.debug(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement getContainingMethod(@Nullable PsiElement elem) {
|
||||
return PsiTreeUtil.getContextOfType(elem, PsiMethod.class, PsiLambdaExpression.class, PsiClassInitializer.class);
|
||||
|
||||
@@ -1616,7 +1616,7 @@
|
||||
<xdebugger.breakpointType implementation="com.intellij.debugger.ui.breakpoints.JavaFieldBreakpointType"/>
|
||||
<xdebugger.breakpointType implementation="com.intellij.debugger.ui.breakpoints.JavaExceptionBreakpointType"/>
|
||||
<xdebugger.breakpointType implementation="com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType"/>
|
||||
<debugger.jvmSmartStepIntoHandler implementation="com.intellij.debugger.actions.JavaSmartStepIntoHandler"/>
|
||||
<debugger.jvmSmartStepIntoHandler implementation="com.intellij.debugger.actions.JavaSmartStepIntoHandler" order="last"/>
|
||||
<debugger.simplePropertyGetterProvider implementation="com.intellij.debugger.engine.JavaSimpleGetterProvider"/>
|
||||
<debugger.syntheticProvider implementation="com.intellij.debugger.engine.DefaultSyntheticProvider"/>
|
||||
<debugger.sourcePositionProvider implementation="com.intellij.debugger.engine.DefaultSourcePositionProvider" order="last"/>
|
||||
|
||||
Reference in New Issue
Block a user