org.eclipse.objectteams.otdt.internal.refactoring.util.RefactoringUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.objectteams.otdt.internal.refactoring.util.RefactoringUtil.java

Source

/**********************************************************************
 * This file is part of "Object Teams Development Tooling"-Software
 * 
 * Copyright 2004, 2014 Fraunhofer Gesellschaft, Munich, Germany,
 * for its Fraunhofer Institute and Computer Architecture and Software
 * Technology (FIRST), Berlin, Germany and Technical University Berlin,
 * Germany.
 * 
 * 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
 * 
 * Please visit http://www.objectteams.org for updates and contact.
 * 
 * Contributors:
 * Fraunhofer FIRST - Initial API and implementation
 * Technical University Berlin - Initial API and implementation
 * Johannes Gebauer - Initial API and implementation
 **********************************************************************/
package org.eclipse.objectteams.otdt.internal.refactoring.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.Flags;
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.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
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.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.AbstractMethodMappingDeclaration;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.CallinMappingDeclaration;
import org.eclipse.jdt.core.dom.CalloutMappingDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodMappingElement;
import org.eclipse.jdt.core.dom.MethodSpec;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.RoleTypeDeclaration;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.corext.Corext;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.refactoring.Checks;
import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
import org.eclipse.jdt.internal.corext.refactoring.rename.RippleMethodFinder2;
import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.jdt.internal.corext.util.JdtFlags;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
import org.eclipse.objectteams.otdt.core.IMethodMapping;
import org.eclipse.objectteams.otdt.core.IOTType;
import org.eclipse.objectteams.otdt.core.IRoleType;
import org.eclipse.objectteams.otdt.core.OTModelManager;
import org.eclipse.objectteams.otdt.core.TypeHelper;
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
import org.eclipse.objectteams.otdt.core.hierarchy.InheritedMethodsRequestor;
import org.eclipse.objectteams.otdt.core.hierarchy.OTTypeHierarchyTraverser;
import org.eclipse.objectteams.otdt.core.search.OTSearchEngine;
import org.eclipse.objectteams.otdt.core.search.OTSearchRequestor;
import org.eclipse.objectteams.otdt.internal.refactoring.OTRefactoringPlugin;
import org.eclipse.objectteams.otdt.internal.refactoring.corext.OTRefactoringCoreMessages;
import org.eclipse.objectteams.otdt.internal.refactoring.corext.base.OTRefactoringStatusCodes;
import org.eclipse.objectteams.otdt.internal.refactoring.otrefactorings.OTRefactoringMessages;
import org.eclipse.osgi.util.NLS;

/**
 * This utility class is a part of the OT/J refactoring adaptation. It contains
 * some OT refactoring related helper methods.
 * 
 * @author brcan
 */
@SuppressWarnings("restriction")
public class RefactoringUtil implements ITeamConstants {
    /**
     * Checks whether the top-level type of the given compilation unit is a
     * regular class or a team class.
     * 
     * @param compUnit
     *            the given compilation unit
     * @param str
     *            the string describing the error
     * @return the refactoring status
     * @throws JavaModelException
     */
    public static RefactoringStatus checkOOClass(ICompilationUnit compUnit, String str) throws JavaModelException {
        RefactoringStatus status = new RefactoringStatus();
        IType type = robustFindPrimaryType(compUnit);

        if (Flags.isTeam(type.getFlags())) {
            status.addFatalError(OTRefactoringCoreMessages.getString(str));
        }
        return status;
    }

    /*
     * Make a best guess to find the primary type of a CU even if names do not
     * match.
     */
    private static IType robustFindPrimaryType(ICompilationUnit compUnit) {
        IType type = compUnit.findPrimaryType();
        if (type != null)
            return type;
        IType[] types;
        try {
            types = compUnit.getTypes();
            if (types != null) {
                for (IType type2 : types) {
                    if (Flags.isPublic(type2.getFlags()))
                        return type2;
                }
                if (types.length > 0)
                    return types[0];
            }
        } catch (JavaModelException e) {
            // nothing useful found, return null below
        }
        return null;
    }

    /**
     * Returns all role types contained in the given project and related
     * projects.
     * 
     * @param project
     *            the given project
     * @param monitor
     *            the progress monitor
     * @return an array of role types
     */
    public static IOTType[] getAllRoleClasses(IJavaProject project, IProgressMonitor monitor)
            throws JavaModelException {
        OTSearchRequestor requestor = new OTSearchRequestor();
        try {
            SearchPattern rolePattern = OTSearchEngine.createRoleTypePattern(IJavaSearchConstants.TYPE,
                    SearchPattern.R_EXACT_MATCH);
            IJavaElement[] relevantProjects = getRelevantProjects(project);
            IJavaSearchScope scope = OTSearchEngine.createOTSearchScope(relevantProjects, true);
            OTSearchEngine engine = new OTSearchEngine();
            engine.search(rolePattern, scope, requestor, monitor);
        } catch (CoreException ex) {
            throw new JavaModelException(ex);
        }

        return requestor.getOTTypes();
    }

    public static ArrayList<IRoleType> getAllRolesForBase(IType baseType) throws CoreException {
        OTSearchEngine engine = new OTSearchEngine();
        IJavaSearchScope searchScope = SearchEngine.createWorkspaceScope();
        SearchPattern pattern = SearchPattern.createPattern(baseType, IJavaSearchConstants.PLAYEDBY_REFERENCES);
        final ArrayList<IRoleType> roles = new ArrayList<IRoleType>();
        if (pattern == null)
            OTRefactoringPlugin.getInstance().getLog()
                    .log(new Status(Status.ERROR, OTRefactoringPlugin.PLUGIN_ID, "Error creating pattern")); //$NON-NLS-1$
        else
            engine.search(pattern, searchScope, new SearchRequestor() {
                public void acceptSearchMatch(SearchMatch match) throws CoreException {
                    Object element = match.getElement();
                    if (element instanceof IType)
                        roles.add((IRoleType) OTModelManager.getOTElement((IType) element));
                }
            }, null);
        return roles;
    }

    private static IJavaElement[] getRelevantProjects(IJavaProject srcProject) throws JavaModelException {
        List<IJavaProject> relevantProjects = new ArrayList<IJavaProject>();
        relevantProjects.add(srcProject); // this one is relevant for sure

        IJavaProject[] allJavaProjects = JavaModelManager.getJavaModelManager().getJavaModel().getJavaProjects();
        for (int idx = 0; idx < allJavaProjects.length; idx++) {
            IJavaProject prj = allJavaProjects[idx];
            if (prj.isOnClasspath(srcProject)) {
                relevantProjects.add(prj);
            }
        }
        return relevantProjects.toArray(new IJavaElement[relevantProjects.size()]);
    }

