blob: f1121fe4abf9c6f864a17552ead1cd378b5cfab0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2002 International Business Machines Corp. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
*
* Contributors:
* Martin Moebius
* *****************************************************************************/
package org.eclipse.jdt.ui.actions;
import java.lang.reflect.InvocationTargetException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.text.IRewriteTarget;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.window.Window;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.dialogs.CheckedTreeSelectionDialog;
import org.eclipse.ui.dialogs.ISelectionStatusValidator;
import org.eclipse.ui.help.WorkbenchHelp;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.ui.CodeGeneration;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jdt.ui.JavaElementSorter;
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
import org.eclipse.jdt.internal.corext.codemanipulation.IImportsStructure;
import org.eclipse.jdt.internal.corext.codemanipulation.ImportsStructure;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.JdtFlags;
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.actions.ActionMessages;
import org.eclipse.jdt.internal.ui.actions.ActionUtil;
import org.eclipse.jdt.internal.ui.actions.SelectionConverter;
import org.eclipse.jdt.internal.ui.actions.WorkbenchRunnableAdapter;
import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
import org.eclipse.jdt.internal.ui.util.ElementValidator;
import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
import org.eclipse.jdt.internal.ui.viewsupport.JavaElementLabels;
/**
* Creates delegate methods for a type's fields. Opens a dialog with a list of
* fields for which delegate methods can be generated. User is able to check or
* uncheck items before methods are generated.
* <p>
* Will open the parent compilation unit in a Java editor. The result is
* unsaved, so the user can decide if the changes are acceptable.
* <p>
* The action is applicable to structured selections containing elements
* of type <code>IField</code> or <code>IType</code>.
*
* <p>
* This class may be instantiated; it is not intended to be subclassed.
* </p>
*
* Contributors:
* Martin Moebius: m.moebius@gmx.de - bug: 28793
* @since 2.1
*/
public class AddDelegateMethodsAction extends SelectionDispatchAction {
private static final String DIALOG_TITLE = ActionMessages.getString("AddDelegateMethodsAction.error.title"); //$NON-NLS-1$
private CompilationUnitEditor fEditor;
/**
* Creates a new <code>AddDelegateMethodsAction</code>. The action requires
* that the selection provided by the site's selection provider is of type <code>
* org.eclipse.jface.viewers.IStructuredSelection</code>.
*
* @param site the site providing context information for this action
*/
public AddDelegateMethodsAction(IWorkbenchSite site) {
super(site);
setText(ActionMessages.getString("AddDelegateMethodsAction.label")); //$NON-NLS-1$
setDescription(ActionMessages.getString("AddDelegateMethodsAction.description")); //$NON-NLS-1$
setToolTipText(ActionMessages.getString("AddDelegateMethodsAction.tooltip")); //$NON-NLS-1$
WorkbenchHelp.setHelp(this, IJavaHelpContextIds.ADD_DELEGATE_METHODS_ACTION);
}
/**
* Note: This constructor is for internal use only. Clients should not call this constructor.
*/
public AddDelegateMethodsAction(CompilationUnitEditor editor) {
this(editor.getEditorSite());
fEditor = editor;
setEnabled(SelectionConverter.getInputAsCompilationUnit(editor) != null);
}
//---- Structured Viewer -----------------------------------------------------------
/* (non-Javadoc)
* Method declared on SelectionDispatchAction
*/
protected void selectionChanged(IStructuredSelection selection) {
try {
setEnabled(canEnable(selection));
} catch (JavaModelException e) {
// http://bugs.eclipse.org/bugs/show_bug.cgi?id=19253
if (JavaModelUtil.filterNotPresentException(e))
JavaPlugin.log(e);
setEnabled(false);
}
}
/* (non-Javadoc)
* Method declared on SelectionDispatchAction
*/
protected void run(IStructuredSelection selection) {
try {
IField[] selectedFields = getSelectedFields(selection);
if (canEnableOn(selectedFields)) {
run(selectedFields[0].getDeclaringType(), selectedFields, false);
return;
}
Object firstElement = selection.getFirstElement();
if (firstElement instanceof IType)
run((IType) firstElement, new IField[0], false);
else if (firstElement instanceof ICompilationUnit)
run(JavaElementUtil.getMainType((ICompilationUnit) firstElement), new IField[0], false);
} catch (CoreException e) {
ExceptionHandler.handle(e, getShell(), DIALOG_TITLE, ActionMessages.getString("AddDelegateMethodsAction.error.actionfailed")); //$NON-NLS-1$
}
}
private boolean canEnable(IStructuredSelection selection) throws JavaModelException {
if (canEnableOn(getSelectedFields(selection)))
return true;
if ((selection.size() == 1) && (selection.getFirstElement() instanceof IType))
return canEnableOn((IType) selection.getFirstElement());
if ((selection.size() == 1) && (selection.getFirstElement() instanceof ICompilationUnit))
return canEnableOn(JavaElementUtil.getMainType((ICompilationUnit) selection.getFirstElement()));
return false;
}
private static boolean canEnableOn(IType type) throws JavaModelException {
if (type == null || type.getCompilationUnit() == null)
return false;
return canEnableOn(type.getFields());
}
private static boolean canEnableOn(IField[] fields) throws JavaModelException {
if (fields == null) {
return false;
}
int count = 0;
for (int i = 0; i < fields.length; i++) {
if (!hasPrimitiveType(fields[i]) || isArray(fields[i])) {
count++;
}
}
return (count > 0);
}
/*
* Returns fields in the selection or <code>null</code> if the selection is
* empty or not valid.
*/
private IField[] getSelectedFields(IStructuredSelection selection) {
List elements = selection.toList();
int nElements = elements.size();
if (nElements > 0) {
IField[] res = new IField[nElements];
ICompilationUnit cu = null;
for (int i = 0; i < nElements; i++) {
Object curr = elements.get(i);
if (curr instanceof IField) {
IField fld = (IField) curr;
if (i == 0) {
// remember the cu of the first element
cu = fld.getCompilationUnit();
if (cu == null) {
return null;
}
} else if (!cu.equals(fld.getCompilationUnit())) {
// all fields must be in the same CU
return null;
}
try {
if (fld.getDeclaringType().isInterface()) {
// no delegates for fields in interfaces or fields with
return null;
}
} catch (JavaModelException e) {
JavaPlugin.log(e);
return null;
}
res[i] = fld;
} else {
return null;
}
}
return res;
}
return null;
}
private void run(IType type, IField[] preselected, boolean editor) throws CoreException {
if (!ElementValidator.check(type, getShell(), DIALOG_TITLE, editor))
return;
if (!ActionUtil.isProcessable(getShell(), type))
return;
if(!canEnableOn(type)){
MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.getString("AddDelegateMethodsAction.not_applicable")); //$NON-NLS-1$
return;
}
showUI(type, preselected);
}
//---- Java Editior --------------------------------------------------------------
/* (non-Javadoc)
* Method declared on SelectionDispatchAction
*/
protected void selectionChanged(ITextSelection selection) {
}
/* (non-Javadoc)
* Method declared on SelectionDispatchAction
*/
protected void run(ITextSelection selection) {
try {
IJavaElement input= SelectionConverter.getInput(fEditor);
if (!ActionUtil.isProcessable(getShell(), input))
return;
IJavaElement[] elements = SelectionConverter.codeResolve(fEditor);
if (elements.length == 1 && (elements[0] instanceof IField)) {
IField field = (IField) elements[0];
run(field.getDeclaringType(), new IField[] { field }, true);
return;
}
IJavaElement element = SelectionConverter.getElementAtOffset(fEditor);
if (element != null) {
IType type = (IType) element.getAncestor(IJavaElement.TYPE);
if (type != null) {
if (type.getFields().length > 0) {
run(type, new IField[0], true);
return;
}
}
}
MessageDialog.openInformation(getShell(), DIALOG_TITLE, ActionMessages.getString("AddDelegateMethodsAction.not_applicable")); //$NON-NLS-1$
} catch (CoreException e) {
ExceptionHandler.handle(e, getShell(), DIALOG_TITLE, ActionMessages.getString("AddDelegateMethodsAction.error.actionfailed")); //$NON-NLS-1$
}
}
//---- Helpers -------------------------------------------------------------------
/**build ui */
private void showUI(IType type, IField[] preselected) {
try {
FieldContentProvider provider = new FieldContentProvider(type);
Methods2FieldLabelProvider methodLabel = new Methods2FieldLabelProvider();
CheckedTreeSelectionDialog dialog = new CheckedTreeSelectionDialog(getShell(), methodLabel, provider);
dialog.setValidator(new ISelectionStatusValidator() {
public IStatus validate(Object[] selection) {
StatusInfo state = new StatusInfo();
if (selection != null && selection.length > 0) {
HashSet map = new HashSet(selection.length);
int count = 0;
for (int i = 0; i < selection.length; i++) {
Object key = selection[i];
if (selection[i] instanceof Methods2Field) {
count++;
try {
key = createSignatureKey(((Methods2Field) selection[i]).fMethod);
} catch (JavaModelException e) {
return new StatusInfo(StatusInfo.ERROR, e.toString());
}
}
if (!map.add(key)) { //$NON-NLS-1$
state = new StatusInfo(IStatus.ERROR, ActionMessages.getString("AddDelegateMethodsAction.duplicate_methods")); //$NON-NLS-1$
break;
} else {
String message;
if (count == 1) {
message = ActionMessages.getFormattedString("AddDelegateMethodsAction.selectioninfo.one", String.valueOf(count)); //$NON-NLS-1$
} else {
message = ActionMessages.getFormattedString("AddDelegateMethodsAction.selectioninfo.more", String.valueOf(count)); //$NON-NLS-1$
}
state = new StatusInfo(IStatus.INFO, message);
}
}
}
return state;
}
});
dialog.setSorter(new Methods2FieldSorter());
dialog.setInput(provider);
dialog.setContainerMode(true);
dialog.setMessage(ActionMessages.getString("AddDelegateMethodsAction.message")); //$NON-NLS-1$
dialog.setTitle(ActionMessages.getString("AddDelegateMethodsAction.title")); //$NON-NLS-1$
dialog.setExpandedElements(preselected);
int result = dialog.open();
if (result == Window.OK) {
Object[] o = dialog.getResult();
if (o == null)
return;
ArrayList methods = new ArrayList(o.length);
for (int i = 0; i < o.length; i++) {
if (o[i] instanceof Methods2Field)
methods.add(o[i]);
}
IEditorPart part = EditorUtility.openInEditor(type);
type = (IType) JavaModelUtil.toWorkingCopy(type);
IRewriteTarget target= (IRewriteTarget) part.getAdapter(IRewriteTarget.class);
IMethod[] createdMethods= null;
try {
if (target != null) {
target.beginCompoundChange();
}
createdMethods= processResults(methods, type);
} finally {
if (target != null) {
target.endCompoundChange();
}
}
if (createdMethods != null && createdMethods.length > 0) {
type.getCompilationUnit().reconcile();
EditorUtility.revealInEditor(part, createdMethods[0]);
}
}
} catch (CoreException e) {
ExceptionHandler.handle(e, DIALOG_TITLE, ActionMessages.getString("AddDelegateMethodsAction.error.actionfailed")); //$NON-NLS-1$
} catch (InvocationTargetException e) {
ExceptionHandler.handle(e, DIALOG_TITLE, ActionMessages.getString("AddDelegateMethodsAction.error.actionfailed")); //$NON-NLS-1$
}
}
/**Runnable for the operation*/
private static class ResultRunner implements IWorkspaceRunnable {
/**List with Methods2Field*/
List fList = null;
/**Type to add methods to*/
IType fType = null;
List fCreatedMethods;
public ResultRunner(List resultList, IType type) {
fList = resultList;
fType = type;
fCreatedMethods = new ArrayList();
}
public IMethod[] getCreatedMethods() {
return (IMethod[]) fCreatedMethods.toArray(new IMethod[fCreatedMethods.size()]);
}
public void run(IProgressMonitor monitor) throws CoreException {
String message = ActionMessages.getFormattedString("AddDelegateMethodsAction.monitor.message", String.valueOf(fList.size())); //$NON-NLS-1$
monitor.setTaskName(message);
monitor.beginTask("", fList.size()); //$NON-NLS-1$
// the preferences
CodeGenerationSettings settings = JavaPreferencesSettings.getCodeGenerationSettings();
boolean addComments = settings.createComments;
// already existing methods
IMethod[] existingMethods = fType.getMethods();
//the delemiter used
String lineDelim = StubUtility.getLineDelimiterUsed(fType);
// the indent used + 1
int indent = StubUtility.getIndentUsed(fType) + 1;
// perhaps we have to add import statements
final ImportsStructure imports =
new ImportsStructure(fType.getCompilationUnit(), settings.importOrder, settings.importThreshold, true);
for (int i = 0; i < fList.size(); i++) {
//long time=System.currentTimeMillis();
//check for cancel each iteration
if (monitor.isCanceled()) {
if (i > 0) {
imports.create(false, null);
}
return;
}
ITypeHierarchy typeHierarchy = fType.newSupertypeHierarchy(null);
String content = null;
Methods2Field wrapper = (Methods2Field) fList.get(i);
IMethod curr = wrapper.fMethod;
IField field = wrapper.fField;
monitor.subTask(JavaElementLabels.getElementLabel(curr, JavaElementLabels.M_PARAMETER_TYPES));
IMethod overwrittenMethod =
JavaModelUtil.findMethodImplementationInHierarchy(
typeHierarchy,
fType,
curr.getElementName(),
curr.getParameterTypes(),
curr.isConstructor());
if (overwrittenMethod == null) {
content = createStub(field, curr, addComments, overwrittenMethod, imports);
} else {
// we could ask before overwriting final methods
IMethod declaration =
JavaModelUtil.findMethodDeclarationInHierarchy(
typeHierarchy,
fType,
curr.getElementName(),
curr.getParameterTypes(),
curr.isConstructor());
content = createStub(field, declaration, addComments, overwrittenMethod, imports);
}
IJavaElement sibling = null;
IMethod existing =
JavaModelUtil.findMethod(
curr.getElementName(),
curr.getParameterTypes(),
curr.isConstructor(),
existingMethods);
if (existing != null) {
// we could ask before replacing a method
continue;
} else if (curr.isConstructor() && existingMethods.length > 0) {
// add constructors at the beginning
sibling = existingMethods[0];
}
String formattedContent = StubUtility.codeFormat(content, indent, lineDelim) + lineDelim;
IMethod created = fType.createMethod(formattedContent, sibling, true, null);
fCreatedMethods.add(created);
monitor.worked(1);
//System.out.println(System.currentTimeMillis()-time +" for #"+i);
}
imports.create(false, null);
}
private String createStub(
IField field,
IMethod curr,
boolean addComment,
IMethod overridden,
IImportsStructure imports)
throws CoreException {
String methodName = curr.getElementName();
String[] paramNames = curr.getParameterNames();
String returnTypSig = curr.getReturnType();
StringBuffer buf = new StringBuffer();
if (addComment) {
String comment =
CodeGeneration.getMethodComment(
fType.getCompilationUnit(),
fType.getElementName(),
methodName,
paramNames,
curr.getExceptionTypes(),
returnTypSig,
overridden,
String.valueOf('\n'));
if (comment != null) {
buf.append(comment);
}
}
String methodDeclaration = null;
if (fType.isClass()) {
StringBuffer body = new StringBuffer();
if (!Signature.SIG_VOID.equals(returnTypSig)) {
body.append("return "); //$NON-NLS-1$
}
if (JdtFlags.isStatic(curr)) {
body.append(resolveTypeOfField(field).getElementName());
} else {
body.append(field.getElementName());
}
body.append('.').append(methodName).append('(');
for (int i = 0; i < paramNames.length; i++) {
body.append(paramNames[i]);
if (i < paramNames.length - 1)
body.append(',');
}
body.append(");"); //$NON-NLS-1$
methodDeclaration = body.toString();
}
StubUtility.genMethodDeclaration(fType.getElementName(), curr, methodDeclaration, imports, buf);
return buf.toString();
}
}
/**creates methods in class*/
private IMethod[] processResults(List list, IType type) throws InvocationTargetException {
if (list.size() == 0)
return null;
ResultRunner resultRunner = new ResultRunner(list, type);
IRunnableContext runnableContext = new ProgressMonitorDialog(getShell());
try {
runnableContext.run(false, true, new WorkbenchRunnableAdapter(resultRunner));
} catch (InterruptedException e) {
// cancel pressed
return null;
}
return resultRunner.getCreatedMethods();
}
/** The model (content provider) for the field-methods tree */
private static class FieldContentProvider implements ITreeContentProvider {
private Map fTreeMap = null;
private Map fFieldMap = null;
private Map fFilter = null;
/**
* Method FieldContentProvider.
* @param type outer type to insert in (hide final methods in tree))
*/
FieldContentProvider(IType type) throws JavaModelException {
//hiding final methods
fFilter = new HashMap();
//mapping name to methods
fTreeMap = new TreeMap();
//mapping name to field
fFieldMap = new HashMap();
buildModel(type);
}
private void buildModel(IType type) throws JavaModelException {
IField[] fields = type.getFields();
//build map to filter against
IMethod[] finMeths = resolveFinalMethods(type);
for (int i = 0; i < finMeths.length; i++) {
fFilter.put(createSignatureKey(finMeths[i]), finMeths[i]);
}
IMethod[] filter = type.getMethods();
for (int i = 0; i < filter.length; i++) {
fFilter.put(createSignatureKey(filter[i]), filter[i]);
}
for (int i = 0; i < fields.length; i++) {
IType fieldType = resolveTypeOfField(fields[i]);
if (fieldType == null)
continue;
IMethod[] methods = resolveMethodsHierarchy(fieldType);
List accessMethods = new ArrayList();
//show public methods; hide constructors + final methods
for (int j = 0; j < methods.length; j++) {
boolean publicField = JdtFlags.isPublic(methods[j]);
boolean constructor = methods[j].isConstructor();
boolean finalExist = fFilter.get(createSignatureKey(methods[j])) != null;
if (publicField && !constructor && !finalExist)
accessMethods.add(new Methods2Field(methods[j], fields[i]));
}
Object[] m = accessMethods.toArray();
Methods2Field[] mf = new Methods2Field[m.length];
for (int j = 0; j < m.length; j++) {
mf[j] = (Methods2Field) m[j];
}
fTreeMap.put(fields[i].getElementName(), mf);
fFieldMap.put(fields[i].getElementName(), fields[i]);
}
}
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof IField) {
return (Object[]) fTreeMap.get(((IField) parentElement).getElementName());
}
return null;
}
public Object getParent(Object element) {
return null;
}
public boolean hasChildren(Object element) {
return element instanceof IField;
}
public Object[] getElements(Object inputElement) {
if ((inputElement != null) && (inputElement instanceof FieldContentProvider)) {
Object[] o = fTreeMap.keySet().toArray();
Object[] fields = new Object[o.length];
for (int i = 0; i < o.length; i++) {
fields[i] = fFieldMap.get(o[i]);
}
return fields;
}
return null;
}
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
/**to map from dialog results to corresponding fields*/
private static class Methods2Field {
public Methods2Field(IMethod method, IField field) {
fMethod = method;
fField = field;
}
/**method to wrap*/
IMethod fMethod = null;
/**field where method is declared*/
IField fField = null;
}
/**just to wrap JavaElementLabelProvider using my Methods2Field*/
private static class Methods2FieldLabelProvider implements ILabelProvider {
/**Delegate to forward calls*/
JavaElementLabelProvider fMethodLabel = null;
public Methods2FieldLabelProvider() {
fMethodLabel = new JavaElementLabelProvider();
fMethodLabel.turnOn(JavaElementLabelProvider.SHOW_TYPE);
}
public Image getImage(Object element) {
if (element instanceof Methods2Field) {
Methods2Field wrapper = (Methods2Field) element;
return fMethodLabel.getImage(wrapper.fMethod);
} else if (element instanceof IJavaElement) {
return fMethodLabel.getImage(element);
}
return null;
}
public String getText(Object element) {
if (element instanceof Methods2Field) {
Methods2Field wrapper = (Methods2Field) element;
return fMethodLabel.getText(wrapper.fMethod);
} else if (element instanceof IJavaElement) {
return fMethodLabel.getText(element);
}
return null;
}
public void addListener(ILabelProviderListener listener) {
fMethodLabel.addListener(listener);
}
public void dispose() {
fMethodLabel.dispose();
}
public boolean isLabelProperty(Object element, String property) {
return fMethodLabel.isLabelProperty(element, property);
}
public void removeListener(ILabelProviderListener listener) {
fMethodLabel.removeListener(listener);
}
}
/** and a delegate for the sorter*/
private static class Methods2FieldSorter extends ViewerSorter {
JavaElementSorter fSorter = new JavaElementSorter();
public int category(Object element) {
if (element instanceof Methods2Field)
element = ((Methods2Field) element).fMethod;
return fSorter.category(element);
}
public int compare(Viewer viewer, Object e1, Object e2) {
if (e1 instanceof Methods2Field)
e1 = ((Methods2Field) e1).fMethod;
if (e2 instanceof Methods2Field)
e2 = ((Methods2Field) e2).fMethod;
return fSorter.compare(viewer, e1, e2);
}
public Collator getCollator() {
return fSorter.getCollator();
}
}
/**return all methods of all super types, minus dups*/
private static IMethod[] resolveMethodsHierarchy(IType type) throws JavaModelException {
Map map = new HashMap();
IType[] superTypes = JavaModelUtil.getAllSuperTypes(type, new NullProgressMonitor());
addMethodsToMapping(map, type);
for (int i = 0; i < superTypes.length; i++) {
addMethodsToMapping(map, superTypes[i]);
}
return (IMethod[]) map.values().toArray(new IMethod[map.values().size()]);
}
private static void addMethodsToMapping(Map map, IType type) throws JavaModelException {
IMethod[] methods = type.getMethods();
for (int i = 0; i < methods.length; i++) {
map.put(createSignatureKey(methods[i]), methods[i]);
}
}
/**returns a non null array of final methods of the type*/
private static IMethod[] resolveFinalMethods(IType type) throws JavaModelException {
//Interfaces are java.lang.Objects
if (type.isInterface()) {
type = getJavaLangObject(type.getJavaProject());//$NON-NLS-1$
}
IMethod[] methods = resolveMethodsHierarchy(type);
List list = new ArrayList(methods.length);
for (int i = 0; i < methods.length; i++) {
boolean isFinal = Flags.isFinal(methods[i].getFlags());
if (isFinal)
list.add(methods[i]);
}
return (IMethod[]) list.toArray(new IMethod[list.size()]);
}
/**creates a key used for hashmaps for a method signature (name+arguments(fqn))*/
private static String createSignatureKey(IMethod method) throws JavaModelException {
StringBuffer buffer = new StringBuffer();
buffer.append(method.getElementName());
String[] args = method.getParameterTypes();
for (int i = 0; i < args.length; i++) {
String signature;
if (isUnresolved(args[i])) {
int acount = Signature.getArrayCount(args[i]);
if (acount > 0) {
String arg = args[i];
int index = arg.lastIndexOf(Signature.C_ARRAY);
arg = arg.substring(index + 1);
signature = Signature.toString(arg);
} else {
signature = Signature.toString(args[i]);
}
String[][] fqn = method.getDeclaringType().resolveType(signature);
if (fqn != null) {
buffer.append(fqn[0][0]).append('.').append(fqn[0][1]);
//TODO check for [][]
for (int j = 0; j < acount; j++) {
buffer.append("[]"); //$NON-NLS-1$
}
}
}else{
signature=Signature.toString(args[i]);
buffer.append(signature);
}
}
return buffer.toString();
}
private static boolean isUnresolved(String signature) {
boolean flag = false;
char c=Signature.getElementType(signature).charAt(0);
boolean primitive=(c!= Signature.C_RESOLVED && c != Signature.C_UNRESOLVED);
if(primitive)
return flag;
int acount = Signature.getArrayCount(signature);
if (acount > 0) {
int index = signature.lastIndexOf(Signature.C_ARRAY);
c = signature.charAt(index + 1);
} else {
c = signature.charAt(0);
}
switch (c) {
case Signature.C_RESOLVED :
flag=false;
break;
case Signature.C_UNRESOLVED :
flag=true;
break;
default :
throw new IllegalArgumentException();
}
return flag;
}
private static boolean hasPrimitiveType(IField field) throws JavaModelException {
String signature = field.getTypeSignature();
char first = Signature.getElementType(signature).charAt(0);
return (first != Signature.C_RESOLVED && first != Signature.C_UNRESOLVED);
}
/**
* returns Type of field.
*
* if field is primitve null is returned.
* if field is array java.lang.Object is returned.
**/
private static IType resolveTypeOfField(IField field) throws JavaModelException {
boolean isPrimitive = hasPrimitiveType(field);
boolean isArray = isArray(field);
if (!isPrimitive && !isArray) {
String typeName = JavaModelUtil.getResolvedTypeName(field.getTypeSignature(), field.getDeclaringType());
//if the cu has errors its possible no type name is resolved
return typeName != null ? field.getJavaProject().findType(typeName) : null;
} else if (isArray) {
return getJavaLangObject(field.getJavaProject());
}
return null;
}
private static IType getJavaLangObject(IJavaProject project) throws JavaModelException {
return JavaModelUtil.findType(project, "java.lang.Object");//$NON-NLS-1$
}
private static boolean isArray(IField field) throws JavaModelException {
return Signature.getArrayCount(field.getTypeSignature()) > 0;
}
}