/******************************************************************************* * Copyright (c) 2000, 2012 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.debug.ui; import java.util.Iterator; import java.util.Map; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.debug.core.IJavaBreakpoint; import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint; import org.eclipse.jdt.debug.core.IJavaWatchpoint; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.IVerticalRulerInfo; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.ui.texteditor.SimpleMarkerAnnotation; /** * Utility class for Java breakpoints */ public class BreakpointUtils { /** * Marker attribute storing the handle id of the * Java element associated with a Java breakpoint */ private static final String HANDLE_ID = JDIDebugUIPlugin.getUniqueIdentifier() + ".JAVA_ELEMENT_HANDLE_ID"; //$NON-NLS-1$ /** * Marker attribute used to denote a run to line breakpoint */ private static final String RUN_TO_LINE = JDIDebugUIPlugin.getUniqueIdentifier() + ".run_to_line"; //$NON-NLS-1$ /** * Marker attribute used to denote the start of the region within a Java * member that the breakpoint is located within. */ private static final String MEMBER_START = JDIDebugUIPlugin.getUniqueIdentifier() + ".member_start"; //$NON-NLS-1$ /** * Marker attribute used to denote the end of the region within a Java * member that the breakpoint is located within. */ private static final String MEMBER_END = JDIDebugUIPlugin.getUniqueIdentifier() + ".member_end"; //$NON-NLS-1$ /** * Returns the resource on which a breakpoint marker should * be created for the given member. The resource returned is the * associated file, or workspace root in the case of a binary in * an external archive. * * @param member member in which a breakpoint is being created * @return resource the resource on which a breakpoint marker * should be created */ public static IResource getBreakpointResource(IMember member) { ICompilationUnit cu = member.getCompilationUnit(); if (cu != null && cu.isWorkingCopy()) { member = (IMember)member.getPrimaryElement(); } IResource res = member.getResource(); if (res == null) { res = ResourcesPlugin.getWorkspace().getRoot(); } else if(!res.getProject().exists()) { res = ResourcesPlugin.getWorkspace().getRoot(); } return res; } /** * Returns the type that the given Java breakpoint refers to * * @param breakpoint Java breakpoint * @return the type the breakpoint is associated with */ public static IType getType(IJavaBreakpoint breakpoint) { String handle = breakpoint.getMarker().getAttribute(HANDLE_ID, null); if (handle != null) { IJavaElement je = JavaCore.create(handle); if (je != null) { if (je instanceof IType) { return (IType)je; } if (je instanceof IMember) { return ((IMember)je).getDeclaringType(); } } } return null; } /** * Returns the member associated with the line number of * the given breakpoint. * * @param breakpoint Java line breakpoint * @return member at the given line number in the type * associated with the breakpoint * @exception CoreException if an exception occurs accessing * the breakpoint */ public static IMember getMember(IJavaLineBreakpoint breakpoint) throws CoreException { if (breakpoint instanceof IJavaMethodBreakpoint) { return getMethod((IJavaMethodBreakpoint)breakpoint); } if (breakpoint instanceof IJavaWatchpoint) { return getField((IJavaWatchpoint)breakpoint); } int start = breakpoint.getCharStart(); int end = breakpoint.getCharEnd(); IType type = getType(breakpoint); if (start == -1 && end == -1) { start= breakpoint.getMarker().getAttribute(MEMBER_START, -1); end= breakpoint.getMarker().getAttribute(MEMBER_END, -1); } IMember member = null; if ((type != null && type.exists()) && (end >= start) && (start >= 0)) { member= binSearch(type, start, end); } if (member == null) { member= type; } return member; } /** * Searches the given source range of the container for a member that is * not the same as the given type. * @param type the {@link IType} * @param start the starting position * @param end the ending position * @return the {@link IMember} from the given start-end range * @throws JavaModelException if there is a problem with the backing Java model */ protected static IMember binSearch(IType type, int start, int end) throws JavaModelException { IJavaElement je = getElementAt(type, start); if (je != null && !je.equals(type)) { return asMember(je); } if (end > start) { je = getElementAt(type, end); if (je != null && !je.equals(type)) { return asMember(je); } int mid = ((end - start) / 2) + start; if (mid > start) { je = binSearch(type, start + 1, mid); if (je == null) { je = binSearch(type, mid + 1, end - 1); } return asMember(je); } } return null; } /** * Returns the given Java element if it is an * <code>IMember</code>, otherwise <code>null</code>. * * @param element Java element * @return the given element if it is a type member, * otherwise <code>null</code> */ private static IMember asMember(IJavaElement element) { if (element instanceof IMember) { return (IMember)element; } return null; } /** * Returns the element at the given position in the given type * @param type the {@link IType} * @param pos the position * @return the {@link IJavaElement} at the given position * @throws JavaModelException if there is a problem with the backing Java model */ protected static IJavaElement getElementAt(IType type, int pos) throws JavaModelException { if (type.isBinary()) { return type.getClassFile().getElementAt(pos); } return type.getCompilationUnit().getElementAt(pos); } /** * Adds attributes to the given attribute map:<ul> * <li>Java element handle id</li> * <li>Attributes defined by <code>JavaCore</code></li> * </ul> * * @param attributes the attribute map to use * @param element the Java element associated with the breakpoint */ public static void addJavaBreakpointAttributes(Map<String, Object> attributes, IJavaElement element) { String handleId = element.getHandleIdentifier(); attributes.put(HANDLE_ID, handleId); JavaCore.addJavaElementMarkerAttributes(attributes, element); } /** * Adds attributes to the given attribute map:<ul> * <li>Java element handle id</li> * <li>Member start position</li> * <li>Member end position</li> * <li>Attributes defined by <code>JavaCore</code></li> * </ul> * * @param attributes the attribute map to use * @param element the Java element associated with the breakpoint * @param memberStart the start position of the Java member that the breakpoint is positioned within * @param memberEnd the end position of the Java member that the breakpoint is positioned within */ public static void addJavaBreakpointAttributesWithMemberDetails(Map<String, Object> attributes, IJavaElement element, int memberStart, int memberEnd) { addJavaBreakpointAttributes(attributes, element); attributes.put(MEMBER_START, new Integer(memberStart)); attributes.put(MEMBER_END, new Integer(memberEnd)); } /** * Adds attributes to the given attribute map to make the * breakpoint a run-to-line breakpoint:<ul> * <li>PERSISTED = false</li> * <li>RUN_TO_LINE = true</li> * </ul> * * @param attributes the attribute map to use */ public static void addRunToLineAttributes(Map<String, Object> attributes) { attributes.put(IBreakpoint.PERSISTED, Boolean.FALSE); attributes.put(RUN_TO_LINE, Boolean.TRUE); } /** * Returns the method associated with the method entry * breakpoint. * * @param breakpoint Java method entry breakpoint * @return method */ public static IMethod getMethod(IJavaMethodBreakpoint breakpoint) { String handle = breakpoint.getMarker().getAttribute(HANDLE_ID, null); if (handle != null) { IJavaElement je = JavaCore.create(handle); if (je != null) { if (je instanceof IMethod) { return (IMethod)je; } } } return null; } /** * Returns the field associated with the watchpoint. * * @param breakpoint Java watchpoint * @return field */ public static IField getField(IJavaWatchpoint breakpoint) { String handle = breakpoint.getMarker().getAttribute(HANDLE_ID, null); if (handle != null) { IJavaElement je = JavaCore.create(handle); if (je != null) { if (je instanceof IField) { return (IField)je; } } } return null; } /** * Returns whether the given breakpoint is a run to line * breakpoint * * @param breakpoint line breakpoint * @return whether the given breakpoint is a run to line * breakpoint */ public static boolean isRunToLineBreakpoint(IJavaLineBreakpoint breakpoint) { return breakpoint.getMarker().getAttribute(RUN_TO_LINE, false); } /** * Returns whether the given breakpoint is a compilation * problem breakpoint or uncaught exception breakpoint * * @param breakpoint breakpoint * @return whether the given breakpoint is a compilation error breakpoint or * uncaught exception breakpoint */ public static boolean isProblemBreakpoint(IBreakpoint breakpoint) { return breakpoint == JavaDebugOptionsManager.getDefault().getSuspendOnCompilationErrorBreakpoint() || breakpoint == JavaDebugOptionsManager.getDefault().getSuspendOnUncaughtExceptionBreakpoint(); } /** * Resolves the {@link IBreakpoint} from the given editor and ruler information. Returns <code>null</code> * if no breakpoint exists or the operation fails. * * @param editor the editor * @param info the current ruler information * @return the {@link IBreakpoint} from the current editor position or <code>null</code> * @since 3.8 */ public static IBreakpoint getBreakpointFromEditor(ITextEditor editor, IVerticalRulerInfo info) { IAnnotationModel annotationModel = editor.getDocumentProvider().getAnnotationModel(editor.getEditorInput()); IDocument document = editor.getDocumentProvider().getDocument(editor.getEditorInput()); if (annotationModel != null) { Iterator<Annotation> iterator = annotationModel.getAnnotationIterator(); while (iterator.hasNext()) { Object object = iterator.next(); if (object instanceof SimpleMarkerAnnotation) { SimpleMarkerAnnotation markerAnnotation = (SimpleMarkerAnnotation) object; IMarker marker = markerAnnotation.getMarker(); try { if (marker.isSubtypeOf(IBreakpoint.BREAKPOINT_MARKER)) { Position position = annotationModel.getPosition(markerAnnotation); int line = document.getLineOfOffset(position.getOffset()); if (line == info.getLineOfLastMouseButtonActivity()) { IBreakpoint breakpoint = DebugPlugin.getDefault().getBreakpointManager().getBreakpoint(marker); if (breakpoint != null) { return breakpoint; } } } } catch (CoreException e) { } catch (BadLocationException e) { } } } } return null; } }