blob: c4bfc078d2b09abfdfeb7e087fa92ac0fb2ef91b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.debug.ui.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 java.util.concurrent.atomic.AtomicReference;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
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.internal.ui.DebugUIPlugin;
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.IOrdinaryClassFile;
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.JavaCore;
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.core.manipulation.SharedASTProviderCore;
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.corext.template.java.CompilationUnitContext;
import org.eclipse.jdt.internal.corext.template.java.CompilationUnitContextType;
import org.eclipse.jdt.internal.corext.template.java.JavaContextType;
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.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
import org.eclipse.jdt.internal.ui.text.template.contentassist.TemplateEngine;
import org.eclipse.jdt.internal.ui.text.template.contentassist.TemplateProposal;
import org.eclipse.jdt.ui.IWorkingCopyManager;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.dialogs.ErrorDialog;
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.ITextViewer;
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.jface.text.templates.DocumentTemplateContext;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.jface.text.templates.TemplateException;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
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.ITextEditor;
import org.eclipse.ui.texteditor.SimpleMarkerAnnotation;
/**
* Toggles a line breakpoint in a Java editor.
*
* @since 3.0
*/
public class ToggleBreakpointAdapter implements IToggleBreakpointsTargetExtension2 {
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
/**
* Constructor
*/
public ToggleBreakpointAdapter() {
// initialize helper in UI thread
ActionDelegateHelper.getDefault();
}
/**
* 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 static 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 static 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;
}
}
}
@Override
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 static 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();
}
@Override
public boolean canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection) {
if (isRemote(part, selection)) {
return false;
}
return selection instanceof ITextSelection;
}
@Override
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 {
return doToggleMethodBreakpoints(part, finalSelection, monitor);
} catch (CoreException e) {
return e.getStatus();
} finally {
BreakpointToggleUtils.setUnsetTracepoints(false);
}
}
};
job.setPriority(Job.INTERACTIVE);
job.setSystem(true);
job.schedule();
}
static IStatus doToggleMethodBreakpoints(IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
BreakpointToggleUtils.report(null, part);
ISelection selection = finalSelection;
if (!(selection instanceof IStructuredSelection)) {
selection = translateToMembers(part, selection);
}
boolean isInterface = isInterface(selection, part);
if (!(selection instanceof IStructuredSelection)) {
BreakpointToggleUtils.report(ActionMessages.ToggleBreakpointAdapter_4, part);
return Status.OK_STATUS;
}
IMethod[] members = getMethods((IStructuredSelection) selection, isInterface);
if (members.length == 0) {
if (isInterface) {
BreakpointToggleUtils.report(ActionMessages.ToggleBreakpointAdapter_6, part);
} else {
BreakpointToggleUtils.report(ActionMessages.ToggleBreakpointAdapter_9, part);
}
return Status.OK_STATUS;
}
for (IMethod member : members) {
doToggleMethodBreakpoint(member, part, finalSelection, monitor);
}
return Status.OK_STATUS;
}
private static void doToggleMethodBreakpoint(IMethod member, IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
IJavaBreakpoint breakpoint = getMethodBreakpoint(member);
if (breakpoint != null) {
if (BreakpointToggleUtils.isToggleTracepoints()) {
deleteTracepoint(breakpoint, part, monitor);
BreakpointToggleUtils.setUnsetTracepoints(false);
} else {
deleteBreakpoint(breakpoint, part, monitor);
}
return;
}
int start = -1;
int end = -1;
ISourceRange range = member.getNameRange();
if (range != null) {
start = range.getOffset();
end = start + range.getLength();
}
Map<String, Object> attributes = new HashMap<>(10);
BreakpointUtils.addJavaBreakpointAttributes(attributes, member);
IType type = member.getDeclaringType();
String signature = member.getSignature();
String mname = member.getElementName();
if (member.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(member);
if (signature == null) {
BreakpointToggleUtils.report(ActionMessages.ManageMethodBreakpointActionDelegate_methodNonAvailable, part);
return;
}
}
IResource resource = BreakpointUtils.getBreakpointResource(member);
String qualifiedName = getQualifiedName(type);
IJavaMethodBreakpoint methodBreakpoint = JDIDebugModel.createMethodBreakpoint(resource, qualifiedName, mname, signature, true, false, false, -1, start, end, 0, true, attributes);
if (BreakpointToggleUtils.isToggleTracepoints() && finalSelection instanceof ITextSelection && part instanceof CompilationUnitEditor) {
String pattern = getCodeTemplate((ITextSelection) finalSelection, (CompilationUnitEditor) part);
if (pattern != null) {
pattern = pattern.trim();
pattern = pattern.replaceAll("\\\t", ""); //$NON-NLS-1$//$NON-NLS-2$
methodBreakpoint.setCondition(pattern);
methodBreakpoint.setConditionEnabled(true);
methodBreakpoint.setConditionSuspendOnTrue(true);
}
BreakpointToggleUtils.setUnsetTracepoints(false);
}
}
/**
* 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
*/
static IStatus doLineBreakpointToggle(ISelection selection, IWorkbenchPart part, ValidBreakpointLocationLocator locator, boolean bestMatch, IProgressMonitor monitor) {
ITextEditor editor = getTextEditor(part);
if (editor == null || !(selection instanceof ITextSelection)) {
return Status.CANCEL_STATUS;
}
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
ITextSelection tsel = (ITextSelection) selection;
if (tsel.getStartLine() < 0) {
return Status.CANCEL_STATUS;
}
try {
BreakpointToggleUtils.report(null, part);
ISelection sel = selection;
if (!(selection instanceof IStructuredSelection)) {
sel = translateToMembers(part, selection);
}
if (!(sel instanceof IStructuredSelection)) {
BreakpointToggleUtils.report(ActionMessages.ToggleBreakpointAdapter_3, part);
return Status.OK_STATUS;
}
IMember member = (IMember) ((IStructuredSelection) sel).getFirstElement();
IType type = null;
if (member.getElementType() == IJavaElement.TYPE) {
type = (IType) member;
} else {
type = member.getDeclaringType();
}
if (type == null) {
IStatus status = new Status(IStatus.INFO, DebugUIPlugin.getUniqueIdentifier(), ActionMessages.ToggleBreakpointAdapter_ErrorMessage);
Display.getDefault().asyncExec(() -> ErrorDialog.openError(JDIDebugUIPlugin.getShell(), ActionMessages.ToggleBreakpointAdapter_ErrorTitle, null, status));
return status;
}
if (locator == null && BreakpointToggleUtils.isToggleTracepoints()) {
CompilationUnit cUnit = parseCompilationUnit(type.getTypeRoot());
locator = new ValidBreakpointLocationLocator(cUnit, tsel.getStartLine() + 1, true, bestMatch);
cUnit.accept(locator);
}
String tname = null;
IJavaProject project = type.getJavaProject();
if (locator == null || (project != null && !project.isOnClasspath(type))) {
tname = createQualifiedTypeName(type);
} else {
tname = locator.getFullyQualifiedTypeName();
}
if (tname == null) {
return Status.CANCEL_STATUS;
}
IResource resource = BreakpointUtils.getBreakpointResource(type);
int lnumber = locator == null ? tsel.getStartLine() + 1 : locator.getLineLocation();
IJavaLineBreakpoint existingBreakpoint = JDIDebugModel.lineBreakpointExists(resource, tname, lnumber);
if (existingBreakpoint != null) {
if (BreakpointToggleUtils.isToggleTracepoints()) {
deleteTracepoint(existingBreakpoint, editor, monitor);
BreakpointToggleUtils.setUnsetTracepoints(false);
} else {
deleteBreakpoint(existingBreakpoint, editor, monitor);
}
return Status.OK_STATUS;
}
Map<String, Object> attributes = new HashMap<>(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 (BreakpointToggleUtils.isToggleTracepoints() && selection instanceof ITextSelection && part instanceof CompilationUnitEditor) {
String pattern = getCodeTemplate((ITextSelection) selection, (CompilationUnitEditor) part);
if (pattern != null) {
pattern = pattern.trim();
pattern = pattern.replaceAll("\\\t", ""); //$NON-NLS-1$//$NON-NLS-2$
breakpoint.setCondition(pattern);
breakpoint.setConditionEnabled(true);
breakpoint.setConditionSuspendOnTrue(true);
}
BreakpointToggleUtils.setUnsetTracepoints(false);
}
if (locator == null) {
new BreakpointLocationVerifierJob(document, parseCompilationUnit(type.getTypeRoot()), breakpoint, lnumber, tname, type, editor, bestMatch).schedule();
}
if (BreakpointToggleUtils.isToggleTracepoints()) {
BreakpointToggleUtils.setUnsetTracepoints(false);
}
} catch (CoreException ce) {
return ce.getStatus();
} finally {
BreakpointToggleUtils.setUnsetTracepoints(false);
}
return Status.OK_STATUS;
}
/**
* Toggles a class load breakpoint
* @param part the part
* @param selection the current selection
* @since 3.3
*/
public static 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 {
return doToggleClassBreakpoints(part, selection, monitor);
} catch (CoreException e) {
return e.getStatus();
}
}
};
job.setPriority(Job.INTERACTIVE);
job.setSystem(true);
job.schedule();
}
static IStatus doToggleClassBreakpoints(IWorkbenchPart part, ISelection selection, IProgressMonitor monitor) throws CoreException {
BreakpointToggleUtils.report(null, part);
ISelection sel = selection;
if (!(selection instanceof IStructuredSelection)) {
sel = translateToMembers(part, selection);
}
if (isInterface(sel, part)) {
BreakpointToggleUtils.report(ActionMessages.ToggleBreakpointAdapter_1, part);
return Status.OK_STATUS;
}
if (!(sel instanceof IStructuredSelection)) {
BreakpointToggleUtils.report(ActionMessages.ToggleBreakpointAdapter_0, part);
return Status.OK_STATUS;
}
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<>(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();
}
IResource resource = BreakpointUtils.getBreakpointResource(member);
String qualifiedName = getQualifiedName(type);
JDIDebugModel.createClassPrepareBreakpoint(resource, qualifiedName, IJavaClassPrepareBreakpoint.TYPE_CLASS, start, end, true, map);
return Status.OK_STATUS;
}
/**
* 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 static 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
*/
static String getQualifiedName(IType type) throws JavaModelException {
IJavaProject project = type.getJavaProject();
if (project == null || !project.isOnClasspath(type) || !needsBindings(type)) {
return createQualifiedTypeName(type);
}
CompilationUnit cuNode = parseCompilationUnit(type.getTypeRoot());
ISourceRange nameRange = type.getNameRange();
if (cuNode == null || !SourceRange.isAvailable(nameRange)) {
return createQualifiedTypeName(type);
}
ASTNode node = NodeFinder.perform(cuNode, nameRange);
if (!(node instanceof SimpleName)) {
return createQualifiedTypeName(type);
}
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
*/
static 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
*/
static String createQualifiedTypeName(IType type) {
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)) {
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) {
StringBuilder buffer = new StringBuilder();
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, '$');
}
buffer.insert(0, atype.getElementName());
}
}
catch(JavaModelException jme) {}
}
parent = parent.getParent();
}
return buffer.toString();
}
/**
* 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 static 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);
}
@Override
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 static 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 static ITextEditor getTextEditor(IWorkbenchPart part) {
if (part instanceof ITextEditor) {
return (ITextEditor) part;
}
return 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 static IMethod[] getMethods(IStructuredSelection selection, boolean isInterace) {
if (selection.isEmpty()) {
return new IMethod[0];
}
List<IMethod> 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(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 static IMethod[] getInterfaceMethods(IStructuredSelection selection) {
if (selection.isEmpty()) {
return new IMethod[0];
}
List<IMethod> 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.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 static 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());
}
if (element != null && element.getElementType() == IJavaElement.METHOD) {
IMethod method = (IMethod) element;
if (method.getDeclaringType().isAnonymous()) {
return false;
}
return true;
}
}
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 static List<Object> getFields(IStructuredSelection selection) throws CoreException {
if (selection.isEmpty()) {
return Collections.EMPTY_LIST;
}
List<Object> 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 is part of an interface, false otherwise
* @since 3.2
*/
private static 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();
}
IType type = member.getDeclaringType();
return type != null && type.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 static 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 static boolean isFields(IStructuredSelection selection) {
if (selection.isEmpty()) {
return false;
}
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);
} else if (thing instanceof IJavaFieldVariable) {
IJavaFieldVariable fv = (IJavaFieldVariable) thing;
return !fv.isFinal();
}
}
} catch (JavaModelException | DebugException e) {
return false;
}
return false;
}
@Override
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 {
return doToggleWatchpoints(part, finalSelection, monitor);
} catch (CoreException e) {
return e.getStatus();
}
}
};
job.setPriority(Job.INTERACTIVE);
job.setSystem(true);
job.schedule();
}
static IStatus doToggleWatchpoints(IWorkbenchPart part, ISelection finalSelection, IProgressMonitor monitor) throws CoreException {
BreakpointToggleUtils.report(null, part);
ISelection selection = finalSelection;
if (!(selection instanceof IStructuredSelection)) {
selection = translateToMembers(part, finalSelection);
}
if (isInterface(selection, part)) {
BreakpointToggleUtils.report(ActionMessages.ToggleBreakpointAdapter_5, part);
return Status.OK_STATUS;
}
boolean allowed = false;
if (!(selection instanceof IStructuredSelection)) {
BreakpointToggleUtils.report(ActionMessages.ToggleBreakpointAdapter_2, part);
return Status.OK_STATUS;
}
List<Object> fields = getFields((IStructuredSelection) selection);
if (fields.isEmpty()) {
BreakpointToggleUtils.report(ActionMessages.ToggleBreakpointAdapter_10, part);
return Status.OK_STATUS;
}
IField javaField = null;
String typeName = null;
String fieldName = null;
for (Object element : fields) {
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);
if (fin) {
fin = javaField.getConstant() != null; // watch point is allowed if no constant value
}
allowed = !fin;
} else if (element instanceof IJavaFieldVariable) {
IJavaFieldVariable var = (IJavaFieldVariable) element;
typeName = var.getDeclaringType().getName();
fieldName = var.getName();
boolean fin = var.isFinal();
if (fin) {
fin = javaField.getConstant() != null; // watch point is allowed if no constant value
}
allowed = !fin;
}
IJavaBreakpoint breakpoint = getWatchpoint(typeName, fieldName);
if (breakpoint != null) {
deleteBreakpoint(breakpoint, part, monitor);
continue;
}
if (!allowed) {
return doLineBreakpointToggle(finalSelection, part, null, true, monitor);
}
int start = -1;
int end = -1;
Map<String, Object> attributes = new HashMap<>(10);
IResource resource;
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);
}
return Status.OK_STATUS;
}
/**
* 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 static 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 = 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 static IMethod getMethodHandle(IEditorPart editorPart, String typeName, String methodName, String signature) throws CoreException {
IJavaElement element = 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 IOrdinaryClassFile) {
type = ((IOrdinaryClassFile) 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 static IJavaBreakpoint getMethodBreakpoint(IMember element) {
IBreakpointManager breakpointManager = DebugPlugin.getDefault().getBreakpointManager();
IBreakpoint[] breakpoints = breakpointManager.getBreakpoints(JDIDebugModel.getPluginIdentifier());
if (!(element instanceof IMethod)) {
return null;
}
IMethod method = (IMethod) element;
for (IBreakpoint breakpoint : breakpoints) {
if (!(breakpoint instanceof IJavaMethodBreakpoint)) {
continue;
}
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 static CompilationUnit parseCompilationUnit(ITextEditor editor) {
return parseCompilationUnit(getTypeRoot(editor.getEditorInput()));
}
/**
* Parses the {@link ITypeRoot}.
*
* @param root
* the root
* @return the parsed {@link CompilationUnit} or {@code null}
*/
static CompilationUnit parseCompilationUnit(ITypeRoot root) {
if(root != null) {
return SharedASTProviderCore.getAST(root, SharedASTProviderCore.WAIT_YES, null);
}
return null;
}
@Override
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 static ISelection translateToMembers(IWorkbenchPart part, ISelection selection) throws CoreException {
ITextEditor textEditor = getTextEditor(part);
if (textEditor == null || !(selection instanceof ITextSelection)) {
return selection;
}
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 static ITypeRoot getTypeRoot(IEditorInput input) {
ITypeRoot root = 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 static 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;
}
@Override
public void toggleBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
ISelection sel = translateToMembers(part, selection);
if (!(sel instanceof IStructuredSelection)) {
return;
}
IMember member = (IMember) ((IStructuredSelection) sel).getFirstElement();
int mtype = member.getElementType();
if (mtype == IJavaElement.FIELD || mtype == IJavaElement.METHOD || mtype == IJavaElement.INITIALIZER) {
toggleFieldOrMethodBreakpoints(part, selection);
} else if (member.getElementType() == IJavaElement.TYPE) {
if (BreakpointToggleUtils.isToggleTracepoints()) {
BreakpointToggleUtils.report(ActionMessages.TracepointToggleAction_Unavailable, part);
BreakpointToggleUtils.setUnsetTracepoints(false);
return;
}
toggleClassBreakpoints(part, sel);
} else {
// fall back to old behavior, always create a line breakpoint
toggleLineBreakpoints(part, selection, true, null);
}
}
private static IJavaLineBreakpoint findExistingBreakpoint(ITextEditor editor, ITextSelection ts) {
IDocumentProvider documentProvider = editor.getDocumentProvider();
if (documentProvider == null) {
return null;
}
IEditorInput editorInput = editor.getEditorInput();
IAnnotationModel annotationModel = documentProvider.getAnnotationModel(editorInput);
if (annotationModel == null) {
return null;
}
IDocument document = documentProvider.getDocument(editorInput);
if (document == null) {
return null;
}
Iterator<Annotation> iterator = annotationModel.getAnnotationIterator();
while (iterator.hasNext()) {
Object object = iterator.next();
if (!(object instanceof SimpleMarkerAnnotation)) {
continue;
}
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 == ts.getStartLine()) {
IBreakpoint oldBreakpoint = DebugPlugin.getDefault().getBreakpointManager().getBreakpoint(marker);
if (oldBreakpoint instanceof IJavaLineBreakpoint) {
return (IJavaLineBreakpoint) oldBreakpoint;
}
}
}
} catch (BadLocationException e) {
JDIDebugUIPlugin.log(e);
} catch (CoreException e) {
logBadAnnotation(markerAnnotation, e);
}
}
return null;
}
private void toggleFieldOrMethodBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
if (!(selection instanceof ITextSelection)) {
return;
}
ITextSelection ts = (ITextSelection) selection;
ITextEditor editor = getTextEditor(part);
if (editor == null) {
return;
}
// remove line breakpoint if present first
IJavaLineBreakpoint breakpoint = findExistingBreakpoint(editor, ts);
if (breakpoint != null) {
if (BreakpointToggleUtils.isToggleTracepoints()) {
deleteTracepoint(breakpoint, part, null);
BreakpointToggleUtils.setUnsetTracepoints(false);
} else {
deleteBreakpoint(breakpoint, part, null);
}
return;
}
// no breakpoint found: we create new one
CompilationUnit unit = parseCompilationUnit(editor);
if (unit == null) {
JDIDebugUIPlugin.log("Failed to parse CU for: " + editor.getTitle(), new IllegalStateException()); //$NON-NLS-1$
return;
}
ValidBreakpointLocationLocator loc = new ValidBreakpointLocationLocator(unit, ts.getStartLine() + 1, true, true);
unit.accept(loc);
if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_METHOD) {
toggleMethodBreakpoints(part, ts);
} else if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_FIELD) {
if (BreakpointToggleUtils.isToggleTracepoints()) {
BreakpointToggleUtils.report(ActionMessages.TracepointToggleAction_Unavailable, part);
BreakpointToggleUtils.setUnsetTracepoints(false);
return;
}
toggleWatchpoints(part, ts);
} else if (loc.getLocationType() == ValidBreakpointLocationLocator.LOCATION_LINE) {
toggleLineBreakpoints(part, ts, false, loc);
}
}
/**
* Additional diagnosis info for bug 528321
*/
private static void logBadAnnotation(SimpleMarkerAnnotation annotation, CoreException e) {
String message = "Editor annotation with non existing marker found: "; //$NON-NLS-1$
message += "text: " + annotation.getText(); //$NON-NLS-1$
message += ", type: " + annotation.getType(); //$NON-NLS-1$
message += ", " + annotation.getMarker(); //$NON-NLS-1$
JDIDebugUIPlugin.log(message, e);
}
/**
* 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() {
@Override
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);
}
}
private static void deleteTracepoint(IJavaBreakpoint breakpoint, IWorkbenchPart part, IProgressMonitor monitor) throws CoreException {
final Shell shell = part != null ? part.getSite().getShell() : null;
final IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(JDIDebugUIPlugin.getUniqueIdentifier());
boolean prompt = prefs.getBoolean(IJDIPreferencesConstants.PREF_PROMPT_DELETE_CONDITIONAL_BREAKPOINT, true);
if (!prompt || !(breakpoint instanceof IJavaLineBreakpoint)) {
DebugUITools.deleteBreakpoints(new IBreakpoint[] { breakpoint }, shell, monitor);
return;
}
final boolean[] result = new boolean[] { true };
String condition = ((IJavaLineBreakpoint) breakpoint).getCondition();
boolean conditionChanged = true;
if (condition != null) {
int index = condition.indexOf(';');
if (index != -1) {
int lastIndex = condition.lastIndexOf(';');
if (index == lastIndex) {
conditionChanged = false;
}
} else {
if (condition.indexOf("print") != -1) { //$NON-NLS-1$
conditionChanged = false;
}
}
}
if (conditionChanged && condition != null) {
Display display = shell != null && !shell.isDisposed() ? shell.getDisplay() : PlatformUI.getWorkbench().getDisplay();
if (!display.isDisposed()) {
display.syncExec(new Runnable() {
@Override
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);
}
}
@Override
public boolean canToggleBreakpoints(IWorkbenchPart part, ISelection selection) {
if (isRemote(part, selection)) {
return false;
}
return canToggleLineBreakpoints(part, selection);
}
@Override
public void toggleBreakpointsWithEvent(IWorkbenchPart part, ISelection selection, Event event) throws CoreException {
if (event == null) {
toggleBreakpoints(part, selection);
return;
}
if ((event.stateMask & SWT.MOD2) > 0) {
ITextEditor editor = getTextEditor(part);
if (editor != null) {
IVerticalRulerInfo info = 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 = 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);
}
@Override
public boolean canToggleBreakpointsWithEvent(IWorkbenchPart part, ISelection selection, Event event) {
return canToggleBreakpoints(part, 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.8
*/
private static String getCodeTemplate(ITextSelection textSelection, CompilationUnitEditor part) {
ITextViewer viewer = part.getViewer();
if (viewer == null) {
return null;
}
TemplateContextType contextType = JavaPlugin.getDefault().getTemplateContextRegistry().getContextType(JavaContextType.ID_STATEMENTS);
final AtomicReference<String> templateBuffer = new AtomicReference<>();
Display.getDefault().syncExec(() -> doGetCodeTemplate(textSelection, part, viewer, contextType, templateBuffer));
return templateBuffer.get();
}
private static void doGetCodeTemplate(ITextSelection textSelection, CompilationUnitEditor part, ITextViewer viewer, TemplateContextType contextType, AtomicReference<String> templateBuffer) {
ITextEditor editor = getTextEditor(part);
if (editor == null) {
return;
}
TemplateEngine statementEngine = new TemplateEngine(contextType);
statementEngine.reset();
IJavaElement element = getJavaElement(editor.getEditorInput());
ICompilationUnit cunit = null;
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IFile file = root.getFile(element.getPath());
cunit = JavaCore.createCompilationUnitFrom(file);
IDocumentProvider documentProvider = editor.getDocumentProvider();
if (documentProvider == null) {
return;
}
IDocument document = documentProvider.getDocument(editor.getEditorInput());
try {
IRegion line = document.getLineInformation(textSelection.getStartLine() + 1);
Point selectedRange = viewer.getSelectedRange();
viewer.setSelectedRange(selectedRange.x, 0);
statementEngine.complete(viewer, selectedRange, line.getOffset(), cunit);
viewer.setSelectedRange(selectedRange.x, selectedRange.y);
TemplateProposal[] templateProposals = statementEngine.getResults();
for (TemplateProposal templateProposal : templateProposals) {
Template template = templateProposal.getTemplate();
if (template.getName().equals("systrace")) { //$NON-NLS-1$
CompilationUnitContextType cuContextType = (CompilationUnitContextType) JavaPlugin.getDefault().getTemplateContextRegistry().getContextType(template.getContextTypeId());
DocumentTemplateContext context = cuContextType.createContext(document, line.getOffset(), 0, cunit);
context.setVariable("selection", EMPTY_STRING); //$NON-NLS-1$
((CompilationUnitContext) context).setForceEvaluation(true);
templateBuffer.set(context.evaluate(template).getString());
return;
}
}
} catch (BadLocationException | TemplateException e) {
// ignore
}
}
}