Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement grouping of the stack frames #583

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions org.eclipse.jdt.debug.ui/plugin.properties
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ showMonitorThreadInfo.tooltip=Show the Thread & Monitor Information
showNullEntriesAction.label=Show &Null Array Entries
showNullEntriesAction.tooltip=Show Null Array Entries

collapseStackFrames.label=Collapse Stack Frames
collapseStackFrames.tooltip=Hide less relevant stack frames

stepIntoSelectionHyperlinkDetector.label=Step Into Selection
stepIntoSelectionHyperlinkDetector.description=Performs the step into selection command on demand via a hyperlink

Expand Down
8 changes: 8 additions & 0 deletions org.eclipse.jdt.debug.ui/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2225,6 +2225,14 @@
style="toggle"
menubarPath="org.eclipse.jdt.debug.ui.LaunchView.javaSubmenu/javaPart"
id="org.eclipse.jdt.debug.ui.launchViewActions.ShowMonitorThreadInfo"/>
<action
helpContextId="collapse_stack_frames_action_context"
label="%collapseStackFrames.label"
tooltip="%collapseStackFrames.tooltip"
class="org.eclipse.jdt.internal.debug.ui.actions.CollapseStackFramesAction"
style="toggle"
menubarPath="org.eclipse.jdt.debug.ui.LaunchView.javaSubmenu/javaPart"
id="org.eclipse.jdt.debug.ui.launchViewActions.CollapseStackFrames"/>
<menu
id="org.eclipse.jdt.debug.ui.LaunchView.javaSubmenu"
label="%LaunchViewJavaSubmenu.label"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ public class DebugUIMessages extends NLS {
public static String JDIModelPresentation__garbage_collected_object__6;
public static String JDIModelPresentation__obsolete_method_in__1;
public static String JDIModelPresentation__terminated__2;
public static String JDIModelPresentation_collapsed_frames;

public static String JDIModelPresentation_117;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ JDIModelPresentation_modification_72=\ [modification]
JDIModelPresentation_native_method=[native method]
JDIModelPresentation_not_available=not available
JDIModelPresentation_Suspend_VM=[Suspend VM]
JDIModelPresentation_collapsed_frames={0} collapsed frames

###############################################################################
# Thread label keys are built programmatically
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ public interface IJDIPreferencesConstants {
*/
public static final String PREF_STEP_THRU_FILTERS = IJavaDebugUIConstants.PLUGIN_ID + ".step_thru_filters"; //$NON-NLS-1$

public static final String PREF_COLLAPSE_STACK_FRAMES = IJavaDebugUIConstants.PLUGIN_ID + ".collapse_stack_frames"; //$NON-NLS-1$

/**
* List of active step filters. A String containing a comma
* separated list of fully qualified type names/patterns.
* List of active step filters. A String containing a comma separated list of fully qualified type names/patterns.
*/
public static final String PREF_ACTIVE_FILTERS_LIST = IJavaDebugUIConstants.PLUGIN_ID + ".active_filters"; //$NON-NLS-1$

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2022 IBM Corporation and others.
* Copyright (c) 2000, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -57,6 +57,7 @@
import org.eclipse.jdt.debug.core.IJavaVariable;
import org.eclipse.jdt.debug.core.JDIDebugModel;
import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
import org.eclipse.jdt.internal.debug.core.model.GroupedStackFrame;
import org.eclipse.jdt.internal.debug.ui.breakpoints.ExceptionInspector;
import org.eclipse.jdt.internal.debug.ui.breakpoints.JavaBreakpointTypeAdapterFactory;
import org.eclipse.jdt.internal.debug.ui.classpath.ClasspathEntryAdapterFactory;
Expand Down Expand Up @@ -382,6 +383,7 @@ public void start(BundleContext context) throws Exception {
manager.registerAdapters(monitorFactory, JavaOwningThread.class);
manager.registerAdapters(monitorFactory, JavaWaitingThread.class);
manager.registerAdapters(monitorFactory, IJavaStackFrame.class);
manager.registerAdapters(monitorFactory, GroupedStackFrame.class);

IAdapterFactory targetFactory = new TargetAdapterFactory();
manager.registerAdapters(targetFactory, IJavaDebugTarget.class);
Expand All @@ -391,6 +393,7 @@ public void start(BundleContext context) throws Exception {

IAdapterFactory showInFactory = new JavaDebugShowInAdapterFactory();
manager.registerAdapters(showInFactory, IJavaStackFrame.class);
manager.registerAdapters(showInFactory, GroupedStackFrame.class);

IAdapterFactory columnFactory = new ColumnPresentationAdapterFactory();
manager.registerAdapters(columnFactory, IJavaVariable.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2020 IBM Corporation and others.
* Copyright (c) 2004, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -46,6 +46,8 @@ public void initializeDefaultPreferences() {
store.setDefault(IJDIPreferencesConstants.PREF_INACTIVE_FILTERS_LIST, "com.ibm.*,com.sun.*,java.*,javax.*,jdk.*,jrockit.*,org.omg.*,sun.*,sunw.*"); //$NON-NLS-1$
store.setDefault(IJDIPreferencesConstants.PREF_STEP_THRU_FILTERS, true);

store.setDefault(IJDIPreferencesConstants.PREF_COLLAPSE_STACK_FRAMES, true);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try using org.eclipse.jface.util.Util.ZERO_LENGTH_STRING for empty string declarations, so you can avoid NON-NLS comments

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I didn't know about this class!

store.setDefault(IDebugUIConstants.ID_VARIABLE_VIEW + "." + IJDIPreferencesConstants.PREF_SHOW_CONSTANTS, false); //$NON-NLS-1$
store.setDefault(IDebugUIConstants.ID_EXPRESSION_VIEW + "." + IJDIPreferencesConstants.PREF_SHOW_CONSTANTS, false); //$NON-NLS-1$
store.setDefault(IDebugUIConstants.ID_VARIABLE_VIEW + "." + IJDIPreferencesConstants.PREF_SHOW_STATIC_VARIABLES, false); //$NON-NLS-1$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import org.eclipse.jdt.internal.debug.core.breakpoints.JavaExceptionBreakpoint;
import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIAllInstancesValue;
import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIReturnValueVariable;
import org.eclipse.jdt.internal.debug.core.model.GroupedStackFrame;
import org.eclipse.jdt.internal.debug.core.model.JDIDebugModelMessages;
import org.eclipse.jdt.internal.debug.core.model.JDIReferenceListEntryVariable;
import org.eclipse.jdt.internal.debug.core.model.JDIReferenceListValue;
Expand Down Expand Up @@ -151,6 +152,8 @@ public class JDIModelPresentation extends LabelProvider implements IDebugModelPr

private JavaElementLabelProvider fJavaLabelProvider;

private StackFramePresentationProvider fStackFrameProvider;

public JDIModelPresentation() {
super();
}
Expand All @@ -165,6 +168,9 @@ public void dispose() {
fJavaLabelProvider.dispose();
}
fAttributes.clear();
if (fStackFrameProvider != null) {
fStackFrameProvider.close();
}
}

/**
Expand Down Expand Up @@ -244,6 +250,8 @@ public String getText(Object item) {
return getJavaOwningTreadText((JavaOwningThread)item);
} else if (item instanceof JavaWaitingThread) {
return getJavaWaitingTreadText((JavaWaitingThread)item);
} else if (item instanceof GroupedStackFrame groupping) {
return getFormattedString(DebugUIMessages.JDIModelPresentation_collapsed_frames, String.valueOf(groupping.getFrameCount()));
} else if (item instanceof NoMonitorInformationElement) {
return DebugUIMessages.JDIModelPresentation_5;
} else {
Expand Down Expand Up @@ -737,7 +745,10 @@ public Image getImage(Object item) {
return DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_THREAD_RUNNING);
}
}
if (item instanceof IJavaStackFrame || item instanceof IJavaThread || item instanceof IJavaDebugTarget) {
if (item instanceof IJavaStackFrame) {
return getStackFrameImage((IJavaStackFrame) item);
}
if (item instanceof IJavaThread || item instanceof IJavaDebugTarget) {
return getDebugElementImage(item);
}
if (item instanceof IJavaValue) {
Expand Down Expand Up @@ -937,6 +948,30 @@ protected Image getDebugElementImage(Object element) {
return getDebugImage(image, flags);
}

/**
* Returns the image associated with the given {@link IJavaStackFrame}, decorated with overlays, if the stack frame is out of sync
* ({@link IJavaStackFrame#isOutOfSynch()} or synchronized ({@link IJavaStackFrame#isSynchronized()}). The base image is acquired from the
* {@link StackFramePresentationProvider}.
*/
private Image getStackFrameImage(IJavaStackFrame stackFrame) {
var image = getStackFrameProvider().getStackFrameImage(stackFrame);
gzsombor marked this conversation as resolved.
Show resolved Hide resolved
if (image == null) {
image = DebugUITools.getDefaultImageDescriptor(stackFrame);
}

int flags = 0;
try {
if (stackFrame.isOutOfSynch()) {
flags = JDIImageDescriptor.IS_OUT_OF_SYNCH;
} else if (!stackFrame.isObsolete() && stackFrame.isSynchronized()) {
flags = JDIImageDescriptor.SYNCHRONIZED;
}
} catch (DebugException e) {
// no need to log errors - elements may no longer exist by the time we render them
}

return getDebugImage(image, flags);
}
/**
* Returns the image associated with the given element or <code>null</code>
* if none is defined.
Expand All @@ -959,21 +994,11 @@ protected Image getExpressionImage(Object expression) {
}

/**
* Returns the adornment flags for the given element.
* These flags are used to render appropriate overlay
* icons for the element.
* Returns the adornment flags for the given element. These flags are used to render appropriate overlay icons for the element. It only supports
* {@link IJavaThread} and {@link IJavaDebugTarget}, for other types it always returns 0.
*/
private int computeJDIAdornmentFlags(Object element) {
try {
if (element instanceof IJavaStackFrame) {
IJavaStackFrame javaStackFrame = ((IJavaStackFrame)element);
if (javaStackFrame.isOutOfSynch()) {
return JDIImageDescriptor.IS_OUT_OF_SYNCH;
}
if (!javaStackFrame.isObsolete() && javaStackFrame.isSynchronized()) {
return JDIImageDescriptor.SYNCHRONIZED;
}
}
if (element instanceof IJavaThread) {
int flag= 0;
IJavaThread javaThread = ((IJavaThread)element);
Expand Down Expand Up @@ -2049,6 +2074,16 @@ protected JavaElementLabelProvider getJavaLabelProvider() {
return fJavaLabelProvider;
}

/**
* @return a {@link StackFramePresentationProvider} which responsible to classify stack frames into categories and could provide category specific
* visual representations.
*/
private StackFramePresentationProvider getStackFrameProvider() {
if (fStackFrameProvider == null) {
gzsombor marked this conversation as resolved.
Show resolved Hide resolved
fStackFrameProvider = new StackFramePresentationProvider();
}
return fStackFrameProvider;
}
/**
* Returns whether the given field variable has the same name as any variables
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*******************************************************************************
* Copyright (c) 2021, 2025 Zsombor Gegesy and others.
*
gzsombor marked this conversation as resolved.
Show resolved Hide resolved
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Zsombor Gegesy - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.debug.ui;

import org.eclipse.jdt.debug.core.IJavaStackFrame;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;

/**
* Provides foreground and background colors for stack frames in a debug view. After usage, it needs to be closed, so it could unregister itself from
* preference storage.
*
*/
public final class StackFramePresentationProvider implements IPropertyChangeListener {

private final IPreferenceStore store;
private boolean collapseStackFrames;

public StackFramePresentationProvider(IPreferenceStore store) {
this.store = store;
store.addPropertyChangeListener(this);
collapseStackFrames = store.getBoolean(IJDIPreferencesConstants.PREF_COLLAPSE_STACK_FRAMES);
}

public StackFramePresentationProvider() {
this(JDIDebugUIPlugin.getDefault().getPreferenceStore());
}

/**
* @return the category specific image for the stack frame, or null, if there is no one defined.
*/
public ImageDescriptor getStackFrameImage(IJavaStackFrame frame) {
if (collapseStackFrames) {
var category = frame.getCategory();
if (category != null) {
switch (category) {
case LIBRARY:
case SYNTHETIC:
case PLATFORM:
return JavaPluginImages.DESC_OBJS_JAR;
default:
break;
}
}
}
return null;
}

/**
* Unsubscribes to not receive notifications from the {@link IPreferenceStore}.
*/
public void close() {
store.removePropertyChangeListener(this);
}

@Override
public void propertyChange(PropertyChangeEvent event) {
String prop = event.getProperty();
if (IJDIPreferencesConstants.PREF_COLLAPSE_STACK_FRAMES.equals(prop)) {
collapseStackFrames = (Boolean) event.getNewValue();
}
}

/**
* @return if stack frames should be collapsed.
*/
public boolean isCollapseStackFrames() {
gzsombor marked this conversation as resolved.
Show resolved Hide resolved
return collapseStackFrames;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2022, 2025 Zsombor Gegesy and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Zsombor Gegesy - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.debug.ui.actions;

import org.eclipse.jdt.internal.debug.ui.IJDIPreferencesConstants;

/**
* Enable/disable collapsing of the non-relevant stack frames in debug views.
*
*/
public class CollapseStackFramesAction extends ToggleBooleanPreferenceAction {

@Override
protected String getPreferenceKey() {
return IJDIPreferencesConstants.PREF_COLLAPSE_STACK_FRAMES;
}

@Override
protected String getCompositeKey() {
return getPreferenceKey();
}

}
Loading
Loading