Java tutorial
/******************************************************************************* * Copyright (c) 2000, 2014 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 * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ package org.eclipse.objectteams.otdt.debug.ui.internal.actions; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IBreakpointManager; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension2; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IPackageDeclaration; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeParameter; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.core.SourceRange; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.NodeFinder; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.debug.core.IJavaBreakpoint; import org.eclipse.jdt.debug.core.IJavaClassPrepareBreakpoint; import org.eclipse.jdt.debug.core.IJavaFieldVariable; import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint; import org.eclipse.jdt.debug.core.IJavaType; import org.eclipse.jdt.debug.core.IJavaWatchpoint; import org.eclipse.jdt.debug.core.JDIDebugModel; import org.eclipse.jdt.internal.debug.core.JavaDebugUtils; import org.eclipse.jdt.internal.debug.core.breakpoints.ValidBreakpointLocationLocator; import org.eclipse.jdt.internal.debug.ui.BreakpointUtils; import org.eclipse.jdt.internal.debug.ui.DebugWorkingCopyManager; import org.eclipse.jdt.internal.debug.ui.IJDIPreferencesConstants; import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; import org.eclipse.jdt.internal.debug.ui.actions.ActionDelegateHelper; import org.eclipse.jdt.internal.debug.ui.actions.ActionMessages; import org.eclipse.jdt.ui.IWorkingCopyManager; import org.eclipse.jdt.ui.JavaUI; import org.eclipse.jdt.ui.SharedASTProvider; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialogWithToggle; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.source.IVerticalRulerInfo; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.objectteams.otdt.core.IOTJavaElement; import org.eclipse.objectteams.otdt.core.IOTType; import org.eclipse.objectteams.otdt.core.OTModelManager; import org.eclipse.objectteams.otdt.core.compiler.IOTConstants; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.PreferencesUtil; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.IEditorStatusLine; import org.eclipse.ui.texteditor.ITextEditor; /** * @author ike * Toggles a line breakpoint in a OTJava editor. * * @since 3.0 */ //{OT_COPY_PASTE: class copied from org.eclipse.jdt.internal.debug.ui.actions.ToggleBreakpointAdapter // to instantiate OTBreakpointLocationVerifierJob in favor of BreakpointLocationVerifierJob // and to access a protected method of ValidBreakpointLocationLocator @SuppressWarnings("restriction") // copy&paste adaptation needs access to internals public class OTToggleBreakpointAdapter implements IToggleBreakpointsTargetExtension2 { private static final String EMPTY_STRING = ""; //$NON-NLS-1$ /** * Constructor */ public OTToggleBreakpointAdapter() { // initialize helper in UI thread ActionDelegateHelper.getDefault(); } /** * Convenience method for printing messages to the status line * @param message the message to be displayed * @param part the currently active workbench part */ protected void report(final String message, final IWorkbenchPart part) { JDIDebugUIPlugin.getStandardDisplay().asyncExec(new Runnable() { public void run() { IEditorStatusLine statusLine = (IEditorStatusLine) part.getAdapter(IEditorStatusLine.class); if (statusLine != null) { if (message != null) { statusLine.setMessage(true, message, null); } else { statusLine.setMessage(true, null, null); } } } }); } /** * Returns the <code>IType</code> for the given selection * @param selection the current text selection * @return the <code>IType</code> for the text selection or <code>null</code> */ protected IType getType(ITextSelection selection) { IMember member = ActionDelegateHelper.getDefault().getCurrentMember(selection); IType type = null; if (member instanceof IType) { type = (IType) member; } else if (member != null) { type = member.getDeclaringType(); } // bug 52385: we don't want local and anonymous types from compilation // unit, // we are getting 'not-always-correct' names for them. try { while (type != null && !type.isBinary() && type.isLocal()) { type = type.getDeclaringType(); } } catch (JavaModelException e) { JDIDebugUIPlugin.log(e); } return type; } /** * Returns the IType associated with the <code>IJavaElement</code> passed in * @param element the <code>IJavaElement</code> to get the type from * @return the corresponding <code>IType</code> for the <code>IJavaElement</code>, or <code>null</code> if there is not one. * @since 3.3 */ protected IType getType(IJavaElement element) { switch (element.getElementType()) { case IJavaElement.FIELD: { return ((IField) element).getDeclaringType(); } case IJavaElement.METHOD: { return ((IMethod) element).getDeclaringType(); } case IJavaElement.TYPE: { return (IType) element; } default: { return null; } } } /* (non-Javadoc) * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleLineBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection) */ public void toggleLineBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException { toggleLineBreakpoints(part, selection, false, null); } /** * Toggles a line breakpoint. * @param part the currently active workbench part * @param selection the current selection * @param bestMatch if we should make a best match or not */ public void toggleLineBreakpoints(final IWorkbenchPart part, final ISelection selection, final boolean bestMatch, final ValidBreakpointLocationLocator locator) { Job job = new Job("Toggle Line Breakpoint") { //$NON-NLS-1$ @Override protected IStatus run(IProgressMonitor monitor) { return doLineBreakpointToggle(selection, part, locator, bestMatch, monitor); } }; job.setPriority(Job.INTERACTIVE); job.setSystem(true); job.schedule(); } /* * (non-Javadoc) * * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#canToggleLineBreakpoints(IWorkbenchPart, * ISelection) */ public boolean canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection) { if (isRemote(part, selection)) { return false; } return selection instanceof ITextSelection; } /* * (non-Javadoc) * * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleMethodBreakpoints(org.eclipse.ui.IWorkbenchPart, * org.eclipse.jface.viewers.ISelection) */ public void toggleMethodBreakpoints(final IWorkbenchPart part, final ISelection finalSelection) { Job job = new Job("Toggle Method Breakpoints") { //$NON-NLS-1$ @Override protected IStatus run(IProgressMonitor monitor) { if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } try { report(null, part); ISelection selection = finalSelection; if (!(selection instanceof IStructuredSelection)) { selection = translateToMembers(part, selection); } boolean isInterface = isInterface(selection, part); if (selection instanceof IStructuredSelection) { IMethod[] members = getMethods((IStructuredSelection) selection, isInterface); if (members.length == 0) { if (isInterface) report(ActionMessages.ToggleBreakpointAdapter_6, part); else report(ActionMessages.ToggleBreakpointAdapter_9, part); return Status.OK_STATUS; } IJavaBreakpoint breakpoint = null; ISourceRange range = null; Map<String, Object> attributes = null; IType type = null; String signature = null; String mname = null; for (int i = 0, length = members.length; i < length; i++) { breakpoint = getMethodBreakpoint(members[i]); if (breakpoint == null) { int start = -1; int end = -1; range = members[i].getNameRange(); if (range != null) { start = range.getOffset(); end = start + range.getLength(); } attributes = new HashMap<String, Object>(10); BreakpointUtils.addJavaBreakpointAttributes(attributes, members[i]); type = members[i].getDeclaringType(); signature = members[i].getSignature(); mname = members[i].getElementName(); if (members[i].isConstructor()) { mname = "<init>"; //$NON-NLS-1$ if (type.isEnum()) { signature = "(Ljava.lang.String;I" + signature.substring(1); //$NON-NLS-1$ } } if (!type.isBinary()) { signature = resolveMethodSignature(members[i]); if (signature == null) { report(ActionMessages.ManageMethodBreakpointActionDelegate_methodNonAvailable, part); return Status.OK_STATUS; } } JDIDebugModel.createMethodBreakpoint( BreakpointUtils.getBreakpointResource(members[i]), getQualifiedName(type), mname, signature, true, false, false, -1, start, end, 0, true, attributes); } else { deleteBreakpoint(breakpoint, part, monitor); } } } else { report(ActionMessages.ToggleBreakpointAdapter_4, part); return Status.OK_STATUS; } } catch (CoreException e) { return e.getStatus(); } return Status.OK_STATUS; } }; job.setPriority(Job.INTERACTIVE); job.setSystem(true); job.schedule(); } /** * Performs the actual toggling of the line breakpoint * @param selection the current selection (from the editor or view) * @param part the active part * @param locator the locator, may be <code>null</code> * @param bestMatch if we should consider the best match rather than an exact match * @param monitor progress reporting * @return the status of the toggle * @since 3.8 */ IStatus doLineBreakpointToggle(ISelection selection, IWorkbenchPart part, ValidBreakpointLocationLocator locator, boolean bestMatch, IProgressMonitor monitor) { ITextEditor editor = getTextEditor(part); if (editor != null && selection instanceof ITextSelection) { if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } ITextSelection tsel = (ITextSelection) selection; if (tsel.getStartLine() < 0) { return Status.CANCEL_STATUS; } try { report(null, part); ISelection sel = selection; if (!(selection instanceof IStructuredSelection)) { sel = translateToMembers(part, selection); } if (sel instanceof IStructuredSelection) { IMember member = (IMember) ((IStructuredSelection) sel).getFirstElement(); IType type = null; //{ObjectTeams: also handle IOTJavaElement.{ROLE,TEAM}: /* orig: if(member.getElementType() == IJavaElement.TYPE) { :giro */ if (member instanceof IType) { // SH} type = (IType) member; } else { type = member.getDeclaringType(); } String tname = null; IJavaProject project = type.getJavaProject(); if (locator == null || (project != null && !project.isOnClasspath(type))) { tname = createQualifiedTypeName(type); } else { tname = locator.getFullyQualifiedTypeName(); } IResource resource = BreakpointUtils.getBreakpointResource(type); int lnumber = locator == null ? tsel.getStartLine() + 1 : locator.getLineLocation(); IJavaLineBreakpoint existingBreakpoint = JDIDebugModel.lineBreakpointExists(resource, tname, lnumber); if (existingBreakpoint != null) { deleteBreakpoint(existingBreakpoint, editor, monitor); return Status.OK_STATUS; } Map<String, Object> attributes = new HashMap<String, Object>(10); IDocumentProvider documentProvider = editor.getDocumentProvider(); if (documentProvider == null) { return Status.CANCEL_STATUS; } IDocument document = documentProvider.getDocument(editor.getEditorInput()); int charstart = -1, charend = -1; try { IRegion line = document.getLineInformation(lnumber - 1); charstart = line.getOffset(); charend = charstart + line.getLength(); } catch (BadLocationException ble) { JDIDebugUIPlugin.log(ble); } BreakpointUtils.addJavaBreakpointAttributes(attributes, type); IJavaLineBreakpoint breakpoint = JDIDebugModel.createLineBreakpoint(resource, tname, lnumber, charstart, charend, 0, true, attributes); if (locator == null) { //{ObjectTeams: replace BreakpointLocationVerifierJob with own OTBreakpointLocationVerifierJob /* orig: new BreakpointLocationVerifierJob(document, parseCompilationUnit(type.getTypeRoot()), breakpoint, lnumber, tname, type, editor, bestMatch).schedule(); :giro */ new OTBreakpointLocationVerifierJob(document, breakpoint, lnumber, bestMatch, tname, type, resource, editor).schedule(); //ike} } } else { report(ActionMessages.ToggleBreakpointAdapter_3, part); return Status.OK_STATUS; } } catch (CoreException ce) { return ce.getStatus(); } } return Status.OK_STATUS; } /** * Toggles a class load breakpoint * @param part the part * @param selection the current selection * @since 3.3 */ public void toggleClassBreakpoints(final IWorkbenchPart part, final ISelection selection) { Job job = new Job("Toggle Class Load Breakpoints") { //$NON-NLS-1$ @Override protected IStatus run(IProgressMonitor monitor) { if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } try { report(null, part); ISelection sel = selection; if (!(selection instanceof IStructuredSelection)) { sel = translateToMembers(part, selection); } if (isInterface(sel, part)) { report(ActionMessages.ToggleBreakpointAdapter_1, part); return Status.OK_STATUS; } if (sel instanceof IStructuredSelection) { IMember member = (IMember) ((IStructuredSelection) sel).getFirstElement(); IType type = (IType) member; IJavaBreakpoint existing = getClassLoadBreakpoint(type); if (existing != null) { deleteBreakpoint(existing, part, monitor); return Status.OK_STATUS; } HashMap<String, Object> map = new HashMap<String, Object>(10); BreakpointUtils.addJavaBreakpointAttributes(map, type); ISourceRange range = type.getNameRange(); int start = -1; int end = -1; if (range != null) { start = range.getOffset(); end = start + range.getLength(); } JDIDebugModel.createClassPrepareBreakpoint(BreakpointUtils.getBreakpointResource(member), getQualifiedName(type), IJavaClassPrepareBreakpoint.TYPE_CLASS, start, end, true, map); } else { report(ActionMessages.ToggleBreakpointAdapter_0, part); return Status.OK_STATUS; } } catch (CoreException e) { return e.getStatus(); } return Status.OK_STATUS; } }; job.setPriority(Job.INTERACTIVE); job.setSystem(true); job.schedule(); } /** * Returns the class load breakpoint for the specified type or null if none found * @param type the type to search for a class load breakpoint for * @return the existing class load breakpoint, or null if none * @throws CoreException * @since 3.3 */ protected IJavaBreakpoint getClassLoadBreakpoint(IType type) throws CoreException { IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager() .getBreakpoints(JDIDebugModel.getPluginIdentifier()); for (int i = 0; i < breakpoints.length; i++) { IJavaBreakpoint breakpoint = (IJavaBreakpoint) breakpoints[i]; if (breakpoint instanceof IJavaClassPrepareBreakpoint && getQualifiedName(type).equals(breakpoint.getTypeName())) { return breakpoint; } } return null; } /** * Returns the binary name for the {@link IType} derived from its {@link ITypeBinding}. * <br><br> * If the {@link ITypeBinding} cannot be derived this method falls back to calling * {@link #createQualifiedTypeName(IType)} to try and compose the type name. * @param type * @return the binary name for the given {@link IType} * @since 3.6 */ String getQualifiedName(IType type) throws JavaModelException { IJavaProject project = type.getJavaProject(); if (project != null && project.isOnClasspath(type) && needsBindings(type)) { CompilationUnit cuNode = parseCompilationUnit(type.getTypeRoot()); ISourceRange nameRange = type.getNameRange(); if (SourceRange.isAvailable(nameRange)) { ASTNode node = NodeFinder.perform(cuNode, nameRange); if (node instanceof SimpleName) { IBinding binding; if (node.getLocationInParent() == SimpleType.NAME_PROPERTY && node.getParent().getLocationInParent() == ClassInstanceCreation.TYPE_PROPERTY) { binding = ((ClassInstanceCreation) node.getParent().getParent()).resolveTypeBinding(); } else { binding = ((SimpleName) node).resolveBinding(); } if (binding instanceof ITypeBinding) { String name = ((ITypeBinding) binding).getBinaryName(); if (name != null) { return name; } } } } } return createQualifiedTypeName(type); } /** * Checks if the type or any of its enclosing types are local types. * @param type * @return <code>true</code> if the type or a parent type are a local type * @throws JavaModelException * @since 3.6 */ boolean needsBindings(IType type) throws JavaModelException { if (type.isMember()) { if (type.isLocal() && !type.isAnonymous()) { return true; } IJavaElement parent = type.getParent(); IType ptype = null; while (parent != null) { if (parent.getElementType() == IJavaElement.TYPE) { ptype = (IType) parent; if (ptype.isLocal() && !ptype.isAnonymous()) { return true; } } parent = parent.getParent(); } } return false; } /** * Returns the package qualified name, while accounting for the fact that a source file might * not have a project * @param type the type to ensure the package qualified name is created for * @return the package qualified name * @since 3.3 */ //{ObjectTeams: made API for RoFiBreakpointTests (was private non-static): public static String createQualifiedTypeName(IType type) { // SH} String tname = pruneAnonymous(type); try { String packName = null; if (type.isBinary()) { packName = type.getPackageFragment().getElementName(); } else { IPackageDeclaration[] pd = type.getCompilationUnit().getPackageDeclarations(); if (pd.length > 0) { packName = pd[0].getElementName(); } } if (packName != null && !packName.equals(EMPTY_STRING)) { //{ObjectTeams: package of a role must be a team package: if (tname.startsWith(IOTConstants.OT_DELIM)) tname = packName + '$' + tname; else // SH} tname = packName + "." + tname; //$NON-NLS-1$ } } catch (JavaModelException e) { } return tname; } /** * Prunes out all naming occurrences of anonymous inner types, since these types have no names * and cannot be derived visiting an AST (no positive type name matching while visiting ASTs) * @param type * @return the compiled type name from the given {@link IType} with all occurrences of anonymous inner types removed * @since 3.4 */ private static String pruneAnonymous(IType type) { StringBuffer buffer = new StringBuffer(); IJavaElement parent = type; while (parent != null) { if (parent.getElementType() == IJavaElement.TYPE) { IType atype = (IType) parent; try { if (!atype.isAnonymous()) { if (buffer.length() > 0) { buffer.insert(0, '$'); } //{ObjectTeams: use prefixed role type if appropriate: // cf. OTValidBreakpointLocationLocator.computeTypeName() /* orig: buffer.insert(0, atype.getElementName()); :giro */ buffer.insert(0, getSimpleTypeName(atype)); // SH} } } catch (JavaModelException jme) { } } parent = parent.getParent(); } return buffer.toString(); } //{ObjectTeams: new util: /** Make sure each role type is prefixed with __OT__. */ private static String getSimpleTypeName(IType type) { String name = type.getElementName(); if (name.startsWith(IOTConstants.OT_DELIM)) return name; // already prefixed boolean isRole = false; if (type.getElementType() == IOTJavaElement.ROLE) isRole = true; else if (OTModelManager.hasOTElementFor(type)) { IOTType otType = OTModelManager.getOTElement(type); isRole = otType.isRole(); } if (isRole) return IOTConstants.OT_DELIM + name; return name; } // SH} /** * gets the <code>IJavaElement</code> from the editor input * @param input the current editor input * @return the corresponding <code>IJavaElement</code> * @since 3.3 */ private IJavaElement getJavaElement(IEditorInput input) { IJavaElement je = JavaUI.getEditorInputJavaElement(input); if (je != null) { return je; } //try to get from the working copy manager return DebugWorkingCopyManager.getWorkingCopy(input, false); } /* * (non-Javadoc) * * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#canToggleMethodBreakpoints(org.eclipse.ui.IWorkbenchPart, * org.eclipse.jface.viewers.ISelection) */ public boolean canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) { if (isRemote(part, selection)) { return false; } if (selection instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) selection; return getMethods(ss, isInterface(selection, part)).length > 0; } return (selection instanceof ITextSelection) && isMethod((ITextSelection) selection, part); } /** * Returns whether the given part/selection is remote (viewing a repository) * * @param part * @param selection * @return */ protected boolean isRemote(IWorkbenchPart part, ISelection selection) { if (selection instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) selection; Object element = ss.getFirstElement(); if (element instanceof IMember) { IMember member = (IMember) element; return !member.getJavaProject().getProject().exists(); } } ITextEditor editor = getTextEditor(part); if (editor != null) { IEditorInput input = editor.getEditorInput(); Object adapter = Platform.getAdapterManager().getAdapter(input, "org.eclipse.team.core.history.IFileRevision"); //$NON-NLS-1$ return adapter != null; } return false; } /** * Returns the text editor associated with the given part or <code>null</code> * if none. In case of a multi-page editor, this method should be used to retrieve * the correct editor to perform the breakpoint operation on. * * @param part workbench part * @return text editor part or <code>null</code> */ protected ITextEditor getTextEditor(IWorkbenchPart part) { if (part instanceof ITextEditor) { return (ITextEditor) part; } return (ITextEditor) part.getAdapter(ITextEditor.class); } /** * Returns the methods from the selection, or an empty array * @param selection the selection to get the methods from * @return an array of the methods from the selection or an empty array */ protected IMethod[] getMethods(IStructuredSelection selection, boolean isInterace) { if (selection.isEmpty()) { return new IMethod[0]; } List<IMethod> methods = new ArrayList<IMethod>(selection.size()); Iterator<?> iterator = selection.iterator(); while (iterator.hasNext()) { Object thing = iterator.next(); try { if (thing instanceof IMethod) { IMethod method = (IMethod) thing; if (isInterace) { if (Flags.isDefaultMethod(method.getFlags()) || Flags.isStatic(method.getFlags())) methods.add(method); } else if (!Flags.isAbstract(method.getFlags())) { methods.add(method); } } } catch (JavaModelException e) { } } return methods.toArray(new IMethod[methods.size()]); } /** * Returns the methods from the selection, or an empty array * @param selection the selection to get the methods from * @return an array of the methods from the selection or an empty array */ protected IMethod[] getInterfaceMethods(IStructuredSelection selection) { if (selection.isEmpty()) { return new IMethod[0]; } List<IMethod> methods = new ArrayList<IMethod>(selection.size()); Iterator<?> iterator = selection.iterator(); while (iterator.hasNext()) { Object thing = iterator.next(); try { if (thing instanceof IMethod) { IMethod method = (IMethod) thing; if (Flags.isDefaultMethod(method.getFlags())) { methods.add(method); } } } catch (JavaModelException e) { } } return methods.toArray(new IMethod[methods.size()]); } /** * Returns if the text selection is a valid method or not * @param selection the text selection * @param part the associated workbench part * @return true if the selection is a valid method, false otherwise */ private boolean isMethod(ITextSelection selection, IWorkbenchPart part) { ITextEditor editor = getTextEditor(part); if (editor != null) { IJavaElement element = getJavaElement(editor.getEditorInput()); if (element != null) { try { if (element instanceof ICompilationUnit) { element = ((ICompilationUnit) element).getElementAt(selection.getOffset()); } else if (element instanceof IClassFile) { element = ((IClassFile) element).getElementAt(selection.getOffset()); } return element != null && element.getElementType() == IJavaElement.METHOD; } catch (JavaModelException e) { return false; } } } return false; } /** * Returns a list of <code>IField</code> and <code>IJavaFieldVariable</code> in the given selection. * When an <code>IField</code> can be resolved for an <code>IJavaFieldVariable</code>, it is * returned in favour of the variable. * * @param selection * @return list of <code>IField</code> and <code>IJavaFieldVariable</code>, possibly empty * @throws CoreException */ protected List<Object> getFields(IStructuredSelection selection) throws CoreException { if (selection.isEmpty()) { return Collections.EMPTY_LIST; } List<Object> fields = new ArrayList<Object>(selection.size()); Iterator<?> iterator = selection.iterator(); while (iterator.hasNext()) { Object thing = iterator.next(); if (thing instanceof IField) { fields.add(thing); } else if (thing instanceof IJavaFieldVariable) { IField field = getField((IJavaFieldVariable) thing); if (field == null) { fields.add(thing); } else { fields.add(field); } } } return fields; } /** * Returns if the structured selection is itself or is part of an interface * @param selection the current selection * @return true if the selection is part of an interface, false otherwise * @since 3.2 */ private boolean isInterface(ISelection selection, IWorkbenchPart part) { try { ISelection sel = selection; if (!(sel instanceof IStructuredSelection)) { sel = translateToMembers(part, selection); } if (sel instanceof IStructuredSelection) { Object obj = ((IStructuredSelection) sel).getFirstElement(); if (obj instanceof IMember) { IMember member = (IMember) ((IStructuredSelection) sel).getFirstElement(); if (member.getElementType() == IJavaElement.TYPE) { return ((IType) member).isInterface(); } return member.getDeclaringType().isInterface(); } else if (obj instanceof IJavaFieldVariable) { IJavaFieldVariable var = (IJavaFieldVariable) obj; IType type = JavaDebugUtils.resolveType(var.getDeclaringType()); return type != null && type.isInterface(); } } } catch (CoreException e1) { } return false; } /** * Returns if the text selection is a field selection or not * @param selection the text selection * @param part the associated workbench part * @return true if the text selection is a valid field for a watchpoint, false otherwise * @since 3.3 */ private boolean isField(ITextSelection selection, IWorkbenchPart part) { ITextEditor editor = getTextEditor(part); if (editor != null) { IJavaElement element = getJavaElement(editor.getEditorInput()); if (element != null) { try { if (element instanceof ICompilationUnit) { element = ((ICompilationUnit) element).getElementAt(selection.getOffset()); } else if (element instanceof IClassFile) { element = ((IClassFile) element).getElementAt(selection.getOffset()); } return element != null && element.getElementType() == IJavaElement.FIELD; } catch (JavaModelException e) { return false; } } } return false; } /** * Determines if the selection is a field or not * @param selection the current selection * @return true if the selection is a field false otherwise */ private boolean isFields(IStructuredSelection selection) { if (!selection.isEmpty()) { try { Iterator<?> iterator = selection.iterator(); while (iterator.hasNext()) { Object thing = iterator.next(); if (thing instanceof IField) { int flags = ((IField) thing).getFlags(); return !Flags.isFinal(flags) & !(Flags.isFinal(flags) & Flags.isStatic(flags)); } else if (thing instanceof IJavaFieldVariable) { IJavaFieldVariable fv = (IJavaFieldVariable) thing; return !fv.isFinal() & !(fv.isFinal() & fv.isStatic()); } } } catch (JavaModelException e) { return false; } catch (DebugException de) { return false; } } return false; } /* * (non-Javadoc) * * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleWatchpoints(org.eclipse.ui.IWorkbenchPart, * org.eclipse.jface.viewers.ISelection) */ public void toggleWatchpoints(final IWorkbenchPart part, final ISelection finalSelection) { Job job = new Job("Toggle Watchpoints") { //$NON-NLS-1$ @Override protected IStatus run(IProgressMonitor monitor) { if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } try { report(null, part); ISelection selection = finalSelection; if (!(selection instanceof IStructuredSelection)) { selection = translateToMembers(part, finalSelection); } if (isInterface(selection, part)) { report(ActionMessages.ToggleBreakpointAdapter_5, part); return Status.OK_STATUS; } boolean allowed = false; if (selection instanceof IStructuredSelection) { List<Object> fields = getFields((IStructuredSelection) selection); if (fields.isEmpty()) { report(ActionMessages.ToggleBreakpointAdapter_10, part); return Status.OK_STATUS; } Iterator<Object> theFields = fields.iterator(); IField javaField = null; IResource resource = null; String typeName = null; String fieldName = null; Object element = null; Map<String, Object> attributes = null; IJavaBreakpoint breakpoint = null; while (theFields.hasNext()) { element = theFields.next(); if (element instanceof IField) { javaField = (IField) element; IType type = javaField.getDeclaringType(); typeName = getQualifiedName(type); fieldName = javaField.getElementName(); int f = javaField.getFlags(); boolean fin = Flags.isFinal(f); allowed = !(fin) & !(Flags.isStatic(f) & fin); } else if (element instanceof IJavaFieldVariable) { IJavaFieldVariable var = (IJavaFieldVariable) element; typeName = var.getDeclaringType().getName(); fieldName = var.getName(); boolean fin = var.isFinal(); allowed = !(fin) & !(var.isStatic() & fin); } breakpoint = getWatchpoint(typeName, fieldName); if (breakpoint == null) { if (!allowed) { return doLineBreakpointToggle(finalSelection, part, null, true, monitor); } int start = -1; int end = -1; attributes = new HashMap<String, Object>(10); if (javaField == null) { resource = ResourcesPlugin.getWorkspace().getRoot(); } else { IType type = javaField.getDeclaringType(); ISourceRange range = javaField.getNameRange(); if (range != null) { start = range.getOffset(); end = start + range.getLength(); } BreakpointUtils.addJavaBreakpointAttributes(attributes, javaField); resource = BreakpointUtils.getBreakpointResource(type); } JDIDebugModel.createWatchpoint(resource, typeName, fieldName, -1, start, end, 0, true, attributes); } else { deleteBreakpoint(breakpoint, part, monitor); } } } else { report(ActionMessages.ToggleBreakpointAdapter_2, part); return Status.OK_STATUS; } } catch (CoreException e) { return e.getStatus(); } return Status.OK_STATUS; } }; job.setPriority(Job.INTERACTIVE); job.setSystem(true); job.schedule(); } /** * Returns any existing watchpoint for the given field, or <code>null</code> if none. * * @param typeName fully qualified type name on which watchpoint may exist * @param fieldName field name * @return any existing watchpoint for the given field, or <code>null</code> if none * @throws CoreException */ private IJavaWatchpoint getWatchpoint(String typeName, String fieldName) throws CoreException { IBreakpointManager breakpointManager = DebugPlugin.getDefault().getBreakpointManager(); IBreakpoint[] breakpoints = breakpointManager.getBreakpoints(JDIDebugModel.getPluginIdentifier()); for (int i = 0; i < breakpoints.length; i++) { IBreakpoint breakpoint = breakpoints[i]; if (breakpoint instanceof IJavaWatchpoint) { IJavaWatchpoint watchpoint = (IJavaWatchpoint) breakpoint; if (typeName.equals(watchpoint.getTypeName()) && fieldName.equals(watchpoint.getFieldName())) { return watchpoint; } } } return null; } /** * Returns the resolved signature of the given method * @param method method to resolve * @return the resolved method signature or <code>null</code> if none * @throws JavaModelException * @since 3.4 */ public static String resolveMethodSignature(IMethod method) throws JavaModelException { String signature = method.getSignature(); String[] parameterTypes = Signature.getParameterTypes(signature); int length = parameterTypes.length; String[] resolvedParameterTypes = new String[length]; for (int i = 0; i < length; i++) { resolvedParameterTypes[i] = resolveTypeSignature(method, parameterTypes[i]); if (resolvedParameterTypes[i] == null) { return null; } } String resolvedReturnType = resolveTypeSignature(method, Signature.getReturnType(signature)); if (resolvedReturnType == null) { return null; } return Signature.createMethodSignature(resolvedParameterTypes, resolvedReturnType); } /** * Returns the resolved type signature for the given signature in the given * method, or <code>null</code> if unable to resolve. * * @param method method containing the type signature * @param typeSignature the type signature to resolve * @return the resolved type signature * @throws JavaModelException */ private static String resolveTypeSignature(IMethod method, String typeSignature) throws JavaModelException { int count = Signature.getArrayCount(typeSignature); String elementTypeSignature = Signature.getElementType(typeSignature); if (elementTypeSignature.length() == 1) { // no need to resolve primitive types return typeSignature; } String elementTypeName = Signature.toString(elementTypeSignature); IType type = method.getDeclaringType(); String[][] resolvedElementTypeNames = type.resolveType(elementTypeName); if (resolvedElementTypeNames == null || resolvedElementTypeNames.length != 1) { // check if type parameter ITypeParameter typeParameter = method.getTypeParameter(elementTypeName); if (!typeParameter.exists()) { typeParameter = type.getTypeParameter(elementTypeName); } if (typeParameter.exists()) { String[] bounds = typeParameter.getBounds(); if (bounds.length == 0) { return "Ljava/lang/Object;"; //$NON-NLS-1$ } String bound = Signature.createTypeSignature(bounds[0], false); return Signature.createArraySignature(resolveTypeSignature(method, bound), count); } // the type name cannot be resolved return null; } String[] types = resolvedElementTypeNames[0]; types[1] = types[1].replace('.', '$'); String resolvedElementTypeName = Signature.toQualifiedName(types); String resolvedElementTypeSignature = EMPTY_STRING; if (types[0].equals(EMPTY_STRING)) { resolvedElementTypeName = resolvedElementTypeName.substring(1); resolvedElementTypeSignature = Signature.createTypeSignature(resolvedElementTypeName, true); } else { resolvedElementTypeSignature = Signature.createTypeSignature(resolvedElementTypeName, true).replace('.', '/'); } return Signature.createArraySignature(resolvedElementTypeSignature, count); } /** * Returns the resource associated with the specified editor part * @param editor the currently active editor part * @return the corresponding <code>IResource</code> from the editor part */ protected static IResource getResource(IEditorPart editor) { IEditorInput editorInput = editor.getEditorInput(); IResource resource = (IResource) editorInput.getAdapter(IFile.class); if (resource == null) { resource = ResourcesPlugin.getWorkspace().getRoot(); } return resource; } /** * Returns a handle to the specified method or <code>null</code> if none. * * @param editorPart * the editor containing the method * @param typeName * @param methodName * @param signature * @return handle or <code>null</code> */ protected IMethod getMethodHandle(IEditorPart editorPart, String typeName, String methodName, String signature) throws CoreException { IJavaElement element = (IJavaElement) editorPart.getEditorInput().getAdapter(IJavaElement.class); IType type = null; if (element instanceof ICompilationUnit) { IType[] types = ((ICompilationUnit) element).getAllTypes(); for (int i = 0; i < types.length; i++) { if (types[i].getFullyQualifiedName().equals(typeName)) { type = types[i]; break; } } } else if (element instanceof IClassFile) { type = ((IClassFile) element).getType(); } if (type != null) { String[] sigs = Signature.getParameterTypes(signature); return type.getMethod(methodName, sigs); } return null; } /** * Returns the <code>IJavaBreakpoint</code> from the specified <code>IMember</code> * @param element the element to get the breakpoint from * @return the current breakpoint from the element or <code>null</code> */ protected IJavaBreakpoint getMethodBreakpoint(IMember element) { IBreakpointManager breakpointManager = DebugPlugin.getDefault().getBreakpointManager(); IBreakpoint[] breakpoints = breakpointManager.getBreakpoints(JDIDebugModel.getPluginIdentifier()); if (element instanceof IMethod) { IMethod method = (IMethod) element; for (int i = 0; i < breakpoints.length; i++) { IBreakpoint breakpoint = breakpoints[i]; if (breakpoint instanceof IJavaMethodBreakpoint) { IJavaMethodBreakpoint methodBreakpoint = (IJavaMethodBreakpoint) breakpoint; IMember container = null; try { container = BreakpointUtils.getMember(methodBreakpoint); } catch (CoreException e) { JDIDebugUIPlugin.log(e); return null; } if (container == null) { try { if (method.getDeclaringType().getFullyQualifiedName() .equals(methodBreakpoint.getTypeName()) && method.getElementName().equals(methodBreakpoint.getMethodName()) && methodBreakpoint.getMethodSignature() .equals(resolveMethodSignature(method))) { return methodBreakpoint; } } catch (CoreException e) { JDIDebugUIPlugin.log(e); } } else { if (container instanceof IMethod) { if (method.getDeclaringType().getFullyQualifiedName() .equals(container.getDeclaringType().getFullyQualifiedName())) { if (method.isSimilar((IMethod) container)) { return methodBreakpoint; } } } } } } } return null; } /** * Returns the compilation unit from the editor * @param editor the editor to get the compilation unit from * @return the compilation unit or <code>null</code> */ protected CompilationUnit parseCompilationUnit(ITextEditor editor) { return parseCompilationUnit(getTypeRoot(editor.getEditorInput())); } /** * Parses the {@link ITypeRoot}. * @param root the root * @return the parsed {@link CompilationUnit} */ CompilationUnit parseCompilationUnit(ITypeRoot root) { if (root != null) { return SharedASTProvider.getAST(root, SharedASTProvider.WAIT_YES, null); } return null; } /* * (non-Javadoc) * * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#canToggleWatchpoints(org.eclipse.ui.IWorkbenchPart, * org.eclipse.jface.viewers.ISelection) */ public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection) { if (isRemote(part, selection)) { return false; } if (selection instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) selection; return isFields(ss); } return (selection instanceof ITextSelection) && isField((ITextSelection) selection, part); } /** * Returns a selection of the member in the given text selection, or the * original selection if none. * * @param part * @param selection * @return a structured selection of the member in the given text selection, * or the original selection if none * @exception CoreException * if an exception occurs */ protected ISelection translateToMembers(IWorkbenchPart part, ISelection selection) throws CoreException { ITextEditor textEditor = getTextEditor(part); if (textEditor != null && selection instanceof ITextSelection) { ITextSelection textSelection = (ITextSelection) selection; IEditorInput editorInput = textEditor.getEditorInput(); IDocumentProvider documentProvider = textEditor.getDocumentProvider(); if (documentProvider == null) { throw new CoreException(Status.CANCEL_STATUS); } IDocument document = documentProvider.getDocument(editorInput); int offset = textSelection.getOffset(); if (document != null) { try { IRegion region = document.getLineInformationOfOffset(offset); int end = region.getOffset() + region.getLength(); while (Character.isWhitespace(document.getChar(offset)) && offset < end) { offset++; } } catch (BadLocationException e) { } } IMember m = null; ITypeRoot root = getTypeRoot(editorInput); if (root instanceof ICompilationUnit) { ICompilationUnit unit = (ICompilationUnit) root; synchronized (unit) { unit.reconcile(ICompilationUnit.NO_AST, false, null, null); } } if (root != null) { IJavaElement e = root.getElementAt(offset); if (e instanceof IMember) { m = (IMember) e; } } if (m != null) { return new StructuredSelection(m); } } return selection; } /** * Returns the {@link ITypeRoot} for the given {@link IEditorInput} * @param input * @return the type root or <code>null</code> if one cannot be derived * @since 3.4 */ private ITypeRoot getTypeRoot(IEditorInput input) { ITypeRoot root = (ITypeRoot) input.getAdapter(IClassFile.class); if (root == null) { IWorkingCopyManager manager = JavaUI.getWorkingCopyManager(); root = manager.getWorkingCopy(input); } if (root == null) { root = DebugWorkingCopyManager.getWorkingCopy(input, false); } return root; } /** * Return the associated IField (Java model) for the given * IJavaFieldVariable (JDI model) */ private IField getField(IJavaFieldVariable variable) throws CoreException { String varName = null; try { varName = variable.getName(); } catch (DebugException x) { JDIDebugUIPlugin.log(x); return null; } IField field; IJavaType declaringType = variable.getDeclaringType(); IType type = JavaDebugUtils.resolveType(declaringType); if (type != null) { field = type.getField(varName); if (field.exists()) { return field; } } return null; } /* * (non-Javadoc) * * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension#toggleBreakpoints(org.eclipse.ui.IWorkbenchPart, * org.eclipse.jface.viewers.ISelection) */ public void toggleBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException { ISelection sel = translateToMembers(part, selection); if (sel instanceof IStructuredSelection) { IMember member = (IMember) ((IStructuredSelection) sel).getFirstElement(); int mtype = member.getElementType(); if (mtype == IJavaElement.FIELD || mtype == IJavaElement.METHOD || mtype == IJavaElement.INITIALIZER) { // remove line breakpoint if present first if (selection instanceof ITextSelection) { ITextSelection ts = (ITextSelection) selection; IType declaringType = member.getDeclaringType(); IResource resource = BreakpointUtils.getBreakpointResource(declaringType); IJavaLineBreakpoint breakpoint = JDIDebugModel.lineBreakpointExists(resource, getQualifiedName(declaringType), ts.getStartLine() + 1); if (breakpoint != null) { deleteBreakpoint(breakpoint, part, null); return; } CompilationUnit unit = parseCompilationUnit(getTextEditor(part)); //ObjectTeams: (visibility) OTValidBreakpointLocationLocator instead of ValidBreakpointLocationLocator OTValidBreakpointLocationLocator loc = new OTValidBreakpointLocationLocator(unit, ts.getStartLine() + 1, true, true); unit.accept(loc); if (loc.getLocationType() == OTValidBreakpointLocationLocator.LOCATION_METHOD) { toggleMethodBreakpoints(part, sel); } else if (loc.getLocationType() == OTValidBreakpointLocationLocator.LOCATION_FIELD) { toggleWatchpoints(part, ts); } else if (loc.getLocationType() == OTValidBreakpointLocationLocator.LOCATION_LINE) { toggleLineBreakpoints(part, ts); } // carp} } } else if (member.getElementType() == IJavaElement.TYPE) { toggleClassBreakpoints(part, sel); } else { //fall back to old behavior, always create a line breakpoint toggleLineBreakpoints(part, selection, true, null); } } } /** * Deletes the given breakpoint using the operation history, which allows to undo the deletion. * * @param breakpoint the breakpoint to delete * @param part a workbench part, or <code>null</code> if unknown * @param progressMonitor the progress monitor * @throws CoreException if the deletion fails */ private static void deleteBreakpoint(IJavaBreakpoint breakpoint, IWorkbenchPart part, IProgressMonitor monitor) throws CoreException { final Shell shell = part != null ? part.getSite().getShell() : null; final boolean[] result = new boolean[] { true }; final IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(JDIDebugUIPlugin.getUniqueIdentifier()); boolean prompt = prefs.getBoolean(IJDIPreferencesConstants.PREF_PROMPT_DELETE_CONDITIONAL_BREAKPOINT, true); if (prompt && breakpoint instanceof IJavaLineBreakpoint && ((IJavaLineBreakpoint) breakpoint).getCondition() != null) { Display display = shell != null && !shell.isDisposed() ? shell.getDisplay() : PlatformUI.getWorkbench().getDisplay(); if (!display.isDisposed()) { display.syncExec(new Runnable() { public void run() { MessageDialogWithToggle dialog = MessageDialogWithToggle.openOkCancelConfirm(shell, ActionMessages.ToggleBreakpointAdapter_confirmDeleteTitle, ActionMessages.ToggleBreakpointAdapter_confirmDeleteMessage, ActionMessages.ToggleBreakpointAdapter_confirmDeleteShowAgain, false, null, null); if (dialog.getToggleState()) prefs.putBoolean(IJDIPreferencesConstants.PREF_PROMPT_DELETE_CONDITIONAL_BREAKPOINT, false); result[0] = dialog.getReturnCode() == IDialogConstants.OK_ID; } }); } } if (result[0]) DebugUITools.deleteBreakpoints(new IBreakpoint[] { breakpoint }, shell, monitor); } /* * (non-Javadoc) * * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension#canToggleBreakpoints(org.eclipse.ui.IWorkbenchPart, * org.eclipse.jface.viewers.ISelection) */ public boolean canToggleBreakpoints(IWorkbenchPart part, ISelection selection) { if (isRemote(part, selection)) { return false; } return canToggleLineBreakpoints(part, selection); } /* (non-Javadoc) * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension2#toggleBreakpointsWithEvent(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection, org.eclipse.swt.widgets.Event) */ public void toggleBreakpointsWithEvent(IWorkbenchPart part, ISelection selection, Event event) throws CoreException { if (event != null) { if ((event.stateMask & SWT.MOD2) > 0) { ITextEditor editor = getTextEditor(part); if (editor != null) { IVerticalRulerInfo info = (IVerticalRulerInfo) editor.getAdapter(IVerticalRulerInfo.class); if (info != null) { IBreakpoint bp = BreakpointUtils.getBreakpointFromEditor(editor, info); if (bp != null) { bp.setEnabled(!bp.isEnabled()); return; } } } } else if ((event.stateMask & SWT.MOD1) > 0) { ITextEditor editor = getTextEditor(part); if (editor != null) { IVerticalRulerInfo info = (IVerticalRulerInfo) editor.getAdapter(IVerticalRulerInfo.class); if (info != null) { IBreakpoint bp = BreakpointUtils.getBreakpointFromEditor(editor, info); if (bp != null) { PreferencesUtil .createPropertyDialogOn(editor.getSite().getShell(), bp, null, null, null) .open(); return; } } } } } toggleBreakpoints(part, selection); } /* (non-Javadoc) * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension2#canToggleBreakpointsWithEvent(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection, org.eclipse.swt.widgets.Event) */ public boolean canToggleBreakpointsWithEvent(IWorkbenchPart part, ISelection selection, Event event) { return canToggleBreakpoints(part, selection); } } //ike}