mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
async debugger:
- store Locations for frames - reuse XDebuggerFramesList in views
This commit is contained in:
@@ -39,14 +39,12 @@ public class ShowRelatedStackAction extends AnAction {
|
||||
Project project = e.getProject();
|
||||
List<StackFrameItem> stack = getRelatedStack(e);
|
||||
if (project != null && stack != null) {
|
||||
DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
|
||||
|
||||
DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
|
||||
DebugProcessImpl debugProcess = DebuggerAction.getDebuggerContext(e.getDataContext()).getDebugProcess();
|
||||
if (debugProcess == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
new StackFramePopup(project, stack, debugProcess.getSearchScope()).show();
|
||||
StackFramePopup.show(stack, debugProcess);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.debugger.engine;
|
||||
|
||||
/**
|
||||
* @author egor
|
||||
*/
|
||||
public interface JVMStackFrameInfoProvider {
|
||||
boolean isSynthetic();
|
||||
boolean isInLibraryContent();
|
||||
}
|
||||
@@ -22,12 +22,15 @@ import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadGroupReferenceProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
import com.intellij.debugger.ui.breakpoints.StackCapturingLineBreakpoint;
|
||||
import com.intellij.debugger.ui.impl.watch.MethodsTracker;
|
||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.ui.ColoredTextContainer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.xdebugger.frame.XExecutionStack;
|
||||
import com.intellij.xdebugger.frame.XStackFrame;
|
||||
@@ -204,9 +207,26 @@ public class JavaExecutionStack extends XExecutionStack {
|
||||
|
||||
// replace the rest with the related stack (if available)
|
||||
if (Registry.is("debugger.capture.points") && frame instanceof JavaStackFrame) {
|
||||
List<? extends XStackFrame> relatedStack = StackCapturingLineBreakpoint.getRelatedStack(frameProxy, suspendContext);
|
||||
List<StackFrameItem> relatedStack = StackCapturingLineBreakpoint.getRelatedStack(frameProxy, suspendContext);
|
||||
if (!ContainerUtil.isEmpty(relatedStack)) {
|
||||
myContainer.addStackFrames(relatedStack, true);
|
||||
int i = 0;
|
||||
for (StackFrameItem stackFrame : relatedStack) {
|
||||
if (i > StackCapturingLineBreakpoint.MAX_STACK_LENGTH) {
|
||||
myContainer.addStackFrames(Collections.singletonList(new XStackFrame() {
|
||||
@Override
|
||||
public void customizePresentation(@NotNull ColoredTextContainer component) {
|
||||
component.append("Too many frames, the rest is truncated...", SimpleTextAttributes.REGULAR_ITALIC_ATTRIBUTES);
|
||||
}
|
||||
}), true);
|
||||
return;
|
||||
}
|
||||
XStackFrame newFrame = stackFrame.createFrame(myDebugProcess);
|
||||
if (showFrame(newFrame)) {
|
||||
myContainer.addStackFrames(Collections.singletonList(newFrame), false);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
myContainer.addStackFrames(Collections.emptyList(), true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -221,10 +241,10 @@ public class JavaExecutionStack extends XExecutionStack {
|
||||
}
|
||||
|
||||
private static boolean showFrame(@NotNull XStackFrame frame) {
|
||||
if (XDebuggerSettingsManager.getInstance().getDataViewSettings().isShowLibraryStackFrames()) return true;
|
||||
if (frame instanceof JavaStackFrame) {
|
||||
StackFrameDescriptorImpl descriptor = ((JavaStackFrame)frame).getDescriptor();
|
||||
return !descriptor.isSynthetic() && !descriptor.isInLibraryContent();
|
||||
if (!XDebuggerSettingsManager.getInstance().getDataViewSettings().isShowLibraryStackFrames() &&
|
||||
frame instanceof JVMStackFrameInfoProvider) {
|
||||
JVMStackFrameInfoProvider info = (JVMStackFrameInfoProvider)frame;
|
||||
return !info.isSynthetic() && !info.isInLibraryContent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ import java.util.*;
|
||||
/**
|
||||
* @author egor
|
||||
*/
|
||||
public class JavaStackFrame extends XStackFrame {
|
||||
public class JavaStackFrame extends XStackFrame implements JVMStackFrameInfoProvider {
|
||||
private static final Logger LOG = Logger.getInstance(JavaStackFrame.class);
|
||||
|
||||
private final DebugProcessImpl myDebugProcess;
|
||||
@@ -668,4 +668,14 @@ public class JavaStackFrame extends XStackFrame {
|
||||
});
|
||||
return rangeRef.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSynthetic() {
|
||||
return myDescriptor.isSynthetic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInLibraryContent() {
|
||||
return myDescriptor.isInLibraryContent();
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +16,13 @@
|
||||
package com.intellij.debugger.memory.action.tracking;
|
||||
|
||||
import com.intellij.debugger.DebuggerManager;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.memory.action.DebuggerTreeAction;
|
||||
import com.intellij.debugger.memory.component.MemoryViewDebugProcessData;
|
||||
import com.intellij.debugger.memory.ui.StackFramePopup;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebuggerManager;
|
||||
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
|
||||
@@ -45,9 +45,9 @@ public class JumpToAllocationSourceAction extends DebuggerTreeAction {
|
||||
if (project != null && stack != null) {
|
||||
final XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession();
|
||||
if (session != null) {
|
||||
final GlobalSearchScope searchScope = DebuggerManager.getInstance(project)
|
||||
.getDebugProcess(session.getDebugProcess().getProcessHandler()).getSearchScope();
|
||||
new StackFramePopup(project, stack, searchScope).show();
|
||||
DebugProcessImpl process = (DebugProcessImpl)DebuggerManager.getInstance(project)
|
||||
.getDebugProcess(session.getDebugProcess().getProcessHandler());
|
||||
StackFramePopup.show(stack, process);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -39,7 +39,6 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.ui.DoubleClickListener;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
@@ -221,9 +220,7 @@ public class InstancesWindow extends DialogWrapper {
|
||||
});
|
||||
|
||||
|
||||
final StackFrameList list = new StackFrameList(myProject,
|
||||
Collections.emptyList(),
|
||||
GlobalSearchScope.allScope(myProject));
|
||||
final StackFrameList list = new StackFrameList(myDebugProcess);
|
||||
|
||||
list.addListSelectionListener(e -> list.navigateToSelectedValue(false));
|
||||
new DoubleClickListener() {
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -42,7 +42,6 @@ class InstancesWithStackFrameView {
|
||||
private static final String EMPTY_TEXT_WHEN_ITEM_NOT_SELECTED = "Select instance to see stack frame";
|
||||
private static final String EMPTY_TEXT_WHEN_STACK_NOT_FOUND = "No stack frame for this instance";
|
||||
private static final String TEXT_FOR_ARRAYS = "Arrays could not be tracked";
|
||||
private static final List<StackFrameItem> EMPTY_FRAME = Collections.emptyList();
|
||||
|
||||
private float myHidedProportion;
|
||||
|
||||
@@ -108,7 +107,7 @@ class InstancesWithStackFrameView {
|
||||
if (ref != null && data != null) {
|
||||
List<StackFrameItem> stack = data.getTrackedStacks().getStack(ref);
|
||||
if (stack != null) {
|
||||
list.setFrame(stack);
|
||||
list.setFrameItems(stack);
|
||||
if (mySplitter.getProportion() == 1.f) {
|
||||
mySplitter.setProportion(DEFAULT_SPLITTER_PROPORTION);
|
||||
}
|
||||
@@ -120,7 +119,7 @@ class InstancesWithStackFrameView {
|
||||
list.setEmptyText(EMPTY_TEXT_WHEN_ITEM_NOT_SELECTED);
|
||||
}
|
||||
|
||||
list.setFrame(EMPTY_FRAME);
|
||||
list.setFrameItems(Collections.emptyList());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
package com.intellij.debugger.memory.ui;
|
||||
|
||||
import com.intellij.debugger.engine.DebuggerUtils;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
import com.intellij.execution.filters.OpenFileHyperlinkInfo;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
@@ -26,125 +26,97 @@ import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.ui.ColoredListCellRenderer;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.xdebugger.XSourcePosition;
|
||||
import com.intellij.xdebugger.frame.XStackFrame;
|
||||
import com.intellij.xdebugger.impl.frame.XDebuggerFramesList;
|
||||
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class StackFrameList extends JBList<StackFrameItem> {
|
||||
private static final char ANONYMOUS_CLASS_DELIMITER = '$';
|
||||
class StackFrameList extends XDebuggerFramesList {
|
||||
private static final MyOpenFilesState myEditorState = new MyOpenFilesState();
|
||||
|
||||
private List<StackFrameItem> myStackFrames;
|
||||
private final Project myProject;
|
||||
private final GlobalSearchScope myScope;
|
||||
private final MyListModel myModel = new MyListModel();
|
||||
private final DebugProcessImpl myDebugProcess;
|
||||
|
||||
StackFrameList(@NotNull Project project,
|
||||
@NotNull List<StackFrameItem> stack,
|
||||
@NotNull GlobalSearchScope searchScope) {
|
||||
super();
|
||||
|
||||
myStackFrames = new ArrayList<>(stack);
|
||||
myProject = project;
|
||||
myScope = searchScope;
|
||||
|
||||
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
setModel(myModel);
|
||||
|
||||
setCellRenderer(new ColoredListCellRenderer<StackFrameItem>() {
|
||||
@Override
|
||||
protected void customizeCellRenderer(@NotNull JList<? extends StackFrameItem> list,
|
||||
StackFrameItem value, int index, boolean isSelected, boolean hasFocus) {
|
||||
value.customizePresentation(this);
|
||||
setIcon(null); // no icons in the list
|
||||
}
|
||||
});
|
||||
StackFrameList(DebugProcessImpl debugProcess) {
|
||||
super(debugProcess.getProject());
|
||||
myDebugProcess = debugProcess;
|
||||
}
|
||||
|
||||
void setFrame(@NotNull List<StackFrameItem> stack) {
|
||||
myModel.update(stack);
|
||||
void setFrameItems(@NotNull List<StackFrameItem> items) {
|
||||
setFrameItems(items, null);
|
||||
}
|
||||
|
||||
void navigateToSelectedValue(boolean focusOnEditor) {
|
||||
StackFrameItem selectedValue = getSelectedValue();
|
||||
if (selectedValue != null) {
|
||||
navigateToFrame(selectedValue, focusOnEditor);
|
||||
}
|
||||
}
|
||||
|
||||
private void navigateToFrame(@NotNull StackFrameItem frame, boolean focusOnEditor) {
|
||||
String path = frame.path();
|
||||
int anonymousClassDelimiterIndex = path.indexOf(ANONYMOUS_CLASS_DELIMITER);
|
||||
int pathLength = anonymousClassDelimiterIndex > 0 ? anonymousClassDelimiterIndex : path.length();
|
||||
path = path.substring(0, pathLength);
|
||||
PsiClass psiClass = DebuggerUtils.findClass(path, myProject, myScope);
|
||||
if (psiClass != null) {
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
PsiElement navigationElement = psiClass.getNavigationElement();
|
||||
VirtualFile file = PsiUtilCore.getVirtualFile(navigationElement);
|
||||
|
||||
if (file == null) {
|
||||
file = psiClass.getContainingFile().getVirtualFile();
|
||||
}
|
||||
|
||||
OpenFileHyperlinkInfo info =
|
||||
new OpenFileHyperlinkInfo(myProject, file, frame.line() - 1);
|
||||
OpenFileDescriptor descriptor = info.getDescriptor();
|
||||
if (descriptor != null) {
|
||||
FileEditorManagerImpl manager = (FileEditorManagerImpl)FileEditorManager.getInstance(myProject);
|
||||
VirtualFile lastFile = myEditorState.myLastOpenedFile;
|
||||
if (myEditorState.myIsNeedToCloseLastOpenedFile && lastFile != null &&
|
||||
manager.isFileOpen(lastFile) && !lastFile.equals(descriptor.getFile())) {
|
||||
manager.closeFile(myEditorState.myLastOpenedFile, false, true);
|
||||
void setFrameItems(@NotNull List<StackFrameItem> items, Runnable onDone) {
|
||||
clear();
|
||||
if (!items.isEmpty()) {
|
||||
myDebugProcess.getManagerThread().schedule(new DebuggerCommandImpl() {
|
||||
@Override
|
||||
protected void action() throws Exception {
|
||||
for (StackFrameItem frameInfo : items) {
|
||||
StackFrameItem.CapturedStackFrame frame = frameInfo.createFrame(myDebugProcess);
|
||||
DebuggerUIUtil.invokeLater(() -> getModel().addElement(frame));
|
||||
}
|
||||
|
||||
descriptor.setScrollType(ScrollType.CENTER);
|
||||
descriptor.setUseCurrentWindow(true);
|
||||
|
||||
if (lastFile == null || !lastFile.equals(descriptor.getFile())) {
|
||||
myEditorState.myIsNeedToCloseLastOpenedFile = !manager.isFileOpen(descriptor.getFile());
|
||||
}
|
||||
|
||||
descriptor.navigateInEditor(myProject, focusOnEditor);
|
||||
FileEditor[] editors = manager.getEditors(descriptor.getFile());
|
||||
if (editors.length != 0) {
|
||||
myEditorState.myLastOpenedFile = descriptor.getFile();
|
||||
if (onDone != null) {
|
||||
onDone.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFrameChanged(Object selectedValue) {
|
||||
navigateTo(selectedValue, false);
|
||||
}
|
||||
|
||||
void navigateToSelectedValue(boolean focusOnEditor) {
|
||||
navigateTo(getSelectedValue(), focusOnEditor);
|
||||
}
|
||||
|
||||
private void navigateTo(Object frame, boolean focusOnEditor) {
|
||||
if (frame instanceof XStackFrame) {
|
||||
navigateToFrame((XStackFrame)frame, focusOnEditor);
|
||||
}
|
||||
}
|
||||
|
||||
private void navigateToFrame(@NotNull XStackFrame frame, boolean focusOnEditor) {
|
||||
XSourcePosition position = frame.getSourcePosition();
|
||||
if (position == null) return;
|
||||
|
||||
VirtualFile file = position.getFile();
|
||||
int line = position.getLine();
|
||||
|
||||
Project project = myDebugProcess.getProject();
|
||||
|
||||
OpenFileHyperlinkInfo info = new OpenFileHyperlinkInfo(project, file, line);
|
||||
OpenFileDescriptor descriptor = info.getDescriptor();
|
||||
if (descriptor != null) {
|
||||
FileEditorManagerImpl manager = (FileEditorManagerImpl)FileEditorManager.getInstance(project);
|
||||
VirtualFile lastFile = myEditorState.myLastOpenedFile;
|
||||
if (myEditorState.myIsNeedToCloseLastOpenedFile && lastFile != null &&
|
||||
manager.isFileOpen(lastFile) && !lastFile.equals(descriptor.getFile())) {
|
||||
manager.closeFile(myEditorState.myLastOpenedFile, false, true);
|
||||
}
|
||||
|
||||
descriptor.setScrollType(ScrollType.CENTER);
|
||||
descriptor.setUseCurrentWindow(true);
|
||||
|
||||
if (lastFile == null || !lastFile.equals(descriptor.getFile())) {
|
||||
myEditorState.myIsNeedToCloseLastOpenedFile = !manager.isFileOpen(descriptor.getFile());
|
||||
}
|
||||
|
||||
descriptor.navigateInEditor(project, focusOnEditor);
|
||||
FileEditor[] editors = manager.getEditors(descriptor.getFile());
|
||||
if (editors.length != 0) {
|
||||
myEditorState.myLastOpenedFile = descriptor.getFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyOpenFilesState {
|
||||
VirtualFile myLastOpenedFile;
|
||||
boolean myIsNeedToCloseLastOpenedFile;
|
||||
}
|
||||
|
||||
private class MyListModel extends AbstractListModel<StackFrameItem> {
|
||||
|
||||
void update(@NotNull List<StackFrameItem> newFrame) {
|
||||
fireIntervalRemoved(this, 0, getSize());
|
||||
myStackFrames = newFrame;
|
||||
fireIntervalAdded(this, 0, getSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return myStackFrames.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackFrameItem getElementAt(int index) {
|
||||
return myStackFrames.get(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,44 +15,28 @@
|
||||
*/
|
||||
package com.intellij.debugger.memory.ui;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
import com.intellij.openapi.ui.popup.JBPopup;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.xdebugger.impl.ui.DebuggerUIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.intellij.debugger.memory.utils.StackFrameItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StackFramePopup {
|
||||
private final Project myProject;
|
||||
private final List<StackFrameItem> myStackFrame;
|
||||
private final GlobalSearchScope myScope;
|
||||
|
||||
public StackFramePopup(@NotNull Project project,
|
||||
@NotNull List<StackFrameItem> stack,
|
||||
@NotNull GlobalSearchScope searchScope) {
|
||||
myProject = project;
|
||||
myStackFrame = stack;
|
||||
myScope = searchScope;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
StackFrameList list = new StackFrameList(myProject, myStackFrame, myScope);
|
||||
list.addListSelectionListener(e -> {
|
||||
if (!e.getValueIsAdjusting()) {
|
||||
list.navigateToSelectedValue(false);
|
||||
}
|
||||
});
|
||||
|
||||
JBPopup popup = JBPopupFactory.getInstance().createListPopupBuilder(list)
|
||||
public static void show(@NotNull List<StackFrameItem> stack, DebugProcessImpl debugProcess) {
|
||||
StackFrameList list = new StackFrameList(debugProcess);
|
||||
list.setFrameItems(stack, () -> DebuggerUIUtil.invokeLater(() -> {
|
||||
JBPopup popup = JBPopupFactory.getInstance().createListPopupBuilder(list)
|
||||
.setTitle("Select stack frame")
|
||||
.setAutoSelectIfEmpty(true)
|
||||
.setResizable(false)
|
||||
.setItemChoosenCallback(() -> list.navigateToSelectedValue(true))
|
||||
.createPopup();
|
||||
|
||||
list.setSelectedIndex(1);
|
||||
popup.showInFocusCenter();
|
||||
list.setSelectedIndex(1);
|
||||
popup.showInFocusCenter();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,27 +15,16 @@
|
||||
*/
|
||||
package com.intellij.debugger.memory.utils;
|
||||
|
||||
import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.DebugProcessImpl;
|
||||
import com.intellij.debugger.engine.JavaStackFrame;
|
||||
import com.intellij.debugger.engine.PositionManagerImpl;
|
||||
import com.intellij.debugger.engine.SuspendContextImpl;
|
||||
import com.intellij.debugger.engine.*;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.DecompiledLocalVariable;
|
||||
import com.intellij.debugger.jdi.LocalVariablesUtil;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
|
||||
import com.intellij.debugger.jdi.*;
|
||||
import com.intellij.debugger.settings.NodeRendererSettings;
|
||||
import com.intellij.debugger.ui.breakpoints.StackCapturingLineBreakpoint;
|
||||
import com.intellij.debugger.ui.impl.watch.MessageDescriptor;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.NullableLazyValue;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.ui.ColoredTextContainer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
@@ -58,99 +47,24 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class StackFrameItem extends XStackFrame {
|
||||
public class StackFrameItem {
|
||||
private static final Logger LOG = Logger.getInstance(StackFrameItem.class);
|
||||
|
||||
private final Project myProject;
|
||||
private final GlobalSearchScope mySearchScope;
|
||||
private final Location myLocation;
|
||||
private final List<XNamedValue> myVariables;
|
||||
|
||||
private final String myFilePath;
|
||||
private final String myMethodName;
|
||||
private final int myLineNumber;
|
||||
private List<XNamedValue> myVariables = null;
|
||||
private boolean myFirst;
|
||||
|
||||
private final NullableLazyValue<XSourcePosition> mySourcePosition;
|
||||
|
||||
public StackFrameItem(Project project,
|
||||
GlobalSearchScope scope,
|
||||
@NotNull String path,
|
||||
@NotNull String methodName,
|
||||
int line) {
|
||||
myProject = project;
|
||||
mySearchScope = scope;
|
||||
myFilePath = path.replace('\\', '.');
|
||||
myMethodName = methodName;
|
||||
myLineNumber = line;
|
||||
|
||||
//TODO: need to reuse PositionManager somehow
|
||||
mySourcePosition = NullableLazyValue.createValue(() -> {
|
||||
PsiClass psiClass = PositionManagerImpl.findClass(myProject, myFilePath, mySearchScope);
|
||||
if (psiClass == null) {
|
||||
return null;
|
||||
}
|
||||
PsiElement element = psiClass.getNavigationElement();
|
||||
// see IDEA-137167, prefer not compiled elements
|
||||
if (element instanceof PsiCompiledElement) {
|
||||
PsiElement fileElement = psiClass.getContainingFile().getNavigationElement();
|
||||
if (!(fileElement instanceof PsiCompiledElement)) {
|
||||
element = fileElement;
|
||||
}
|
||||
}
|
||||
SourcePosition position = SourcePosition.createFromLine(element.getContainingFile(), myLineNumber - 1);
|
||||
PsiFile psiFile = psiClass.getContainingFile().getOriginalFile();
|
||||
if (psiFile instanceof PsiCompiledFile) {
|
||||
position = new PositionManagerImpl.ClsSourcePosition(position, myLineNumber - 1);
|
||||
}
|
||||
return DebuggerUtilsEx.toXSourcePosition(position);
|
||||
});
|
||||
public StackFrameItem(Location location, List<XNamedValue> variables) {
|
||||
myLocation = location;
|
||||
myVariables = variables;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String path() {
|
||||
return myFilePath;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String methodName() {
|
||||
return myMethodName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String className() {
|
||||
return StringUtil.getShortName(myFilePath);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String packageName() {
|
||||
return StringUtil.getPackageName(myFilePath);
|
||||
return myLocation.declaringType().name();
|
||||
}
|
||||
|
||||
public int line() {
|
||||
return myLineNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizePresentation(@NotNull ColoredTextContainer component) {
|
||||
component.setIcon(myFirst ? AllIcons.Actions.Menu_cut : JBUI.scale(EmptyIcon.create(6)));
|
||||
component.append(String.format("%s:%d, %s", myMethodName, myLineNumber, className()), SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
String packageName = packageName();
|
||||
if (!packageName.trim().isEmpty()) {
|
||||
component.append(String.format(" (%s)", packageName), SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public XSourcePosition getSourcePosition() {
|
||||
return mySourcePosition.getValue();
|
||||
}
|
||||
|
||||
void addVariable(XNamedValue var) {
|
||||
if (myVariables == null) {
|
||||
myVariables = new ArrayList<>();
|
||||
}
|
||||
myVariables.add(var);
|
||||
return myLocation.lineNumber();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -162,19 +76,9 @@ public class StackFrameItem extends XStackFrame {
|
||||
List<StackFrameItem> res = new ArrayList<>();
|
||||
for (StackFrameProxyImpl frame : threadReferenceProxy.frames()) {
|
||||
try {
|
||||
Location loc = frame.location();
|
||||
DebugProcessImpl debugProcess = suspendContext.getDebugProcess();
|
||||
StackFrameItem frameItem = new StackFrameItem(debugProcess.getProject(),
|
||||
debugProcess.getSearchScope(),
|
||||
loc.declaringType().name(),
|
||||
loc.method().name(),
|
||||
loc.lineNumber());
|
||||
if (res.isEmpty()) {
|
||||
frameItem.myFirst = true;
|
||||
}
|
||||
res.add(frameItem);
|
||||
|
||||
List<XNamedValue> vars = null;
|
||||
if (withVars) {
|
||||
vars = new ArrayList<>();
|
||||
List<StackFrameItem> relatedStack = StackCapturingLineBreakpoint.getRelatedStack(frame, suspendContext);
|
||||
if (!ContainerUtil.isEmpty(relatedStack)) {
|
||||
res.addAll(relatedStack);
|
||||
@@ -184,7 +88,7 @@ public class StackFrameItem extends XStackFrame {
|
||||
try {
|
||||
ObjectReference thisObject = frame.thisObject();
|
||||
if (thisObject != null) {
|
||||
frameItem.addVariable(createVariable(thisObject, "this", VariableItem.VarType.OBJECT));
|
||||
vars.add(createVariable(thisObject, "this", VariableItem.VarType.OBJECT));
|
||||
}
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
@@ -192,28 +96,25 @@ public class StackFrameItem extends XStackFrame {
|
||||
}
|
||||
|
||||
try {
|
||||
frame.visibleVariables().forEach(v -> {
|
||||
for (LocalVariableProxyImpl v : frame.visibleVariables()) {
|
||||
try {
|
||||
Value value = frame.getValue(v);
|
||||
VariableItem.VarType varType = VariableItem.VarType.OBJECT;
|
||||
if (v.getVariable().isArgument()) {
|
||||
varType = VariableItem.VarType.PARAM;
|
||||
}
|
||||
frameItem.addVariable(createVariable(value, v.name(), varType));
|
||||
VariableItem.VarType varType = v.getVariable().isArgument() ? VariableItem.VarType.PARAM :VariableItem.VarType.OBJECT;
|
||||
vars.add(createVariable(frame.getValue(v), v.name(), varType));
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
if (e.getCause() instanceof AbsentInformationException) {
|
||||
frameItem.addVariable(JavaStackFrame.createMessageNode(MessageDescriptor.LOCAL_VARIABLES_INFO_UNAVAILABLE.getLabel(),
|
||||
vars.add(JavaStackFrame.createMessageNode(MessageDescriptor.LOCAL_VARIABLES_INFO_UNAVAILABLE.getLabel(),
|
||||
XDebuggerUIConstants.INFORMATION_MESSAGE_ICON));
|
||||
// trying to collect values from variable slots
|
||||
try {
|
||||
for (Map.Entry<DecompiledLocalVariable, Value> entry : LocalVariablesUtil.fetchValues(frame, debugProcess).entrySet()) {
|
||||
frameItem.addVariable(createVariable(entry.getValue(), entry.getKey().getDisplayName(), VariableItem.VarType.PARAM));
|
||||
for (Map.Entry<DecompiledLocalVariable, Value> entry : LocalVariablesUtil
|
||||
.fetchValues(frame, suspendContext.getDebugProcess()).entrySet()) {
|
||||
vars.add(createVariable(entry.getValue(), entry.getKey().getDisplayName(), VariableItem.VarType.PARAM));
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
@@ -225,6 +126,9 @@ public class StackFrameItem extends XStackFrame {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StackFrameItem frameItem = new StackFrameItem(frame.location(), vars);
|
||||
res.add(frameItem);
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
LOG.debug(e);
|
||||
@@ -248,18 +152,6 @@ public class StackFrameItem extends XStackFrame {
|
||||
return new VariableItem(name, type, valueText, varType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeChildren(@NotNull XCompositeNode node) {
|
||||
if (myVariables != null) {
|
||||
XValueChildrenList children = new XValueChildrenList();
|
||||
myVariables.forEach(children::add);
|
||||
node.addChildren(children, true);
|
||||
}
|
||||
else {
|
||||
node.addChildren(XValueChildrenList.EMPTY, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static class VariableItem extends XNamedValue {
|
||||
enum VarType {PARAM, OBJECT}
|
||||
|
||||
@@ -281,4 +173,76 @@ public class StackFrameItem extends XStackFrame {
|
||||
node.setPresentation(icon, type, myValue, false);
|
||||
}
|
||||
}
|
||||
|
||||
public CapturedStackFrame createFrame(DebugProcessImpl debugProcess) {
|
||||
return new CapturedStackFrame(debugProcess, this);
|
||||
}
|
||||
|
||||
public static class CapturedStackFrame extends XStackFrame implements JVMStackFrameInfoProvider {
|
||||
private final XSourcePosition mySourcePosition;
|
||||
private final boolean myIsSynthetic;
|
||||
private final boolean myIsInLibraryContent;
|
||||
|
||||
private final String myPath;
|
||||
private final String myMethodName;
|
||||
private final int myLineNumber;
|
||||
|
||||
private final List<XNamedValue> myVariables;
|
||||
|
||||
public CapturedStackFrame(DebugProcessImpl debugProcess, StackFrameItem item) {
|
||||
DebuggerManagerThreadImpl.assertIsManagerThread();
|
||||
mySourcePosition = DebuggerUtilsEx.toXSourcePosition(debugProcess.getPositionManager().getSourcePosition(item.myLocation));
|
||||
myIsSynthetic = DebuggerUtils.isSynthetic(item.myLocation.method());
|
||||
myIsInLibraryContent =
|
||||
DebuggerUtilsEx.isInLibraryContent(mySourcePosition != null ? mySourcePosition.getFile() : null, debugProcess.getProject());
|
||||
myPath = item.path();
|
||||
myMethodName = item.myLocation.method().name();
|
||||
myLineNumber = item.line();
|
||||
myVariables = item.myVariables;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public XSourcePosition getSourcePosition() {
|
||||
return mySourcePosition;
|
||||
}
|
||||
|
||||
public boolean isSynthetic() {
|
||||
return myIsSynthetic;
|
||||
}
|
||||
|
||||
public boolean isInLibraryContent() {
|
||||
return myIsInLibraryContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizePresentation(@NotNull ColoredTextContainer component) {
|
||||
//component.setIcon(myFirst ? AllIcons.Actions.Menu_cut : JBUI.scale(EmptyIcon.create(6)));
|
||||
component.setIcon(JBUI.scale(EmptyIcon.create(6)));
|
||||
component.append(String.format("%s:%d, %s", myMethodName, myLineNumber, StringUtil.getShortName(myPath)), getAttributes());
|
||||
String packageName = StringUtil.getPackageName(myPath);
|
||||
if (!packageName.trim().isEmpty()) {
|
||||
component.append(String.format(" (%s)", packageName), SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeChildren(@NotNull XCompositeNode node) {
|
||||
if (myVariables != null) {
|
||||
XValueChildrenList children = new XValueChildrenList();
|
||||
myVariables.forEach(children::add);
|
||||
node.addChildren(children, true);
|
||||
}
|
||||
else {
|
||||
node.addChildren(XValueChildrenList.EMPTY, true);
|
||||
}
|
||||
}
|
||||
|
||||
private SimpleTextAttributes getAttributes() {
|
||||
if (isSynthetic() || isInLibraryContent()) {
|
||||
return SimpleTextAttributes.GRAYED_ATTRIBUTES;
|
||||
}
|
||||
return SimpleTextAttributes.REGULAR_ATTRIBUTES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-22
@@ -35,10 +35,7 @@ import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.NullableLazyValue;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.ColoredTextContainer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.xdebugger.XSourcePosition;
|
||||
import com.sun.jdi.Location;
|
||||
import com.sun.jdi.Method;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
@@ -49,7 +46,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.java.debugger.breakpoints.properties.JavaMethodBreakpointProperties;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
@@ -66,7 +66,7 @@ public class StackCapturingLineBreakpoint extends WildcardMethodBreakpoint {
|
||||
public static final Key<List<StackCapturingLineBreakpoint>> CAPTURE_BREAKPOINTS = Key.create("CAPTURE_BREAKPOINTS");
|
||||
public static final Key<Map<ObjectReference, List<StackFrameItem>>> CAPTURED_STACKS = Key.create("CAPTURED_STACKS");
|
||||
private static final int MAX_STORED_STACKS = 1000;
|
||||
private static final int MAX_STACK_LENGTH = 500;
|
||||
public static final int MAX_STACK_LENGTH = 500;
|
||||
|
||||
private final JavaMethodBreakpointProperties myProperties = new JavaMethodBreakpointProperties();
|
||||
|
||||
@@ -124,10 +124,7 @@ public class StackCapturingLineBreakpoint extends WildcardMethodBreakpoint {
|
||||
if (key instanceof ObjectReference) {
|
||||
List<StackFrameItem> frames = StackFrameItem.createFrames(suspendContext.getThread(), suspendContext, true);
|
||||
if (frames.size() > MAX_STACK_LENGTH) {
|
||||
ArrayList<StackFrameItem> truncated = new ArrayList<>(MAX_STACK_LENGTH + 1);
|
||||
truncated.addAll(frames.subList(0, MAX_STACK_LENGTH));
|
||||
truncated.add(TOO_MANY_FRAMES);
|
||||
frames = truncated;
|
||||
frames = frames.subList(0, MAX_STACK_LENGTH);
|
||||
}
|
||||
stacks.put((ObjectReference)key, frames);
|
||||
}
|
||||
@@ -139,19 +136,6 @@ public class StackCapturingLineBreakpoint extends WildcardMethodBreakpoint {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static StackFrameItem TOO_MANY_FRAMES = new StackFrameItem(null, null, "", "", -1) {
|
||||
@Nullable
|
||||
@Override
|
||||
public XSourcePosition getSourcePosition() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizePresentation(@NotNull ColoredTextContainer component) {
|
||||
component.append("Too many frames, the rest is truncated...", SimpleTextAttributes.REGULAR_ITALIC_ATTRIBUTES);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public StreamEx matchingMethods(StreamEx<Method> methods, DebugProcessImpl debugProcess) {
|
||||
String methodName = getMethodName();
|
||||
|
||||
+6
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,6 +46,11 @@ public abstract class DebuggerFramesList extends JBList implements OccurenceNavi
|
||||
getEmptyText().setText(XDebuggerBundle.message("debugger.frames.not.available"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModel(ListModel model) {
|
||||
// do not allow to change model (e.g. to FilteringListModel)
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultListModel getModel() {
|
||||
return (DefaultListModel)super.getModel();
|
||||
|
||||
Reference in New Issue
Block a user