blob: f6c042b099f415066208ae04b74d90ee0f5b96c7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2017 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.core.refactoring;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IImportContainer;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IOrdinaryClassFile;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
import org.eclipse.jdt.debug.core.IJavaObject;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
/**
* An abstract change for breakpoint type refactoring changes
* @since 3.2
*
*/
public abstract class BreakpointChange extends Change {
/**
* constant for no line number
*
* @since 3.5
*/
protected static final int NO_LINE_NUMBER = -1;
private IJavaBreakpoint fBreakpoint;
private String fTypeName;
private int fHitCount;
private IJavaObject[] fInstanceFilters;
private int fSuspendPolicy;
private IJavaThread[] fThreadFilters;
private boolean fEnabled;
private String fWorkingSetNames;
/**
* Constructor
* @param breakpoint
* @throws CoreException
*/
public BreakpointChange(IJavaBreakpoint breakpoint) throws CoreException {
fBreakpoint = breakpoint;
fTypeName = breakpoint.getTypeName();
fHitCount = breakpoint.getHitCount();
fInstanceFilters = breakpoint.getInstanceFilters();
fSuspendPolicy = breakpoint.getSuspendPolicy();
fThreadFilters = breakpoint.getThreadFilters();
fEnabled = breakpoint.isEnabled();
fWorkingSetNames = (String) breakpoint.getMarker().getAttribute(IInternalDebugUIConstants.WORKING_SET_NAME);
}
/**
* Applies the original attributes to the new breakpoint
*
* @param breakpoint the new breakpoint
* @throws CoreException
*/
protected void apply(IJavaBreakpoint breakpoint) throws CoreException {
breakpoint.setHitCount(fHitCount);
for (int i = 0; i < fInstanceFilters.length; i++) {
breakpoint.addInstanceFilter(fInstanceFilters[i]);
}
breakpoint.setSuspendPolicy(fSuspendPolicy);
for (int i = 0; i < fThreadFilters.length; i++) {
breakpoint.setThreadFilter(fThreadFilters[i]);
}
breakpoint.setEnabled(fEnabled);
}
/**
* Returns the original breakpoints prior to the change
* @return the original breakpoint prior to the change
*/
protected IJavaBreakpoint getOriginalBreakpoint() {
return fBreakpoint;
}
/**
* Returns the original name of the type the associated breakpoint was set on.
* This can be different than the type being changed.
*
* @return
*/
protected String getOriginalBreakpointTypeName() {
return fTypeName;
}
/* (non-Javadoc)
* @see org.eclipse.ltk.core.refactoring.Change#initializeValidationData(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public void initializeValidationData(IProgressMonitor pm) {
// do nothing
}
/* (non-Javadoc)
* @see org.eclipse.ltk.core.refactoring.Change#isValid(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException, OperationCanceledException {
return new RefactoringStatus();
}
/* (non-Javadoc)
* @see org.eclipse.ltk.core.refactoring.Change#getModifiedElement()
*/
@Override
public Object getModifiedElement() {
return fBreakpoint;
}
/**
* Returns an array of ints representing the new line number, char start and char end
* of the member.
*
* @param member
* @return array of 3 ints or <code>null</code>
*/
protected int[] getNewLineNumberAndRange(IMember member) throws CoreException {
ISourceRange nameRange = member.getNameRange();
int offset = nameRange.getOffset();
int lineNumber = getNewLineNumber(member, offset);
return new int[]{lineNumber, offset, offset + nameRange.getLength()};
}
/**
* Returns the new line number of the from the source of the specified member's compilation unit
* @param member the member to query
* @param offset the offset
* @return the new line number
* @throws JavaModelException
*/
private int getNewLineNumber(IMember member, int offset) throws JavaModelException {
int lineNumber = getLineNumber();
Document document = new Document(member.getCompilationUnit().getSource());
try {
lineNumber = document.getLineOfOffset(offset);
} catch (BadLocationException e) {
}
return lineNumber;
}
/**
* Return the line number for the breakpoint
* @return the line number for the breakpoint
*/
protected int getLineNumber() {
return -1;
}
/**
* Returns the hit count for the breakpoint
* @return the hit count for the breakpoint
*/
protected int getHitCount() {
return fHitCount;
}
/**
* Returns the <code>IType</code> within the specified parent type given by simpleName
* @param parent
* @param simpleName
* @return the <code>IType</code> within the specified parent type given by simpleName
*/
public static IType getType(IJavaElement parent, String simpleName) {
switch (parent.getElementType()) {
case IJavaElement.COMPILATION_UNIT:
return ((ICompilationUnit)parent).getType(simpleName);
case IJavaElement.TYPE:
return ((IType)parent).getType(simpleName);
case IJavaElement.FIELD:
case IJavaElement.INITIALIZER:
case IJavaElement.METHOD:
return ((IMember)parent).getType(simpleName, -1);
}
return null;
}
/**
* Returns the <code>IJavaElement</code> contained within the specified parent one, or the parent one
* by default
* @param parent
* @param element
* @return the <code>IJavaElement</code> contained within the specified parent one, or the parent one
* by default
*/
public static IJavaElement findElement(IJavaElement parent, IJavaElement element) {
List<IJavaElement> children = getPath(element);
List<IJavaElement> path = getPath(parent);
IJavaElement currentElement = parent;
for (int i = children.size() - path.size() - 1; i >= 0; i--) {
IJavaElement child = children.get(i);
switch (child.getElementType()) {
case IJavaElement.PACKAGE_DECLARATION:
currentElement = ((ICompilationUnit)currentElement).getPackageDeclaration(child.getElementName());
break;
case IJavaElement.IMPORT_CONTAINER:
currentElement = ((ICompilationUnit)currentElement).getImportContainer();
break;
case IJavaElement.IMPORT_DECLARATION:
currentElement = ((IImportContainer)currentElement).getImport(child.getElementName());
break;
case IJavaElement.TYPE:
switch (currentElement.getElementType()) {
case IJavaElement.COMPILATION_UNIT:
currentElement = ((ICompilationUnit)currentElement).getType(child.getElementName());
break;
case IJavaElement.CLASS_FILE:
if (currentElement instanceof IOrdinaryClassFile) {
currentElement = ((IOrdinaryClassFile) currentElement).getType();
}
break;
case IJavaElement.TYPE:
currentElement = ((IType)currentElement).getType(child.getElementName());
break;
case IJavaElement.FIELD:
case IJavaElement.INITIALIZER:
case IJavaElement.METHOD:
currentElement = ((IMember)currentElement).getType(child.getElementName(), ((IMember)child).getOccurrenceCount());
break;
}
break;
case IJavaElement.INITIALIZER:
currentElement = ((IType)currentElement).getInitializer(((IMember)child).getOccurrenceCount());
break;
case IJavaElement.FIELD:
currentElement = ((IType)currentElement).getField(child.getElementName());
break;
case IJavaElement.METHOD:
currentElement = ((IType)currentElement).getMethod(child.getElementName(), ((IMethod)child).getParameterTypes());
break;
}
}
return currentElement;
}
/**
* Returns the path of the given element up to but not including its compilation unit,
* in bottom up order.
*
* @param element
* @return element's path
*/
private static List<IJavaElement> getPath(IJavaElement element) {
ArrayList<IJavaElement> children = new ArrayList<>();
while (element != null && element.getElementType() != IJavaElement.COMPILATION_UNIT) {
children.add(element);
element = element.getParent();
}
return children;
}
/**
* Returns a label for the given breakpoint generated from the JDI model presentation.
*
* @param breakpoint a breakpoint
* @return standard label for the breakpoint
*/
protected String getBreakpointLabel(IBreakpoint breakpoint) {
return JDIDebugUIPlugin.getDefault().getModelPresentation().getText(breakpoint);
}
/**
* Returns the original breakpoint working set names
* @return the original breakpoint working set names
*/
protected String getOriginalWorkingSets() {
return fWorkingSetNames;
}
}