    /**
     * Returns all bound base types of the given role types, that are declared
     * by playedBy.
     * 
     * @param roleTypes
     *            an array of IRoleTypes
     * @return a list of bound base types
     * @throws JavaModelException
     */
    public static ArrayList<IType> getAllDeclaredBaseTypes(IOTType[] roleTypes) throws JavaModelException {
        ArrayList<IType> baseTypes = new ArrayList<IType>();
        for (int idx = 0; idx < roleTypes.length; idx++) {
            // IRoleType roleType =
            // (IRoleType)OTModelManager.getOTElement(roleTypes[idx]);
            IRoleType roleType = (IRoleType) roleTypes[idx];
            if (roleType.getBaseclassName() == null) {
                continue;
            }
            try {
                IType baseType = roleType.getBaseClass();
                if (baseType != null && !baseTypes.contains(baseType)) {
                    baseTypes.add(baseType);
                }
            } catch (JavaModelException jme) {
                // not resolved;
            }
        }
        return baseTypes;
    }

    public static IMethod[] hierarchyDeclaresMethodName(IProgressMonitor pm, IMethod method, String newName)
            throws CoreException {
        Set<IMethod> result = new HashSet<IMethod>();
        IType type = method.getDeclaringType();
        ITypeHierarchy hier = type.newTypeHierarchy(pm);
        IMethod foundMethod = Checks.findMethod(newName, method.getParameterTypes().length, false, type);
        if (foundMethod != null) {
            result.add(foundMethod);
        }
        IMethod[] foundInHierarchyClasses = classesDeclareMethodName(hier, Arrays.asList(hier.getAllClasses()),
                method, newName);
        if (foundInHierarchyClasses != null) {
            result.addAll(Arrays.asList(foundInHierarchyClasses));
        }
        IType[] implementingClasses = hier.getImplementingClasses(type);
        IMethod[] foundInImplementingClasses = classesDeclareMethodName(hier, Arrays.asList(implementingClasses),
                method, newName);
        if (foundInImplementingClasses != null) {
            result.addAll(Arrays.asList(foundInImplementingClasses));
        }
        return result.toArray(new IMethod[result.size()]);
    }

    private static IMethod[] classesDeclareMethodName(ITypeHierarchy hier, List<IType> classes, IMethod method,
            String newName) throws CoreException {
        Set<IMethod> result = new HashSet<IMethod>();
        IType type = method.getDeclaringType();
        List<IType> subtypes = Arrays.asList(hier.getAllSubtypes(type));

        int parameterCount = method.getParameterTypes().length;
        boolean isMethodPrivate = JdtFlags.isPrivate(method);

        for (Iterator<IType> iter = classes.iterator(); iter.hasNext();) {
            IType clazz = iter.next();
            IMethod[] methods = clazz.getMethods();
            boolean isSubclass = subtypes.contains(clazz);
            for (int j = 0; j < methods.length; j++) {
                IMethod foundMethod = Checks.findMethod(newName, parameterCount, false,
                        new IMethod[] { methods[j] });
                if (foundMethod == null) {
                    continue;
                }
                if (isSubclass || type.equals(clazz)) {
                    result.add(foundMethod);
                } else if ((!isMethodPrivate) && (!JdtFlags.isPrivate(methods[j]))) {
                    result.add(foundMethod);
                }
            }
        }
        return result.toArray(new IMethod[result.size()]);
    }

    /**
     * Checks if the given method is declared in an interface. If the method's
     * declaring type is an interface the method returns <code>false</code> if
     * it is only declared in that interface.
     */
    public static IMethod isDeclaredInInterface(IMethod method, ITypeHierarchy hierarchy, IProgressMonitor pm)
            throws JavaModelException {
        assert isVirtual(method);
        try {
            IType[] classes = hierarchy.getAllClasses();
            IProgressMonitor subPm = new SubProgressMonitor(pm, 3);
            subPm.beginTask("", classes.length); //$NON-NLS-1$
            for (int idxAllHierarchyClasses = 0; idxAllHierarchyClasses < classes.length; idxAllHierarchyClasses++) {
                ITypeHierarchy superTypes = classes[idxAllHierarchyClasses].newSupertypeHierarchy(subPm);
                IType[] superinterfaces = superTypes.getAllSuperInterfaces(classes[idxAllHierarchyClasses]);

                for (int idxSuperInterfaces = 0; idxSuperInterfaces < superinterfaces.length; idxSuperInterfaces++) {
                    IMethod found = Checks.findSimilarMethod(method, superinterfaces[idxSuperInterfaces]);
                    if (found != null && !found.equals(method))
                        return found;
                }
                subPm.worked(1);
            }
            return null;
        } finally {
            pm.done();
        }
    }

    public static boolean isVirtual(IMethod method) throws JavaModelException {
        IType declaringType = method.getDeclaringType();

        if (TypeHelper.isRole(declaringType.getFlags())) {
            if (method.isConstructor())
                return false;
            // note: private role method is virtual
            // if (JdtFlags.isPrivate(method))
            // return false;
            if (JdtFlags.isStatic(method))
                return false;
        } else {
            if (method.isConstructor())
                return false;
            if (JdtFlags.isPrivate(method))
                return false;
            if (JdtFlags.isStatic(method))
                return false;
        }
        return true;
    }

    public static IMethod overridesAnotherMethod(IMethod method, ITypeHierarchy hier, IProgressMonitor pm)
            throws JavaModelException {
        IType declaringType = method.getDeclaringType();
        InheritedMethodsRequestor requestor = new InheritedMethodsRequestor(declaringType, true, true);
        OTTypeHierarchyTraverser traverser = new OTTypeHierarchyTraverser(hier, requestor, false/*implicitFirst*/,
                false/*focusType*/, false/*rootClass*/);

        traverser.traverse(pm);
        IMethod[] collectedMethods = requestor.getResult();

        for (int idx = collectedMethods.length - 1; idx >= 0; idx--) {
            if (method.isSimilar(collectedMethods[idx])) {
                return collectedMethods[idx];
            }
        }
        return null;
    }

    public static boolean isRoleMethod(IMethod method) throws JavaModelException {
        IType type = method.getDeclaringType();
        IOTType otType = OTModelManager.getOTElement(type);

        if (otType == null) {
            return false;
        } else if (otType.isRole()) {
            return true;
        } else {
            return false;
        }
    }

    public static String stripOffJavaSuffix(String compUnit) {
        int dot = compUnit.lastIndexOf('.');
        return compUnit.substring(0, dot);
    }

    /**
     * Returns the corresponding DOM-AST node for the given role type.
     * 
     * @param role
     *            the given role type
     * @return node of type RoleTypeDeclaration
     * @throws JavaModelException
     */
    public static RoleTypeDeclaration getRoleClassDeclaration(IMember role) throws JavaModelException {
        ASTNode result = getASTNode(role, RoleTypeDeclaration.class);
        return (RoleTypeDeclaration) result;
    }

    /**
     * Returns the corresponding DOM-AST node for the given method.
     * 
     * @param method
     *            the given method
     * @return node of type MethodDeclaration
     * @throws JavaModelException
     */
    public static MethodDeclaration getMethodDeclaration(IMember method) throws JavaModelException {
        ASTNode result = getASTNode(method, MethodDeclaration.class);
        return (MethodDeclaration) result;
    }

    public static IMethod[] getInheritedMethods(IOTType iotType, boolean includeFocusType, boolean includeRootClass,
            boolean checkVisibility, IProgressMonitor pm) throws JavaModelException {
        return getInheritedMethods((IType) iotType.getCorrespondingJavaElement(), includeFocusType,
                includeRootClass, checkVisibility, pm);
    }

