Java tutorial
/********************************************************************** * 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(); } }