blob: 9cefef706903bdd43b7bea5daf5e6bef065ea367 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 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.actions;
import com.ibm.icu.text.MessageFormat;
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.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
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.actions.IToggleBreakpointsTargetExtension;
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.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
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.ui.BreakpointUtils;
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
import org.eclipse.jdt.internal.debug.ui.LocalFileStorageEditorInput;
import org.eclipse.jdt.internal.debug.ui.ZipEntryStorageEditorInput;
import org.eclipse.jdt.ui.IWorkingCopyManager;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.action.IStatusLineManager;
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.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.editors.text.ILocationProvider;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.IEditorStatusLine;
import org.eclipse.ui.texteditor.ITextEditor;
/**
* Toggles a line breakpoint in a Java editor.
*
* @since 3.0
*/
public class ToggleBreakpointAdapter implements IToggleBreakpointsTargetExtension {
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
/**
* Constructor
*/
public ToggleBreakpointAdapter() {
// init 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);
}
}
if (message != null && JDIDebugUIPlugin.getActiveWorkbenchShell() != null) {
JDIDebugUIPlugin.getActiveWorkbenchShell().getDisplay().beep();
}
}
});
}
/**
* 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;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleLineBreakpoints(IWorkbenchPart,
* ISelection)
*/
public void toggleLineBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
toggleLineBreakpoints(part, selection, false);
}
/**
* Toggles a line breakpoint. This is also the method called by the keybinding for creating breakpoints
* @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) {
Job job = new Job("Toggle Line Breakpoint") { //$NON-NLS-1$
protected IStatus run(IProgressMonitor monitor) {
if(isInterface(selection)) {
report(ActionMessages.ToggleBreakpointAdapter_6, part);
return Status.OK_STATUS;
}
ITextEditor editor = getTextEditor(part);
if (editor != null && selection instanceof ITextSelection) {
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
report(null, part);
ITextSelection textSelection = (ITextSelection) selection;
IType type = getType(textSelection);
int lineNumber = textSelection.getStartLine() + 1;
int offset = textSelection.getOffset();
try {
IEditorInput editorInput = editor.getEditorInput();
IDocumentProvider documentProvider = editor.getDocumentProvider();
if (documentProvider == null) {
return Status.CANCEL_STATUS;
}
IDocument document = documentProvider.getDocument(editorInput);
if (type == null) {
IClassFile classFile = (IClassFile) editorInput.getAdapter(IClassFile.class);
if (classFile != null) {
type = classFile.getType();
// bug 34856 - if this is an inner type, ensure
// the breakpoint is not
// being added to the outer type
if (type.getDeclaringType() != null) {
ISourceRange sourceRange = type.getSourceRange();
int start = sourceRange.getOffset();
int end = start + sourceRange.getLength();
if (offset < start || offset > end) {
// not in the inner type
final ITextEditor finalEditor = editor;
final IType finalType = type;
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
IStatusLineManager statusLine = finalEditor.getEditorSite().getActionBars().getStatusLineManager();
statusLine.setErrorMessage(MessageFormat.format(ActionMessages.ManageBreakpointRulerAction_Breakpoints_can_only_be_created_within_the_type_associated_with_the_editor___0___1, new String[] { finalType.getTypeQualifiedName() }));
}
});
Display.getCurrent().beep();
return Status.OK_STATUS;
}
}
}
}
String typeName = null;
IResource resource = null;
Map attributes = new HashMap(10);
if (type == null) {
resource = getResource(editor);
CompilationUnit unit = parseCompilationUnit(editor);
Iterator types = unit.types().iterator();
while (types.hasNext()) {
TypeDeclaration declaration = (TypeDeclaration) types.next();
int begin = declaration.getStartPosition();
int end = begin + declaration.getLength();
if (offset >= begin && offset <= end && !declaration.isInterface()) {
typeName = ValidBreakpointLocationLocator.computeTypeName(declaration);
break;
}
}
} else {
typeName = type.getFullyQualifiedName();
int index = typeName.indexOf('$');
if (index >= 0) {
typeName = typeName.substring(0, index);
}
resource = BreakpointUtils.getBreakpointResource(type);
try {
IRegion line = document.getLineInformation(lineNumber - 1);
int start = line.getOffset();
int end = start + line.getLength() - 1;
BreakpointUtils.addJavaBreakpointAttributesWithMemberDetails(attributes, type, start, end);
} catch (BadLocationException ble) {
JDIDebugUIPlugin.log(ble);
}
}
if (typeName != null && resource != null) {
IJavaLineBreakpoint existingBreakpoint = JDIDebugModel.lineBreakpointExists(resource, typeName, lineNumber);
if (existingBreakpoint != null) {
removeBreakpoint(existingBreakpoint, true);
return Status.OK_STATUS;
}
createLineBreakpoint(resource, typeName, lineNumber, -1, -1, 0, true, attributes, document, bestMatch, type, editor);
}
} catch (CoreException ce) {
return ce.getStatus();
}
}
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.schedule();
}
private void createLineBreakpoint(IResource resource, String typeName, int lineNumber, int charStart, int charEnd, int hitCount, boolean register, Map attributes, IDocument document, boolean bestMatch, IType type, IEditorPart editorPart) throws CoreException {
IJavaLineBreakpoint breakpoint = JDIDebugModel.createLineBreakpoint(resource, typeName, lineNumber, charStart, charEnd, hitCount, register, attributes);
new BreakpointLocationVerifierJob(document, breakpoint, lineNumber, bestMatch, typeName, type, resource, editorPart).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$
protected IStatus run(IProgressMonitor monitor) {
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
if(isInterface(finalSelection)) {
report(ActionMessages.ToggleBreakpointAdapter_7, part);
return Status.OK_STATUS;
}
try {
report(null, part);
ISelection selection = finalSelection;
selection = translateToMembers(part, selection);
ITextEditor textEditor = getTextEditor(part);
if (textEditor != null && selection instanceof ITextSelection) {
ITextSelection textSelection = (ITextSelection) selection;
CompilationUnit compilationUnit = parseCompilationUnit(textEditor);
if (compilationUnit != null) {
BreakpointMethodLocator locator = new BreakpointMethodLocator(textSelection.getOffset());
compilationUnit.accept(locator);
String methodName = locator.getMethodName();
if (methodName == null) {
report(ActionMessages.ManageMethodBreakpointActionDelegate_CantAdd, part);
return Status.OK_STATUS;
}
String typeName = locator.getTypeName();
String methodSignature = locator.getMethodSignature();
if (methodSignature == null) {
report(ActionMessages.ManageMethodBreakpointActionDelegate_methodNonAvailable, part);
return Status.OK_STATUS;
}
// check if this method breakpoint already
// exist. If yes, remove it, else create one
IJavaMethodBreakpoint existing = getMethodBreakpoint(typeName, methodName, methodSignature);
if (existing == null) {
createMethodBreakpoint(getResource((IEditorPart) part), typeName, methodName, methodSignature, true, false, false, -1, -1, -1, 0, true, new HashMap(10));
} else {
removeBreakpoint(existing, true);
}
}
} else if (selection instanceof IStructuredSelection) {
IMethod[] members = getMethods((IStructuredSelection) selection);
if (members.length == 0) {
report(ActionMessages.ToggleBreakpointAdapter_9, part);
return Status.OK_STATUS;
}
for (int i = 0, length = members.length; i < length; i++) {
IMethod method = members[i];
IJavaBreakpoint breakpoint = getMethodBreakpoint(method);
if (breakpoint == null) {
// add breakpoint
int start = -1;
int end = -1;
ISourceRange range = method.getNameRange();
if (range != null) {
start = range.getOffset();
end = start + range.getLength();
}
Map attributes = new HashMap(10);
BreakpointUtils.addJavaBreakpointAttributes(attributes, method);
IType type = method.getDeclaringType();
String methodSignature = method.getSignature();
String methodName = method.getElementName();
if (method.isConstructor()) {
methodName = "<init>"; //$NON-NLS-1$
if (type.isEnum()) {
methodSignature = "(Ljava.lang.String;I" + methodSignature.substring(1); //$NON-NLS-1$
}
}
if (!type.isBinary()) {
// resolve the type names
methodSignature = resolveMethodSignature(type, methodSignature);
if (methodSignature == null) {
report(ActionMessages.ManageMethodBreakpointActionDelegate_methodNonAvailable, part);
return Status.OK_STATUS;
}
}
createMethodBreakpoint(BreakpointUtils.getBreakpointResource(method), type.getFullyQualifiedName(), methodName, methodSignature, true, false, false, -1, start, end, 0, true, attributes);
} else {
// remove breakpoint
removeBreakpoint(breakpoint, true);
}
}
}
} catch (CoreException e) {
return e.getStatus();
}
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.schedule();
}
/**
* Returns any existing method breakpoint for the specified method or <code>null</code> if none.
*
* @param typeName fully qualified type name
* @param methodName method selector
* @param methodSignature method signature
* @return existing method or <code>null</code>
* @throws CoreException
*/
private IJavaMethodBreakpoint getMethodBreakpoint(String typeName, String methodName, String methodSignature) throws CoreException {
final 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 IJavaMethodBreakpoint) {
final IJavaMethodBreakpoint methodBreakpoint = (IJavaMethodBreakpoint) breakpoint;
if (typeName.equals(methodBreakpoint.getTypeName()) && methodName.equals(methodBreakpoint.getMethodName()) && methodSignature.equals(methodBreakpoint.getMethodSignature())) {
return methodBreakpoint;
}
}
}
return null;
}
/**
* Removes the specified breakpoint
* @param breakpoint the breakpoint to remove
* @param delete if it should be deleted as well
* @throws CoreException
*/
private void removeBreakpoint(IBreakpoint breakpoint, boolean delete) throws CoreException {
DebugPlugin.getDefault().getBreakpointManager().removeBreakpoint(breakpoint, delete);
}
private void createMethodBreakpoint(IResource resource, String typeName, String methodName, String methodSignature, boolean entry, boolean exit, boolean nativeOnly, int lineNumber, int charStart, int charEnd, int hitCount, boolean register, Map attributes) throws CoreException {
JDIDebugModel.createMethodBreakpoint(resource, typeName, methodName, methodSignature, entry, exit, nativeOnly, lineNumber, charStart, charEnd, hitCount, register, attributes);
}
/*
* (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).length > 0;
}
return selection instanceof ITextSelection;
}
/**
* Returns whether the given part/selection is remote (viewing a repsitory)
*
* @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 IAdaptable) {
IAdaptable adaptable = (IAdaptable) element;
IJavaElement javaElement = (IJavaElement) adaptable.getAdapter(IJavaElement.class);
return javaElement == null || !javaElement.getJavaProject().getProject().exists();
}
}
ITextEditor editor = getTextEditor(part);
if (editor != null) {
IEditorInput input = editor.getEditorInput();
IJavaElement element = (IJavaElement) input.getAdapter(IJavaElement.class);
if (element == null) {
// try to determine remote vs local but not in the workspace
if (input instanceof LocalFileStorageEditorInput ||
input instanceof ZipEntryStorageEditorInput) {
return false;
}
ILocationProvider provider = (ILocationProvider) input.getAdapter(ILocationProvider.class);
if (provider != null && provider.getPath(input) != null) {
return false;
}
} else {
return false;
}
return true;
}
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) {
if (selection.isEmpty()) {
return new IMethod[0];
}
List methods = new ArrayList(selection.size());
Iterator iterator = selection.iterator();
while (iterator.hasNext()) {
Object thing = iterator.next();
try {
if (thing instanceof IMethod) {
IMethod method = (IMethod) thing;
if (!Flags.isAbstract(method.getFlags())) {
methods.add(method);
}
}
} catch (JavaModelException e) {
}
}
return (IMethod[]) methods.toArray(new IMethod[methods.size()]);
}
/**
* 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 getFields(IStructuredSelection selection) throws CoreException {
if (selection.isEmpty()) {
return Collections.EMPTY_LIST;
}
List fields = new ArrayList(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 isor is part of an interface, false otherwise
* @since 3.2
*/
private boolean isInterface(ISelection selection) {
if (!selection.isEmpty()) {
try {
if(selection instanceof IStructuredSelection) {
IStructuredSelection ss = (IStructuredSelection) selection;
Iterator iterator = ss.iterator();
IType type = null;
Object obj = null;
while (iterator.hasNext()) {
obj = iterator.next();
if(obj instanceof IMember) {
type = ((IMember)obj).getDeclaringType();
}
if(type != null && type.isInterface()) {
return true;
}
}
}
else if(selection instanceof ITextSelection) {
ITextSelection tsel = (ITextSelection) selection;
IType type = getType(tsel);
if(type != null && type.isInterface()) {
return true;
}
}
}
catch (JavaModelException e) {JDIDebugUIPlugin.log(e);}
}
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()) {
Iterator iterator = selection.iterator();
while (iterator.hasNext()) {
Object thing = iterator.next();
if (!(thing instanceof IField || thing instanceof IJavaFieldVariable)) {
return false;
}
}
return true;
}
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$
protected IStatus run(IProgressMonitor monitor) {
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
if(isInterface(finalSelection)) {
report(ActionMessages.ToggleBreakpointAdapter_5, part);
return Status.OK_STATUS;
}
try {
report(null, part);
ISelection selection = finalSelection;
selection = translateToMembers(part, selection);
ITextEditor textEditor = getTextEditor(part);
boolean allowed = false;
if (textEditor != null && selection instanceof ITextSelection) {
ITextSelection textSelection = (ITextSelection) selection;
CompilationUnit compilationUnit = parseCompilationUnit(textEditor);
if (compilationUnit != null) {
BreakpointFieldLocator locator = new BreakpointFieldLocator(textSelection.getOffset());
compilationUnit.accept(locator);
String fieldName = locator.getFieldName();
if (fieldName == null) {
report(ActionMessages.ManageWatchpointActionDelegate_CantAdd, part);
return Status.OK_STATUS;
}
int idx = fieldName.indexOf("final"); //$NON-NLS-1$
if(!(idx > -1) & !(fieldName.indexOf("static") > -1 & idx > -1)) { //$NON-NLS-1$
allowed = true;
}
String typeName = locator.getTypeName();
// check if the watchpoint already exists. If yes,
// remove it, else create one
IJavaWatchpoint existing = getWatchpoint(typeName, fieldName);
if (existing == null) {
if(!allowed) {
report(ActionMessages.ToggleBreakpointAdapter_8, part);
return Status.OK_STATUS;
}
createWatchpoint(getResource((IEditorPart) part), typeName, fieldName, -1, -1, -1, 0, true, new HashMap(10));
} else {
removeBreakpoint(existing, true);
}
}
} else if (selection instanceof IStructuredSelection) {
List fields = getFields((IStructuredSelection) selection);
if (fields.isEmpty()) {
report(ActionMessages.ToggleBreakpointAdapter_10, part);
return Status.OK_STATUS;
}
Iterator theFields = fields.iterator();
while (theFields.hasNext()) {
Object element = theFields.next();
IField javaField = null;
IJavaFieldVariable var = null;
String typeName = null;
String fieldName = null;
if (element instanceof IField) {
javaField = (IField) element;
typeName = javaField.getDeclaringType().getFullyQualifiedName();
fieldName = javaField.getElementName();
int f = javaField.getFlags();
boolean fin = Flags.isFinal(f);
allowed = !(fin) & !(Flags.isStatic(f) & fin);
} else if (element instanceof IJavaFieldVariable) {
var = (IJavaFieldVariable) element;
typeName = var.getDeclaringType().getName();
fieldName = var.getName();
allowed = !(var.isFinal() || var.isStatic());
}
IJavaBreakpoint breakpoint = getWatchpoint(typeName, fieldName);
if (breakpoint == null) {
if(!allowed) {
report(ActionMessages.ToggleBreakpointAdapter_8, part);
return Status.OK_STATUS;
}
IResource resource = null;
int start = -1;
int end = -1;
Map attributes = new HashMap(10);
if (javaField == null) {
if(var != null) {
Object object = JavaDebugUtils.resolveSourceElement(var.getJavaType(), var.getLaunch());
if (object instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) object;
resource = (IResource) adaptable.getAdapter(IResource.class);
}
}
if (resource == 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);
}
createWatchpoint(resource, typeName, fieldName, -1, start, end, 0, true, attributes);
} else {
// remove breakpoint
removeBreakpoint(breakpoint, true);
}
}
}
} catch (CoreException e) {
return e.getStatus();
}
return Status.OK_STATUS;
}
};
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;
}
private void createWatchpoint(IResource resource, String typeName, String fieldName, int lineNumber, int charStart, int charEnd, int hitCount, boolean register, Map attributes) throws CoreException {
JDIDebugModel.createWatchpoint(resource, typeName, fieldName, lineNumber, charStart, charEnd, hitCount, register, attributes);
}
/**
* Returns the resolved method signature for the specified type
* @param type the decalring type the method is contained in
* @param methodSignature the method signature to resolve
* @return the resolved method signature
* @throws JavaModelException
*/
public static String resolveMethodSignature(IType type, String methodSignature) throws JavaModelException {
String[] parameterTypes = Signature.getParameterTypes(methodSignature);
int length = parameterTypes.length;
String[] resolvedParameterTypes = new String[length];
for (int i = 0; i < length; i++) {
resolvedParameterTypes[i] = resolveType(type, parameterTypes[i]);
if (resolvedParameterTypes[i] == null) {
return null;
}
}
String resolvedReturnType = resolveType(type, Signature.getReturnType(methodSignature));
if (resolvedReturnType == null) {
return null;
}
return Signature.createMethodSignature(resolvedParameterTypes, resolvedReturnType);
}
/**
* Resolves the the type for its given signature
* @param type the type
* @param typeSignature the types signature
* @return the resolved type name
* @throws JavaModelException
*/
private static String resolveType(IType type, 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);
String[][] resolvedElementTypeNames = type.resolveType(elementTypeName);
if (resolvedElementTypeNames == null || resolvedElementTypeNames.length != 1) {
// check if type parameter
ITypeParameter[] typeParameters = type.getTypeParameters();
for (int i = 0; i < typeParameters.length; i++) {
ITypeParameter parameter = typeParameters[i];
if (parameter.getElementName().equals(elementTypeName)) {
String[] bounds = parameter.getBounds();
if (bounds.length == 0) {
return "Ljava/lang/Object;"; //$NON-NLS-1$
} else {
String bound = Signature.createTypeSignature(bounds[0], false);
return resolveType(type, bound);
}
}
}
// 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</cdoe> 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()) && method.getSignature().equals(methodBreakpoint.getMethodSignature())) {
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>
* @throws CoreException
*/
protected CompilationUnit parseCompilationUnit(ITextEditor editor) throws CoreException {
IEditorInput editorInput = editor.getEditorInput();
IDocumentProvider documentProvider = editor.getDocumentProvider();
if (documentProvider == null) {
throw new CoreException(Status.CANCEL_STATUS);
}
IDocument document = documentProvider.getDocument(editorInput);
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setSource(document.get().toCharArray());
return (CompilationUnit) parser.createAST(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;
}
/**
* 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 exceptoin occurrs
*/
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;
IClassFile classFile = (IClassFile) editorInput.getAdapter(IClassFile.class);
if (classFile != null) {
IJavaElement e = classFile.getElementAt(offset);
if (e instanceof IMember) {
m = (IMember) e;
}
} else {
IWorkingCopyManager manager = JavaUI.getWorkingCopyManager();
ICompilationUnit unit = manager.getWorkingCopy(editorInput);
if (unit != null) {
synchronized (unit) {
unit.reconcile(ICompilationUnit.NO_AST /*
* don't create
* ast
*/, false/*
* don't
* force
* problem
* detection
*/, null/*
* use
* primary
* owner
*/, null/*
* no
* progress
* monitor
*/);
}
IJavaElement e = unit.getElementAt(offset);
if (e instanceof IMember) {
m = (IMember) e;
}
}
}
if (m != null) {
return new StructuredSelection(m);
}
}
return selection;
}
/**
* 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 {
toggleLineBreakpoints(part, selection, true);
}
/*
* (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);
}
}