    public static IMethod[] getInheritedMethods(IType type, boolean includeFocusType, boolean includeRootClass,
            boolean checkVisibility, IProgressMonitor pm) throws JavaModelException {
        InheritedMethodsRequestor requestor = new InheritedMethodsRequestor(type, false, checkVisibility);
        OTTypeHierarchyTraverser traverser = new OTTypeHierarchyTraverser(null, // let traverser create the type hierarchy
                requestor, true/*implicitFirst*/, includeFocusType, includeRootClass);

        traverser.traverse(pm);
        return requestor.getResult();
    }

    /**
     * Determines the focus type, i.e. the destination type of the refactored
     * element (e.g. the destination type for an extracted or moved method).
     * 
     * @param topLevelType
     *            the top-level type of the destination compilation unit
     * @param destinationType
     *            the destination type node
     * @return the focus type, i.e. either a regular class (including team) or a
     *         role class
     */
    public static IType determineFocusType(IType topLevelType, ASTNode destinationType) {
        // if the destination of the extracted/moved code fragment/element is a
        // role type,
        // this role is the focus type...
        if (destinationType instanceof RoleTypeDeclaration) {
            RoleTypeDeclaration roleTypeDecl = (RoleTypeDeclaration) destinationType;
            ITypeBinding roleTypeBinding = ASTNodes.getTypeBinding(roleTypeDecl.getName());
            // if role is declared in the top-level type, get it...
            if (roleTypeBinding != null) {
                // Note: use String-based comparison for ITypeBinding <-> IType:
                String topLevelName = topLevelType.getFullyQualifiedName();
                String roleName = roleTypeBinding.getQualifiedName();
                if (roleName.equals(topLevelName))
                    return topLevelType; // top level = focus (RoFi)
                if (roleTypeBinding.getDeclaringClass().getQualifiedName().equals(topLevelName)) {
                    String simpleRoleName = roleTypeBinding.getName();
                    // role name very likely starts with __OT__, strip it off:
                    if (simpleRoleName.startsWith(IOTConstants.OT_DELIM))
                        simpleRoleName = simpleRoleName.substring(IOTConstants.OT_DELIM_LEN);
                    return TypeHelper.findRoleType(topLevelType, simpleRoleName);
                }
                // ...else find the nested role
                else {
                    String relativeRoleName = getRelativeName(topLevelName, roleName);
                    return TypeHelper.findNestedRoleType(topLevelType, relativeRoleName);
                }
            }
            return null;
        }
        // ...else the focus type is a team or regular class
        else {
            return topLevelType;
        }
    }

    /**
     * Make the given qualified name relative, so that the simple name or
     * rootType is the first part of the resulting name.
     * 
     * @param rootType
     * @param fullyQualifiedName
     * @return
     */
    private static String getRelativeName(String rootType, String fullyQualifiedName) {
        assert fullyQualifiedName.startsWith(rootType) : "role type must start like enclosing team"; //$NON-NLS-1$
        int pos = rootType.lastIndexOf('.');
        if (pos == -1)
            pos = rootType.length();
        return fullyQualifiedName.substring(pos + 1);
    }

    public static RefactoringStatus checkOverloading(IMethod[] inheritedMethods, String newName,
            String[] newParameterTypes, IOverloadingMessageCreator msgCreator) {
        RefactoringStatus result = new RefactoringStatus();

        for (int idx = 0; idx < inheritedMethods.length; idx++) {
            // check if an inherited method or a local method has the
            // same name as the method to be refactored
            IMethod actualMethod = inheritedMethods[idx];
            if (actualMethod.getElementName().equals(newName)) {
                // get number of parameters of actual method
                int actualMethodParamCount = actualMethod.getParameterTypes().length;
                // get parameter types of actual method
                String[] actualMethodParamTypes = getParameterTypesOfActualMethod(actualMethod);
                // get number of parameters of method to be refactored
                int refactoredMethodParamCount = newParameterTypes == null ? 0 : newParameterTypes.length;

                // check if this method has a different number of parameters
                // than
                // the method to be refactored or...
                if (actualMethodParamCount != refactoredMethodParamCount) {
                    // if overloading is present, issue a warning
                    result.merge(addOverloadingWarning(msgCreator));
                }
                // ...if it has the same number of parameters but different
                // parameter types
                else if (newParameterTypes != null) {
                    for (int idz = 0; idz < actualMethodParamTypes.length; idz++) {
                        if (!actualMethodParamTypes[idz].equals(newParameterTypes[idz])) {
                            // if overloading is present, issue a warning
                            result.merge(addOverloadingWarning(msgCreator));
                        }
                    }
                }
            }
        }
        return result;
    }

    private static String[] getParameterTypesOfActualMethod(IMethod actualMethod) {
        String[] actualMethodParamTypes = actualMethod.getParameterTypes();
        String[] readableActualMethodParamTypes = new String[actualMethodParamTypes.length];
        for (int idy = 0; idy < actualMethodParamTypes.length; idy++) {
            // convert parameter types into readable names
            readableActualMethodParamTypes[idy] = Signature.toString(actualMethodParamTypes[idy]);
        }
        return readableActualMethodParamTypes;
    }

    // List getBaseMappingElements()
    public static RefactoringStatus checkForAmbiguousBaseMethodSpecs(ArrayList<IRoleType> boundRoleTypes,
            String newMethodName, String oldMethodName, IAmbuguityMessageCreator msgCreator)
            throws JavaModelException {
        RefactoringStatus result = new RefactoringStatus();

        for (Iterator<IRoleType> iter = boundRoleTypes.iterator(); iter.hasNext();) {
            IRoleType boundRoleType = iter.next();
            // get all method mappings of bound role type
            AbstractMethodMappingDeclaration[] mappings = RefactoringUtil.getAllMethodMappings(boundRoleType);

            if (mappings != null && mappings.length != 0) {
                for (int idx = 0; idx < mappings.length; idx++) {
                    AbstractMethodMappingDeclaration mapping = mappings[idx];
                    if (mapping instanceof CallinMappingDeclaration) {
                        CallinMappingDeclaration callinDecl = (CallinMappingDeclaration) mapping;
                        List<MethodMappingElement> baseMethodSpecs = callinDecl.getBaseMappingElements();
                        for (Iterator<MethodMappingElement> iterator = baseMethodSpecs.iterator(); iterator
                                .hasNext();) {
                            MethodMappingElement baseMethodSpec = iterator.next();
                            String baseMethodName = baseMethodSpec.getName().getIdentifier();
                            // check if base method specifier in callin mapping
                            // has
                            // no signature and if it has the same name as the
                            // extracted
                            // method
                            if (!baseMethodSpec.hasSignature() && (baseMethodName.equals(newMethodName)
                                    || baseMethodName.equals(oldMethodName))) {
                                // create the context
                                RefactoringStatusContext context = createContext(boundRoleType, baseMethodSpec);
                                // if it has the same name, issue an error
                                result.merge(addAmbiguityFatalError(context, msgCreator));
                            }
                        }
                    } else if (mapping instanceof CalloutMappingDeclaration) {
                        CalloutMappingDeclaration calloutDecl = (CalloutMappingDeclaration) mapping;
                        MethodMappingElement baseElement = calloutDecl.getBaseMappingElement();
                        // check if base element is a method spec and not a
                        // field access spec
                        if (baseElement instanceof MethodSpec) {
                            MethodSpec baseMethodSpec = (MethodSpec) baseElement;
                            String baseMethodName = baseMethodSpec.getName().getIdentifier();
                            // check if base method specifier in callout mapping
                            // has
                            // no signature and if it has the same name as the
                            // extracted
                            // method
                            if (!baseMethodSpec.hasSignature() && (baseMethodName.equals(newMethodName)
                                    || baseMethodName.equals(oldMethodName))) {
                                // create the context
                                RefactoringStatusContext context = createContext(boundRoleType, baseMethodSpec);
                                // if it has the same name, issue an error
                                result.merge(addAmbiguityFatalError(context, msgCreator));
                            }
                        }
                    }
                }
            }
        }
        return result;
    }

