diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ShowRelatedStackAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/ShowRelatedStackAction.java index f6e54fdfdb07..b810f8d4551f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/ShowRelatedStackAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/ShowRelatedStackAction.java @@ -39,14 +39,12 @@ public class ShowRelatedStackAction extends AnAction { Project project = e.getProject(); List 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); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JVMStackFrameInfoProvider.java b/java/debugger/impl/src/com/intellij/debugger/engine/JVMStackFrameInfoProvider.java new file mode 100644 index 000000000000..9efbfdc0a500 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JVMStackFrameInfoProvider.java @@ -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(); +} diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaExecutionStack.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaExecutionStack.java index 19e7d36e304a..99c306c26765 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaExecutionStack.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaExecutionStack.java @@ -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 relatedStack = StackCapturingLineBreakpoint.getRelatedStack(frameProxy, suspendContext); + List 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; } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java index 12f40ba54430..eb5992263edd 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStackFrame.java @@ -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(); + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java b/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java index 489ae76d6f06..af976ac14fef 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/action/tracking/JumpToAllocationSourceAction.java @@ -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); } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java index 619eb6fd1dc4..4c950c91ed0f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWindow.java @@ -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() { diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWithStackFrameView.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWithStackFrameView.java index 23d678182978..4fc5b098e06f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWithStackFrameView.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesWithStackFrameView.java @@ -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 EMPTY_FRAME = Collections.emptyList(); private float myHidedProportion; @@ -108,7 +107,7 @@ class InstancesWithStackFrameView { if (ref != null && data != null) { List 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()); }); } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/StackFrameList.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/StackFrameList.java index 05e2b9fa50d7..7918307e10dc 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/StackFrameList.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/StackFrameList.java @@ -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 { - private static final char ANONYMOUS_CLASS_DELIMITER = '$'; +class StackFrameList extends XDebuggerFramesList { private static final MyOpenFilesState myEditorState = new MyOpenFilesState(); - private List 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 stack, - @NotNull GlobalSearchScope searchScope) { - super(); - - myStackFrames = new ArrayList<>(stack); - myProject = project; - myScope = searchScope; - - setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - - setModel(myModel); - - setCellRenderer(new ColoredListCellRenderer() { - @Override - protected void customizeCellRenderer(@NotNull JList 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 stack) { - myModel.update(stack); + void setFrameItems(@NotNull List 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 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 { - - void update(@NotNull List 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); - } - } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/StackFramePopup.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/StackFramePopup.java index 3bf5a6d0d61f..ff063c9d68ac 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/StackFramePopup.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/StackFramePopup.java @@ -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 myStackFrame; - private final GlobalSearchScope myScope; - - public StackFramePopup(@NotNull Project project, - @NotNull List 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 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(); + })); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/utils/StackFrameItem.java b/java/debugger/impl/src/com/intellij/debugger/memory/utils/StackFrameItem.java index 74941fe43e75..29fc0bcb5f79 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/utils/StackFrameItem.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/utils/StackFrameItem.java @@ -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 myVariables; - private final String myFilePath; - private final String myMethodName; - private final int myLineNumber; - private List myVariables = null; - private boolean myFirst; - - private final NullableLazyValue 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 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 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 vars = null; if (withVars) { + vars = new ArrayList<>(); List 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 entry : LocalVariablesUtil.fetchValues(frame, debugProcess).entrySet()) { - frameItem.addVariable(createVariable(entry.getValue(), entry.getKey().getDisplayName(), VariableItem.VarType.PARAM)); + for (Map.Entry 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 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; + } + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/StackCapturingLineBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/StackCapturingLineBreakpoint.java index a154bf89e839..9dcb880b0fe2 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/StackCapturingLineBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/StackCapturingLineBreakpoint.java @@ -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> CAPTURE_BREAKPOINTS = Key.create("CAPTURE_BREAKPOINTS"); public static final Key>> 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 frames = StackFrameItem.createFrames(suspendContext.getThread(), suspendContext, true); if (frames.size() > MAX_STACK_LENGTH) { - ArrayList 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 methods, DebugProcessImpl debugProcess) { String methodName = getMethodName(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/DebuggerFramesList.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/DebuggerFramesList.java index bd5ea1e051ff..28eff24ce0e7 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/DebuggerFramesList.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/DebuggerFramesList.java @@ -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();