    public static RefactoringStatus checkForAmbiguousRoleMethodSpecs(IRoleType roleType, String newMethodName,
            IAmbuguityMessageCreator msgCreator) throws JavaModelException {
        RefactoringStatus result = new RefactoringStatus();
        // get all method mappings of role type
        AbstractMethodMappingDeclaration[] mappings = RefactoringUtil.getAllMethodMappings(roleType);

        if (mappings != null && mappings.length != 0) {
            for (int idx = 0; idx < mappings.length; idx++) {
                AbstractMethodMappingDeclaration mapping = mappings[idx];
                if (mapping instanceof CallinMappingDeclaration) {
                    CallinMappingDeclaration callinDecl = (CallinMappingDeclaration) mapping;
                    MethodSpec roleMethodSpec = (MethodSpec) callinDecl.getRoleMappingElement();
                    String roleMethodName = roleMethodSpec.getName().getIdentifier();
                    // check if role method specifier in callin mapping has
                    // no signature and if it has the same name as the extracted
                    // method
                    if (!roleMethodSpec.hasSignature() && roleMethodName.equals(newMethodName)) {
                        // create the context
                        RefactoringStatusContext context = createContext(roleType, roleMethodSpec);
                        // if it has the same name, issue an error
                        result.merge(addAmbiguityFatalError(context, msgCreator));
                    }
                } else if (mapping instanceof CalloutMappingDeclaration) {
                    CalloutMappingDeclaration calloutDecl = (CalloutMappingDeclaration) mapping;
                    MethodSpec roleMethodSpec = (MethodSpec) calloutDecl.getRoleMappingElement();
                    String roleMethodName = roleMethodSpec.getName().getIdentifier();
                    // check if role method specifier in callout mapping has
                    // no signature and if it has the same name as the extracted
                    // method
                    if (!roleMethodSpec.hasSignature() && roleMethodName.equals(newMethodName)) {
                        // create the context
                        RefactoringStatusContext context = createContext(roleType, roleMethodSpec);
                        // if it has the same name, issue an error
                        result.merge(addAmbiguityFatalError(context, msgCreator));
                    }
                }
            }
        }
        return result;
    }

    /**
     * Returns all method mappings of the given role type.
     * 
     * @param roleType
     *            the given role type
     * @return an array of method mapping declarations
     * @throws JavaModelException
     */
    public static AbstractMethodMappingDeclaration[] getAllMethodMappings(IRoleType roleType)
            throws JavaModelException {
        RoleTypeDeclaration roleClassDecl = getRoleClassDeclaration(roleType);
        // get all callin and callout mappings of given role type
        AbstractMethodMappingDeclaration[] callinMappings = roleClassDecl.getCallIns();
        AbstractMethodMappingDeclaration[] calloutMappings = roleClassDecl.getCallOuts();

        AbstractMethodMappingDeclaration[] mappings = new AbstractMethodMappingDeclaration[callinMappings.length
                + calloutMappings.length];
        if (callinMappings.length != 0) {
            System.arraycopy(callinMappings, 0, mappings, 0, callinMappings.length);
            System.arraycopy(calloutMappings, 0, mappings, callinMappings.length, calloutMappings.length);
        } else {
            System.arraycopy(calloutMappings, 0, mappings, 0, calloutMappings.length);
        }
        return mappings;
    }

    public static RefactoringStatus addOverloadingWarning(IOverloadingMessageCreator msgCreator) {
        RefactoringStatus result = RefactoringUtil.createWarningStatus(msgCreator.createOverloadingMessage(), null,
                OTRefactoringStatusCodes.OVERLOADING);
        return result;
    }

    public static RefactoringStatus addAmbiguityFatalError(RefactoringStatusContext context,
            IAmbuguityMessageCreator msgCreator) {
        RefactoringStatus result = RefactoringUtil.createFatalErrorStatus(
                msgCreator.createAmbiguousMethodSpecifierMsg(), context,
                OTRefactoringStatusCodes.AMBIGUOUS_METHOD_SPECIFIER);
        return result;
    }

    /**
     * Performs overloading checks for a team class or a regular class.
     * 
     * @param result
     *            the actual refactoring status
     * @param newMethodName
     *            the name of the refactored method
     * @param focusType
     *            the destination type of the refactored method
     * @param msgCreator a message creator object to provide refactoring specific error messages
     * @param pm
     *            the progress monitor
     * @param newMethod
     *            the refactored method
     * @return the refactoring status containing a warning entry in case of
     *         overloading; ok otherwise.
     * @throws JavaModelException
     */
    public static RefactoringStatus checkOverloadingForTeamOrRegularClass(RefactoringStatus result,
            String newMethodName, String[] newParamTypes, IType focusType, IOverloadingMessageCreator msgCreator,
            IProgressMonitor pm) throws JavaModelException {
        RefactoringStatus status = new RefactoringStatus();

        RefactoringStatusEntry overloading = result.getEntryMatchingCode(Corext.getPluginId(),
                OTRefactoringStatusCodes.OVERLOADING);

        if (overloading == null) {
            IMethod[] methods = getInheritedMethods(focusType, true, true, true, pm);
            status.merge(checkOverloading(methods, newMethodName, newParamTypes, msgCreator));
        }
        return status;
    }

    /**
     * Performs overloading and ambiguity checks for a role type.
     * 
     * @param result
     *            the actual refactoring status
     * @param newMethodName
     *            the name of the refactored method
     * @param roleType
     *            the focus role
     * @param ambiguitymsgCreator a message creator object to provide refactoring specific error messages
     * @param overloadingmsgCreator a message creator object to provide refactoring specific error messages
     * @param pm
     *            the progress monitor
     * @param newMethod
     *            the refactored method
     * @return the refactoring status containing a warning entry in case of
     *         overloading, or a warning and fatal error entry in case of
     *         overloading and ambiguous method specs; ok otherwise.
     * @throws JavaModelException
     */
    public static RefactoringStatus checkOverloadingAndAmbiguityForRole(RefactoringStatus result,
            String newMethodName, String[] newParamTypes, IRoleType roleType,
            IAmbuguityMessageCreator ambiguityMsgCreator, IOverloadingMessageCreator overloadingMsgCreator,
            IProgressMonitor pm) throws JavaModelException {
        RefactoringStatus status = new RefactoringStatus();

        RefactoringStatusEntry overloading = result.getEntryMatchingCode(Corext.getPluginId(),
                OTRefactoringStatusCodes.OVERLOADING);

        if (overloading == null) {
            // NOTE(gbr): result array of getInheritedMethods(..) also includes
            // private methods. The reason is that method bindings may refer
            // to hidden base methods (see OTJLD 3.4 and 4.6). This fact
            // must be considered in the overloading and ambiguity checks.
            IMethod[] methods = getInheritedMethods(roleType, true, true, false, pm);
            status.merge(checkOverloading(methods, newMethodName, newParamTypes, overloadingMsgCreator));
        }
        if (status.hasWarning() || result.hasWarning()) {
            status.merge(checkForAmbiguousRoleMethodSpecs(roleType, newMethodName, ambiguityMsgCreator));
        }
        return status;
    }

    /**
     * Performs overloading and ambiguity checks for a bound base type.
     * 
     * @param result
     *            the actual refactoring status
     * @param newMethodName
     *            the name of the refactored method
     * @param oldMethodName
     *            the old name of the refactored method (can be null)
     * @param focusType
     *            the regarded type
     * @param roleTypes
     *            the role types contained in the project
     * @param ambiguitymsgCreator a message creator object to provide refactoring specific error messages
     * @param overloadingmsgCreator a message creator object to provide refactoring specific error messages
     * @param pm
     *            the progress monitor
     * @param newMethod
     *            the refactored method
     * @return the refactoring status containing a warning entry in case of
     *         overloading, or a warning and fatal error entry in case of
     *         overloading and ambiguous method specs; ok otherwise.
     * @throws JavaModelException
     */
    public static RefactoringStatus checkOverloadingAndAmbiguityForBase(RefactoringStatus result,
            String newMethodName, String oldMethodName, String[] newParamTypes, IType focusType,
            IOTType[] roleTypes, IAmbuguityMessageCreator ambiguityMsgCreator,
            IOverloadingMessageCreator overloadingMsgCreator, IProgressMonitor pm) throws JavaModelException {
        RefactoringStatus status = new RefactoringStatus();

        ArrayList<IRoleType> boundRoleTypes = new ArrayList<IRoleType>();
        for (int idx = 0; idx < roleTypes.length; idx++) {
            IRoleType roleType = (IRoleType) roleTypes[idx];
            IType baseClass = roleType.getBaseClass();
            if (baseClass != null && baseClass.equals(focusType)) {
                RefactoringStatusEntry overloadingThis = status.getEntryMatchingCode(Corext.getPluginId(),
                        OTRefactoringStatusCodes.OVERLOADING);
                RefactoringStatusEntry overloadingOther = result.getEntryMatchingCode(Corext.getPluginId(),
                        OTRefactoringStatusCodes.OVERLOADING);

                // check overloading only once for all role types bound to the
                // same baseclass
                if (overloadingThis == null && overloadingOther == null) {
                    // NOTE(gbr): result array of getInheritedMethods(..) also
                    // includes
                    // private methods. The reason is that method bindings may
                    // refer
                    // to hidden base methods (see OTJLD 3.4 and 4.6).
                    // This fact
                    // must be considered in the overloading and ambiguity
                    // checks.
                    IMethod[] baseMethods = getInheritedMethods(baseClass, true, true, false, pm);
                    status.merge(
                            checkOverloading(baseMethods, newMethodName, newParamTypes, overloadingMsgCreator));
                }
                // add role that is bound to the base class to the list
                boundRoleTypes.add(roleType);
            }
        }
        if (status.hasWarning() || result.hasWarning()) {
            status.merge(checkForAmbiguousBaseMethodSpecs(boundRoleTypes, newMethodName, oldMethodName,
                    ambiguityMsgCreator));
        }
        return status;
    }

    /**
     * Performs overloading and ambiguity checks for a bound base type present
     * in the super hierarchy of the focus (destination) type.
     * 
     * @param newMethodName
     *            the name of the refactored method
     * @param oldMethodName
     *            the old name of the refactored method (can be null)
     * @param superTypes
     *            the super types of the focus type
     * @param msgCreator a message creator object to provide refactoring specific error messages
     * @param roleType
     *            the role type bound to the base type
     * @return the refactoring status containing a fatal error entry in case of
     *         ambiguous method specs; ok otherwise.
     * @throws JavaModelException
     */
    public static RefactoringStatus checkAmbiguityForBasePresentInFocusTypeSuperhierarchy(String newMethodName,
            String oldMethodName, IType[] superTypes, IAmbuguityMessageCreator msgCreator, IRoleType roleType)
            throws JavaModelException {
        RefactoringStatus status = new RefactoringStatus();
        ArrayList<IRoleType> roleList = new ArrayList<IRoleType>();

        IType baseClass = roleType.getBaseClass();
        if (baseClass != null) {
            for (int idx = 0; idx < superTypes.length; idx++) {
                if (baseClass.equals(superTypes[idx])) {
                    roleList.add(roleType);
                    status.merge(
                            checkForAmbiguousBaseMethodSpecs(roleList, newMethodName, oldMethodName, msgCreator));
                }
            }
        }
        return status;
    }

    /**
     * Checks overloading and ambiguity for the given method name and method
     * declaration.
     * 
     * @param compUnit
     *            the target compilation unit
     * @param destination
     *            the ast node representing the destination type
     * @param newMethodName
     *            the name of the new method
     * @param ambiguitymsgCreator a message creator object to provide refactoring specific error messages
     * @param overloadingmsgCreator a message creator object to provide refactoring specific error messages
     * @param pm
     *            the progress monitor
     * @param newMethod
     *            the method declaration of the new method
     * @return the refactoring status
     * @throws JavaModelException
     */
    public static RefactoringStatus checkOverloadingAndAmbiguity(ICompilationUnit compUnit, ASTNode destination,
            String newMethodName, String[] newParamTypes, IAmbuguityMessageCreator ambiguityMsgCreator,
            IOverloadingMessageCreator overloadingMsgCreator, IProgressMonitor pm) throws JavaModelException {
        // get top level type declared in compilation unit
        IType topLevelType = robustFindPrimaryType(compUnit);
        // determine focus type: can be either a regular class (including team)
        // or a role
        IType focusType = RefactoringUtil.determineFocusType(topLevelType, destination);

        return checkOverloadingAndAmbiguity(focusType, null, newMethodName, newParamTypes, ambiguityMsgCreator,
                overloadingMsgCreator, pm);

    }

    /**
     * Checks overloading and ambiguity for the given method name and method
     * declaration.
     * 
     * @param focusType
     *            the focus type to check for ambiguity
     * @param focusTypeHierarchy
     *            the type hierarchy for the focus type - will be computed if
     *            <code>null</code>
     * @param newMethodName
     *            the name of the new method
     * @param newParamTypes
     *            the parameters of the new method
     * @param ambigutiymsgCreator a message creator object to provide refactoring specific error messages
     * @param overloadingmsgCreator a message creator object to provide refactoring specific error messages
     * @param pm
     *            the progress monitor
     * @return the refactoring status
     * @throws JavaModelException
     */
    public static RefactoringStatus checkOverloadingAndAmbiguity(IType focusType, ITypeHierarchy focusTypeHierarchy,
            String newMethodName, String[] newParamTypes, IAmbuguityMessageCreator ambigutiyMsgCreator,
            IOverloadingMessageCreator overloadingMsgCreator, IProgressMonitor pm) throws JavaModelException {
        ICompilationUnit compUnit = focusType.getCompilationUnit();
        // create OT typehierarchy
        if (focusTypeHierarchy == null) {
            focusTypeHierarchy = focusType.newTypeHierarchy(pm);
        }
        // get all supertypes of focus type
        IType[] superTypes = focusTypeHierarchy.getAllSupertypes(focusType);
        // get all subtypes of focus type
        IType[] subTypes = focusTypeHierarchy.getAllSubtypes(focusType);
        // get all role types in this project
        // FIXME(SH): should replace gettingAllRoles with s.t. like RefactoringUtil.getAllRolesForBase(focusType);
        IOTType[] roleTypes = RefactoringUtil.getAllRoleClasses(compUnit.getJavaProject(), pm);
        // get all base types
        ArrayList<IType> baseTypes = RefactoringUtil.getAllDeclaredBaseTypes(roleTypes);

        RefactoringStatus result = new RefactoringStatus();
        // if the focus type is a team,
        // check for overloading methods in team and its supertypes
        if (TypeHelper.isTeam(focusType.getFlags())) {
            result.merge(RefactoringUtil.checkOverloadingForTeamOrRegularClass(result, newMethodName, newParamTypes,
                    focusType, overloadingMsgCreator, pm));
            if (result.getSeverity() == RefactoringStatus.WARNING) {
                return result;
            }
        }
        // if the focus type is a role,
        // check for overloading methods in role and its supertypes,
        // and for ambiguity in its method bindings
        if (TypeHelper.isRole(focusType.getFlags())) {
            IRoleType roleType = (IRoleType) OTModelManager.getOTElement(focusType);
            result.merge(RefactoringUtil.checkOverloadingAndAmbiguityForRole(result, newMethodName, newParamTypes,
                    roleType, ambigutiyMsgCreator, overloadingMsgCreator, pm));
            result.merge(RefactoringUtil.checkAmbiguityForBasePresentInFocusTypeSuperhierarchy(newMethodName, null,
                    superTypes, ambigutiyMsgCreator, roleType));
        }
        // if the focus type is an unbound regular class,
        // check for overloading methods in this class and its supertypes
        else if (!baseTypes.contains(focusType)) {
            RefactoringUtil.checkOverloadingForTeamOrRegularClass(result, newMethodName, newParamTypes, focusType,
                    overloadingMsgCreator, pm);
            if (result.getSeverity() == RefactoringStatus.WARNING) {
                return result;
            }
        }
        // if the focus type is a bound base class,
        // check for overloading methods in this base class and its supertypes,
        // and for ambiguity in method bindings of bound role classes
        else if (baseTypes.contains(focusType)) {
            result.merge(RefactoringUtil.checkOverloadingAndAmbiguityForBase(result, newMethodName, null,
                    newParamTypes, focusType, roleTypes, ambigutiyMsgCreator, overloadingMsgCreator, pm));
        }
        // if the focus type has subtypes,
        // check overloading in the super hierarchy of each type
        if (subTypes.length != 0) {
            for (int idx = 0; idx < subTypes.length; idx++) {
                IType subType = subTypes[idx];

                // if the actual subtype of the focus type is a role,
                // check for overloading methods in this role and its
                // supertypes and for ambiguity in method bindings
                if (TypeHelper.isRole(subType.getFlags())) {
                    IRoleType roleType = (IRoleType) OTModelManager.getOTElement(subType);
                    result.merge(RefactoringUtil.checkOverloadingAndAmbiguityForRole(result, newMethodName,
                            newParamTypes, roleType, ambigutiyMsgCreator, overloadingMsgCreator, pm));
                    if (result.hasWarning()) {
                        IType baseClass = roleType.getBaseClass();
                        ArrayList<IRoleType> roleList = new ArrayList<IRoleType>();
                        // if base class of role type is the focus type,
                        // check also ambiguous base method specs
                        if (baseClass != null && baseClass.equals(focusType)) {
                            roleList.add(roleType);
                            result.merge(RefactoringUtil.checkForAmbiguousBaseMethodSpecs(roleList, newMethodName,
                                    null, ambigutiyMsgCreator));
                        }
                        // else if base class of role type is a direct or
                        // indirect
                        // superclass of focus type, check also ambiguous base
                        // method specs
                        else {
                            result.merge(RefactoringUtil.checkAmbiguityForBasePresentInFocusTypeSuperhierarchy(
                                    newMethodName, null, superTypes, ambigutiyMsgCreator, roleType));
                        }
                    }
                }
                // if the actual subtyp of the focus type is an unbound regular
                // class,
                // check for overloading methods in this class and its
                // supertypes
                else if (!baseTypes.contains(subType)) {
                    result.merge(RefactoringUtil.checkOverloadingForTeamOrRegularClass(result, newMethodName,
                            newParamTypes, subType, overloadingMsgCreator, pm));
                }
                // if the actual subtype of the focus type is a bound base
                // class,
                // check for overloading methods in this base class and its
                // supertypes
                // and for ambiguity in method bindings of bound role classes
                else if (baseTypes.contains(subType)) {
                    result.merge(RefactoringUtil.checkOverloadingAndAmbiguityForBase(result, newMethodName, null,
                            newParamTypes, subType, roleTypes, ambigutiyMsgCreator, overloadingMsgCreator, pm));
                }
            }
        }
        return result;
    }

    // TODO(jsv): copy of checkOverloadingAndAmbiguity with ASTNode as
    // destination -> remove redundant code
    /**
     * Checks overloading and ambiguity for the given method name and method
     * declaration.
     * 
     * @param compUnit
     *            the target compilation unit
     * @param focusType
     *            the type of the renamed method
     * @param newMethodName
     *            the name of the new method
     * @param oldMethodName
     *            the old name of the method
     * @param ambiguitymsgCreator a message creator object to provide refactoring specific error messages
     * @param overloadingmsgCreator a message creator object to provide refactoring specific error messages.
     * @param pm
     *            the progress monitor
     * @param newMethod
     *            the IMethod of the new method
     * @return the refactoring status
     * @throws JavaModelException
     */
    public static RefactoringStatus checkOverloadingAndAmbiguity(ICompilationUnit compUnit, IType focusType,
            String newMethodName, String oldMethodName, String[] newParamTypes,
            IAmbuguityMessageCreator ambiguityMsgCreator, IOverloadingMessageCreator overloadingMsgCreator,
            IProgressMonitor pm) throws JavaModelException {
        // FIXME(SH): what is this unused code good for?
        // get top level type declared in compilation unit
        // IType topLevelType = compUnit.findPrimaryType();
        // determine focus type: can be either a regular class (including team)
        // or a role
        // IType focusType = RefactoringUtil.determineFocusType(topLevelType,
        // destination);

        // create OT typehierarchy
        ITypeHierarchy completeHierarchy = focusType.newTypeHierarchy(pm);
        // get all supertypes of focus type
        IType[] superTypes = completeHierarchy.getAllSupertypes(focusType);
        // get all subtypes of focus type
        IType[] subTypes = completeHierarchy.getAllSubtypes(focusType);
        // get all role types in this project
        // FIXME(SH): should replace gettingAllRoles with s.t. like RefactoringUtil.getAllRolesForBase(focusType);
        IOTType[] roleTypes = RefactoringUtil.getAllRoleClasses(compUnit.getJavaProject(), pm);
        // get all base types
        ArrayList<IType> baseTypes = RefactoringUtil.getAllDeclaredBaseTypes(roleTypes);

        RefactoringStatus result = new RefactoringStatus();
        // if the focus type is a team,
        // check for overloading methods in team and its supertypes
        if (TypeHelper.isTeam(focusType.getFlags())) {
            result.merge(RefactoringUtil.checkOverloadingForTeamOrRegularClass(result, newMethodName, newParamTypes,
                    focusType, overloadingMsgCreator, pm));
            if (result.getSeverity() == RefactoringStatus.WARNING) {
                return result;
            }
        }
        // if the focus type is a role,
        // check for overloading methods in role and its supertypes,
        // and for ambiguity in its method bindings
        if (TypeHelper.isRole(focusType.getFlags())) {
            IRoleType roleType = (IRoleType) OTModelManager.getOTElement(focusType);
            result.merge(RefactoringUtil.checkOverloadingAndAmbiguityForRole(result, newMethodName, newParamTypes,
                    roleType, ambiguityMsgCreator, overloadingMsgCreator, pm));
            result.merge(RefactoringUtil.checkAmbiguityForBasePresentInFocusTypeSuperhierarchy(newMethodName,
                    oldMethodName, superTypes, ambiguityMsgCreator, roleType));
        }
        // if the focus type is an unbound regular class,
        // check for overloading methods in this class and its supertypes
        else if (!baseTypes.contains(focusType)) {
            RefactoringUtil.checkOverloadingForTeamOrRegularClass(result, newMethodName, newParamTypes, focusType,
                    overloadingMsgCreator, pm);
            if (result.getSeverity() == RefactoringStatus.WARNING) {
                return result;
            }
        }
        // if the focus type is a bound base class,
        // check for overloading methods in this base class and its supertypes,
        // and for ambiguity in method bindings of bound role classes
        else if (baseTypes.contains(focusType)) {
            result.merge(RefactoringUtil.checkOverloadingAndAmbiguityForBase(result, newMethodName, oldMethodName,
                    newParamTypes, focusType, roleTypes, ambiguityMsgCreator, overloadingMsgCreator, pm));
        }
        // if the focus type has subtypes,
        // check overloading in the super hierarchy of each type
        if (subTypes.length != 0) {
            for (int idx = 0; idx < subTypes.length; idx++) {
                IType subType = subTypes[idx];

                // if the actual subtype of the focus type is a role,
                // check for overloading methods in this role and its
                // supertypes and for ambiguity in method bindings
                if (TypeHelper.isRole(subType.getFlags())) {
                    IRoleType roleType = (IRoleType) OTModelManager.getOTElement(subType);
                    result.merge(RefactoringUtil.checkOverloadingAndAmbiguityForRole(result, newMethodName,
                            newParamTypes, roleType, ambiguityMsgCreator, overloadingMsgCreator, pm));
                    if (result.hasWarning()) {
                        IType baseClass = roleType.getBaseClass();
                        ArrayList<IRoleType> roleList = new ArrayList<IRoleType>();
                        // if base class of role type is the focus type,
                        // check also ambiguous base method specs
                        if (baseClass != null && baseClass.equals(focusType)) {
                            roleList.add(roleType);
                            result.merge(RefactoringUtil.checkForAmbiguousBaseMethodSpecs(roleList, newMethodName,
                                    oldMethodName, ambiguityMsgCreator));
                        }
                        // else if base class of role type is a direct or
                        // indirect
                        // superclass of focus type, check also ambiguous base
                        // method specs
                        else {
                            result.merge(RefactoringUtil.checkAmbiguityForBasePresentInFocusTypeSuperhierarchy(
                                    newMethodName, oldMethodName, superTypes, ambiguityMsgCreator, roleType));
                        }
                    }
                }
                // if the actual subtyp of the focus type is an unbound regular
                // class,
                // check for overloading methods in this class and its
                // supertypes
                else if (!baseTypes.contains(subType)) {
                    result.merge(RefactoringUtil.checkOverloadingForTeamOrRegularClass(result, newMethodName,
                            newParamTypes, subType, overloadingMsgCreator, pm));
                }
                // if the actual subtype of the focus type is a bound base
                // class,
                // check for overloading methods in this base class and its
                // supertypes
                // and for ambiguity in method bindings of bound role classes
                else if (baseTypes.contains(subType)) {
                    result.merge(RefactoringUtil.checkOverloadingAndAmbiguityForBase(result, newMethodName,
                            oldMethodName, newParamTypes, subType, roleTypes, ambiguityMsgCreator,
                            overloadingMsgCreator, pm));
                }
            }
        }
        return result;
    }

    /**
     * Creates a refactoring status context for the given role type and method
     * spec.
     * 
     * @param roleType
     *            the role containing the error
     * @param methodSpec
     *            the method spec that has caused the error
     * @return the refactoring status context or null if the context cannot be
     *         created
     */
    public static RefactoringStatusContext createContext(IRoleType roleType, MethodMappingElement methodSpec) {
        RefactoringStatusContext context = JavaStatusContext.create(roleType.getCompilationUnit(), methodSpec);
        return context;
    }

    /**
     * Creates a warning refactoring status.
     * 
     * @param msg
     *            the message of the warning entry
     * @param context
     *            the context of the warning entry
     * @param code
     *            the problem code (@see <code>OTRefactoringStatusCodes</code>)
     * @return the refactoring status
     */
    public static RefactoringStatus createWarningStatus(String msg, RefactoringStatusContext context, int code) {
        return RefactoringStatus.createStatus(RefactoringStatus.WARNING, msg, context, Corext.getPluginId(), code,
                null);
    }

    /**
     * Creates an error refactoring status.
     * 
     * @param msg
     *            the message of the error entry
     * @param context
     *            the context of the error entry
     * @param code
     *            the problem code (@see <code>OTRefactoringStatusCodes</code>)
     * @return the refactoring status
     */
    public static RefactoringStatus createErrorStatus(String msg, RefactoringStatusContext context, int code) {
        return RefactoringStatus.createStatus(RefactoringStatus.ERROR, msg, context, Corext.getPluginId(), code,
                null);
    }

    /**
     * Creates a fatal error refactoring status.
     * 
     * @param msg
     *            the message of the fatal error entry
     * @param context
     *            the context of the fatal error entry
     * @param code
     *            the problem code (@see <code>OTRefactoringStatusCodes</code>)
     * @return the refactoring status
     */
    public static RefactoringStatus createFatalErrorStatus(String msg, RefactoringStatusContext context, int code) {
        return RefactoringStatus.createStatus(RefactoringStatus.FATAL, msg, context, Corext.getPluginId(), code,
                null);
    }

    /**
     * Checks, if method has a special OT name. Does not use the
     * OTTypeHIerarchy, because of performance optimization (team constants are
     * using)
     * 
     * @param current
     *            method to check
     * @param new method name, should be <code>null</code> or an empty String if
     *        you wants to check the current method and not the new method with
     *        the same arguments like the current method
     * @return the refactoring status
     */
    public static boolean isOTSpecialCase(IMethod origMethod, String newMethodName,
            boolean checkImplementingClasses, IProgressMonitor pm) throws CoreException {
        // TODO(jsv) what to do in case of interface is only used by base
        // class(es) ? to check the impolementing classes is a performance
        // overhead
        IType declaringType = origMethod.getDeclaringType();

        if (!Flags.isTeam(declaringType.getFlags())) {
            // heavyweight check for interfaces
            if (Flags.isInterface(declaringType.getFlags()) && checkImplementingClasses) {
                ITypeHierarchy hier = declaringType.newTypeHierarchy(pm);
                IType[] impementingClasses = hier.getImplementingClasses(declaringType);
                boolean teamImplementsInterface = false;
                for (int idx = 0; idx < impementingClasses.length; idx++) {
                    if (Flags.isTeam(impementingClasses[idx].getFlags())) {
                        teamImplementsInterface = true;
                        break;
                    }
                }

                if (!teamImplementsInterface) {
                    return false;
                }
            } else {
                return false;
            }
        }

        if (newMethodName == null || newMethodName.length() == 0)
            newMethodName = origMethod.getElementName();

        assert (virtualTeamMethodNames.length == virtualTeamMethodParamTypes.length)
                && (virtualTeamMethodParamTypes.length == virtualTeamMethodReturnTypes.length);
        for (int i = 0; i < virtualTeamMethodNames.length; i++) {
            if (virtualTeamMethodNames[i].equals(newMethodName)
                    && Checks.compareParamTypes(origMethod.getParameterTypes(), virtualTeamMethodParamTypes[i])
                    && virtualTeamMethodReturnTypes[i].equals(origMethod.getReturnType())) {
                return true;
            }
        }
        return false;
    }

    public static ASTNode getASTNode(IMember member, Class<? extends ASTNode> nodeClass) {
        if (member == null || member.getCompilationUnit() == null) {
            return null;
        }

        ICompilationUnit source = member.getCompilationUnit();

        ASTParser parser = ASTParser.newParser(AST.JLS4);
        parser.setSource(source);
        parser.setResolveBindings(true);
        CompilationUnit astRoot = (CompilationUnit) parser.createAST(null);
        // NOTE(SH): cannot use member.getSourceRange() together with the AST:
        // member uses declarationSourceEnd (incl. comment) whereas
        // the ASTConverter uses bodyEnd instead (excluding comment/trailing
        // '}')
        // However, getNameRange() should be safe.
        try {
            ASTNode name = NodeFinder.perform(astRoot, member.getNameRange());
            return getParent(name, nodeClass);
        } catch (JavaModelException e) {
            return null;
        }
    }

    /**
     * Finds all overridden methods of a certain method.
     * 
     */
    public static IMethod[] getOverriddenMethods(IMethod method, IProgressMonitor monitor) throws CoreException {

        assert method != null;
        return RippleMethodFinder2.getRelatedMethods(method, monitor, null);
    }

    /**
     * Locates the topmost method of an override ripple and returns it. If none
     * is found, null is returned.
     * 
     * @param method
     *            the IMethod which may be part of a ripple
     * @param typeHierarchy
     *            a ITypeHierarchy of the declaring type of the method. May be
     *            null
     * @param monitor
     *            an IProgressMonitor
     * @return the topmost method of the ripple, or null if none
     * @throws JavaModelException
     */
    public static IMethod getTopmostMethod(IMethod method, ITypeHierarchy typeHierarchy, IProgressMonitor monitor)
            throws JavaModelException {

        assert method != null;

        ITypeHierarchy hierarchy = typeHierarchy;
        IMethod topmostMethod = null;
        final IType declaringType = method.getDeclaringType();
        if (!declaringType.isInterface()) {
            if ((hierarchy == null) || !declaringType.equals(hierarchy.getType())) {
                hierarchy = declaringType.newSupertypeHierarchy(monitor);
            }
            IMethod inInterface = isDeclaredInInterface(method, hierarchy, monitor);
            if (inInterface != null && !inInterface.equals(method))
                topmostMethod = inInterface;
        }
        if (topmostMethod == null) {
            if (hierarchy == null) {
                hierarchy = declaringType.newSupertypeHierarchy(monitor);
            }
            IMethod overrides = overridesAnotherMethod(method, hierarchy, monitor);
            if (overrides != null && !overrides.equals(method))
                topmostMethod = overrides;
        }
        return topmostMethod;
    }

    public static IField fieldIsShadowedInType(String elementName, String typeSignature, IType type)
            throws JavaModelException {
        IField field = type.getField(elementName);
        if (field.exists() && !field.getTypeSignature().equals(typeSignature)) {
            return field;
        }
        return null;
    }

    public static MethodDeclaration methodToDeclaration(IMethod method, CompilationUnit node)
            throws JavaModelException {
        ICompilationUnit methodCU = (ICompilationUnit) method.getAncestor(IJavaElement.COMPILATION_UNIT);
        if (!methodCU.equals(node.getJavaElement())) {
            node = RefactoringASTParser.parseWithASTProvider(methodCU, true, null);
        }
        Name result = (Name) NodeFinder.perform(node, method.getNameRange());
        return (MethodDeclaration) getParent(result, MethodDeclaration.class);
    }

    public static AbstractMethodMappingDeclaration methodMappingToDeclaration(IMethodMapping methodMapping,
            CompilationUnit node) throws JavaModelException {
        Name result = (Name) NodeFinder.perform(node, methodMapping.getNameRange());
        return (AbstractMethodMappingDeclaration) getParent(result, AbstractMethodMappingDeclaration.class);
    }

    public static RefactoringStatus createNotYetFullyOTAwareMsg(String refactoringName) {
        return RefactoringStatus.createInfoStatus(
                NLS.bind(OTRefactoringMessages.RefactoringUtil_notFullyOTAware_info, refactoringName));
    }

    @SuppressWarnings("rawtypes")
    private static ASTNode getParent(ASTNode node, Class parentClass) {
        do {
            node = node.getParent();
        } while (node != null && !parentClass.isInstance(node));
        return node;
    }

    public static ASTNode typeToDeclaration(IType type, CompilationUnit node) throws JavaModelException {
        Name result = (Name) NodeFinder.perform(node, type.getNameRange());
        if (type.isAnonymous())
            return getParent(result, AnonymousClassDeclaration.class);
        return getParent(result, AbstractTypeDeclaration.class);
    }

    public static RefactoringStatus checkForExistingRoles(String refactoringName, IJavaProject project,
            IProgressMonitor pm) {
        try {
            if (project == null) {
                return createNotYetFullyOTAwareMsg(refactoringName);

            }
            if (getAllRoleClasses(project, pm).length > 0) {
                return createNotYetFullyOTAwareMsg(refactoringName);
            }
        } catch (JavaModelException e) {
            return createNotYetFullyOTAwareMsg(refactoringName);
        }
        return new RefactoringStatus();
    }

}