blob: 0476dec9c9a896bd23c6c47036e3158ea3b0b70d [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2010, 2012 Johannes Gebauer and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Please visit http://www.objectteams.org for updates and contact.
*
* Contributors:
* Johannes Gebauer - Initial API and implementation
* Stephan Herrmann - Bug fixes and improvements
**********************************************************************/
package org.eclipse.objectteams.otdt.internal.refactoring.adaptor.pullup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
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.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.*;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.MethodDeclarationMatch;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.internal.core.search.matching.MethodPattern;
import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.BodyDeclarationRewrite;
import org.eclipse.jdt.internal.corext.refactoring.Checks;
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.jdt.internal.corext.refactoring.util.JavaStatusContext;
import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
import org.eclipse.jdt.internal.corext.refactoring.structure.ImportRewriteUtil;
import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment;
import org.eclipse.jdt.internal.corext.refactoring.structure.TypeVariableMaplet;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.JdtFlags;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.internal.corext.util.SearchUtils;
import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.ltk.core.refactoring.GroupCategorySet;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.objectteams.otdt.core.ICallinMapping;
import org.eclipse.objectteams.otdt.core.ICalloutMapping;
import org.eclipse.objectteams.otdt.core.ICalloutToFieldMapping;
import org.eclipse.objectteams.otdt.core.IMethodMapping;
import org.eclipse.objectteams.otdt.core.IOTJavaElement;
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.hierarchy.OTTypeHierarchies;
import org.eclipse.objectteams.otdt.internal.core.AbstractCalloutMapping;
import org.eclipse.objectteams.otdt.internal.core.CalloutMapping;
import org.eclipse.objectteams.otdt.internal.core.CalloutToFieldMapping;
import org.eclipse.objectteams.otdt.internal.core.RoleType;
import org.eclipse.objectteams.otdt.internal.refactoring.RefactoringMessages;
import org.eclipse.objectteams.otdt.internal.refactoring.util.IAmbuguityMessageCreator;
import org.eclipse.objectteams.otdt.internal.refactoring.util.IOverloadingMessageCreator;
import org.eclipse.objectteams.otdt.internal.refactoring.util.RefactoringUtil;
import org.eclipse.osgi.util.NLS;
import org.eclipse.text.edits.TextEditGroup;
import base org.eclipse.jdt.internal.core.search.BasicSearchEngine;
import base org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
import base org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil;
import base org.eclipse.jdt.internal.corext.refactoring.structure.HierarchyProcessor;
import base org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor;
import base org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor;
import base org.eclipse.jdt.internal.corext.refactoring.structure.ReferenceFinderUtil;
import base org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor;
import base org.eclipse.jdt.internal.ui.refactoring.PullUpMemberPage;
import base org.eclipse.jdt.internal.ui.refactoring.PullUpMemberPage.MemberActionInfo;
/**
* @author Johannes Gebauer
*
*/
@SuppressWarnings({ "restriction", "decapsulation" }) // private base classes
public team class PullUpAdaptor {
protected team class PullUpRefactoringProcessorRole playedBy PullUpRefactoringProcessor {
public ChangeManagerDetails changeManagerDetails; // set when this team is activated (see #createChangeManager())
// callout (constant):
GroupCategorySet getSET_PULL_UP() -> get GroupCategorySet SET_PULL_UP;
// callouts (fields):
void setFCachedSkippedSuperTypes(Set<IType> fCachedSkippedSuperTypes)
-> set Set<IType> fCachedSkippedSuperTypes;
Set<IType> getFCachedSkippedSuperTypes() -> get Set<IType> fCachedSkippedSuperTypes;
IMember[] getMembersToDelete(IProgressMonitor monitor) -> IMember[] getMembersToDelete(IProgressMonitor monitor);
IMethod[] getFDeletedMethods() -> get IMethod[] fDeletedMethods;
IMember[] getFMembersToMove() -> get IMember[] fMembersToMove;
// callouts (methods):
IType getDestinationType() -> IType getDestinationType();
IMember[] getMembersToMove() -> IMember[] getMembersToMove();
IType getDeclaringType() -> IType getDeclaringType();
ITypeHierarchy getDestinationTypeHierarchy(IProgressMonitor pm)
-> ITypeHierarchy getDestinationTypeHierarchy(IProgressMonitor pm);
IMember[] getCreatedDestinationMembers() -> IMember[] getCreatedDestinationMembers();
void addMatchingMember(Map<IMember, Set<IMember>> mapping, IMember key, IMember matchingMember)
-> void addMatchingMember(Map<IMember, Set<IMember>> mapping, IMember key, IMember matchingMember);
private void checkFinalConditions(IProgressMonitor pm, CheckConditionsContext context, RefactoringStatus status) throws CoreException {
status.merge(checkForAspectBindings(pm));
status.merge(checkOverloadingAndAmbiguity(pm));
status.merge(checkOverriding(pm));
if(TypeHelper.isRole(getDeclaringType().getFlags())){
status.merge(checkDestinationForOTElements(pm));
status.merge(checkShadowingFieldInImplicitHierarchy(pm));
}
}
void checkFinalConditions(IProgressMonitor pm, CheckConditionsContext context, RefactoringStatus status) <- after RefactoringStatus checkFinalConditions(IProgressMonitor pm,
CheckConditionsContext context) with {
pm <- pm,
context <- context,
status <- result
}
private RefactoringStatus checkShadowingFieldInImplicitHierarchy(IProgressMonitor pm) throws JavaModelException {
RefactoringStatus status = new RefactoringStatus();
if(!TypeHelper.isRole(getDestinationType().getFlags())){
return status;
}
ITypeHierarchy hier = getDestinationTypeHierarchy(pm);
ArrayList<IType> implicitSubRoles = new ArrayList<IType>();
implicitSubRoles.addAll(Arrays.asList(OTTypeHierarchies.getInstance().getAllTSubTypes(hier, getDestinationType())));
// remove the subtypes of the declaring type
implicitSubRoles.removeAll(Arrays.asList(OTTypeHierarchies.getInstance().getAllTSubTypes(hier, getDeclaringType())));
pm.beginTask(RefactoringMessages.PullUpAdaptor_checkShadowing_progress, implicitSubRoles.size());
pm.subTask(""); //$NON-NLS-1$
for (int i = 0; i < getFMembersToMove().length; i++) {
IMember element = getFMembersToMove()[i];
if(element instanceof IField){
IField field = (IField) element;
for (IType type : implicitSubRoles) {
IField shadowingField = RefactoringUtil.fieldIsShadowedInType(field.getElementName(), field.getTypeSignature(), type);
if(shadowingField != null){
ArrayList<IMember> membersToDelete = new ArrayList<IMember>();
membersToDelete.addAll(Arrays.asList(getMembersToDelete(pm)));
// do not indicate shadowing by deleted fields as an error
if(!membersToDelete.contains(shadowingField)) {
String msg = NLS.bind(RefactoringMessages.PullUpAdaptor_fieldShadowing_error,
field.getElementName(),
type.getFullyQualifiedName('.'));
status.addFatalError(msg, JavaStatusContext.create(shadowingField));
}
}
pm.worked(1);
// do not repeat errors in hierarchy
if(status.hasFatalError()){
pm.done();
return status;
}
}
}
}
pm.done();
return status;
}
private RefactoringStatus checkDestinationForOTElements(IProgressMonitor pm) throws JavaModelException {
RefactoringStatus status = new RefactoringStatus();
for (int i = 0; i < getFMembersToMove().length; i++) {
IMember element = getFMembersToMove()[i];
if (element instanceof IMethod){
IMethod method = (IMethod)element;
// callin methods can only be moved to roles
if(Flags.isCallin(method.getFlags()) && !TypeHelper.isRole(getDestinationType().getFlags())){
String msg = NLS.bind(RefactoringMessages.PullUpAdaptor_callinMethodToNonRole_error, method.getElementName());
status.addFatalError(msg, JavaStatusContext.create(method));
} else {
// for callout bindings check if the base member will be accessible after refactoring:
checkDestinationForCallout(method, getDestinationType(), status, pm);
}
}
}
return status;
}
protected static void checkDestinationForCallout(IMethod method, IType destinationType, RefactoringStatus status, IProgressMonitor pm) throws JavaModelException {
IMember baseMember = null;
switch (method.getElementType()) {
case IOTJavaElement.CALLOUT_MAPPING:
baseMember = ((CalloutMapping)method).getBoundBaseMethod();
break;
case IOTJavaElement.CALLOUT_TO_FIELD_MAPPING:
baseMember = ((CalloutToFieldMapping)method).getBoundBaseField();
break;
}
if (baseMember == null) return; // not a callout or unresolvable base member
IType requiredBaseType = baseMember.getDeclaringType();
if (!TypeHelper.isRole(destinationType.getFlags())) {
String msg = NLS.bind(RefactoringMessages.PullUpAdaptor_calloutToNonRole_error, method.getElementName());
status.addFatalError(msg, JavaStatusContext.create(method));
} else {
IRoleType roleType = (IRoleType) OTModelManager.getOTElement(destinationType);
IType baseClass = roleType.getBaseClass();
if (baseClass == null) {
String msg = NLS.bind(RefactoringMessages.PullUpAdaptor_calloutToUnboundRole_error, method.getElementName());
status.addFatalError(msg, JavaStatusContext.create(method));
} else if (!requiredBaseType.equals(baseClass)) {
IJavaElement[] elements = new IJavaElement[]{requiredBaseType, baseClass};
ASTParser astParser = ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL);
astParser.setProject(method.getDeclaringType().getJavaProject());
IBinding[] bindings = astParser.createBindings(elements, pm);
ITypeBinding requiredBaseBinding = (ITypeBinding)bindings[0];
ITypeBinding baseOfDestination = (ITypeBinding)bindings[1];
if (!baseOfDestination.isAssignmentCompatible(requiredBaseBinding)) {
String msg = NLS.bind(RefactoringMessages.PullUpAdaptor_calloutBaseNotBoundInDest_error,
new Object[]{method.getElementName(), destinationType.getElementName(), baseMember.getElementName()});
status.addFatalError(msg, JavaStatusContext.create(method));
}
}
}
}
private RefactoringStatus checkOverloadingAndAmbiguityInType(IProgressMonitor pm, IType type) throws JavaModelException {
RefactoringStatus status = new RefactoringStatus();
ITypeHierarchy hier = getDestinationTypeHierarchy(pm);
for (int i = 0; i < getFMembersToMove().length; i++) {
IMember element = getFMembersToMove()[i];
if (element instanceof IMethod){
final IMethod method = (IMethod)element;
String[] paramTypes = method.getParameterTypes();
status.merge(RefactoringUtil.checkOverloadingAndAmbiguity(type, hier, method.getElementName(), paramTypes,
new IAmbuguityMessageCreator() {
public String createAmbiguousMethodSpecifierMsg() {
return RefactoringMessages.PullUpAdaptor_ambiguousMethodSpec_error;
}
}, new IOverloadingMessageCreator() {
public String createOverloadingMessage() {
String msg = NLS.bind(RefactoringMessages.PullUpAdaptor_overloading_error, method.getElementName());
return msg;
}
}, pm));
}
}
return status;
}
private RefactoringStatus checkOverloadingAndAmbiguity(IProgressMonitor pm) throws JavaModelException {
ITypeHierarchy destinationTypeHierarchy = getDestinationTypeHierarchy(pm);
IType[] subtypes = destinationTypeHierarchy.getAllSubtypes(getDestinationType());
pm.beginTask(RefactoringMessages.PullUpAdaptor_checkOverloading_progress, subtypes.length + 1);
pm.subTask(""); //$NON-NLS-1$
RefactoringStatus status = new RefactoringStatus();
// check overloading in destination type
status.merge(checkOverloadingAndAmbiguityInType(pm, getDestinationType()));
pm.worked(1);
// do not repeat errors in hierarchy
if(status.hasFatalError()){
pm.done();
return status;
}
// check overloading in subtypes of the destination type
for (int i = 0; i < subtypes.length; i++) {
status.merge(checkOverloadingAndAmbiguityInType(pm, subtypes[i]));
pm.worked(1);
// do not repeat errors in hierarchy
if(status.hasFatalError()){
pm.done();
return status;
}
}
pm.done();
return status;
}
private RefactoringStatus checkOverriding(IProgressMonitor pm) throws JavaModelException{
RefactoringStatus status = new RefactoringStatus();
ITypeHierarchy hier = getDestinationTypeHierarchy(pm);
ArrayList<IType> allSubTypes = new ArrayList<IType>();
allSubTypes.addAll(Arrays.asList(hier.getAllSubtypes(getDestinationType())));
// remove the subtypes of the declaring type
allSubTypes.removeAll(Arrays.asList(hier.getAllSubtypes(getDeclaringType())));
pm.beginTask(RefactoringMessages.PullUpAdaptor_checkOverriding_progress, allSubTypes.size());
pm.subTask(""); //$NON-NLS-1$
for (int i = 0; i < getFMembersToMove().length; i++) {
IMember element = getFMembersToMove()[i];
if(element instanceof IMethod){
IMethod method = (IMethod) element;
for (IType type : allSubTypes) {
IMethod overridingMethod = methodIsOverriddenInType(method.getElementName(), method.getParameterTypes(), type);
if(overridingMethod != null){
ArrayList<IMember> membersToMove = new ArrayList<IMember>();
membersToMove.addAll(Arrays.asList(getMembersToMove()));
ArrayList<IMember> membersToDelete = new ArrayList<IMember>();
membersToDelete.addAll(Arrays.asList(getMembersToDelete(pm)));
// do not indicate overriding for deleted/moved methods as an error
if(!membersToMove.contains(overridingMethod) && !membersToDelete.contains(overridingMethod)) {
String msg = NLS.bind(RefactoringMessages.PullUpAdaptor_overriding_error,
method.getElementName(),
type.getFullyQualifiedName('.'));
status.addError(msg, JavaStatusContext.create(overridingMethod));
}
}
pm.worked(1);
// do not repeat errors in hierarchy
if(status.hasError()){
pm.done();
return status;
}
}
}
}
pm.done();
return status;
}
private IMethod methodIsOverriddenInType(String methodName, String[] paramTypes, IType type){
IMethod method = type.getMethod(methodName, paramTypes);
if(method.exists()){
return method;
}
return null;
}
/**
* Searches for aspect bindings that reference members to be moved.
* @return The refactoring status contains warnings if any referencing aspect bindings exist.
*/
private RefactoringStatus checkForAspectBindings(IProgressMonitor monitor) throws CoreException {
// search all references for the members to be moved
IMember[] membersToMove = getMembersToMove();
final HashMap<IMember,Set<SearchMatch>> references= new HashMap<IMember,Set<SearchMatch>>();
IJavaSearchScope scope= SearchEngine.createWorkspaceScope();
for (int i = 0; i < membersToMove.length; i++) {
final IMember member = membersToMove[i];
// may not be able to access return type, but IGNORE_RETURN_TYPE is only effective with ALL_OCCURRENCES:
int limitTo = IJavaSearchConstants.ALL_OCCURRENCES|IJavaSearchConstants.IGNORE_RETURN_TYPE;
SearchPattern pattern= SearchPattern.createPattern(member, limitTo, SearchPattern.R_EXACT_MATCH);
SearchEngine engine= new SearchEngine();
engine.search(pattern, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant()}, scope, new SearchRequestor() {
public void acceptSearchMatch(SearchMatch match) throws CoreException {
if ( match.getAccuracy() == SearchMatch.A_ACCURATE
&& !match.isInsideDocComment()
&& !(match instanceof MethodDeclarationMatch)) // limit to references despite ALL_OCCURRENCES above:
{
if(references.get(member) == null){
Set<SearchMatch> refSet = new HashSet<SearchMatch>();
refSet.add(match);
references.put(member, refSet);
}else{
references.get(member).add(match);
}
}
}
}, monitor);
}
// search the matches for aspect bindings
RefactoringStatus status = new RefactoringStatus();
for (int i = 0; i < membersToMove.length; i++) {
IMember member = membersToMove[i];
Set<SearchMatch> refSet = references.get(member);
if(refSet == null){
continue;
}
for (SearchMatch match : refSet) {
Object element= match.getElement();
if (element instanceof ICalloutMapping) {
ICalloutMapping mapping = (ICalloutMapping) element;
IMethod boundBaseMethod = mapping.getBoundBaseMethod();
if (boundBaseMethod == null) {
addUnresolvedBaseMemberError(mapping, status, member);
} else if(boundBaseMethod.equals(member)){
addAspectBindingWarning(member, status, mapping);
}
}
if (element instanceof ICalloutToFieldMapping) {
ICalloutToFieldMapping mapping = (ICalloutToFieldMapping) element;
IField boundBaseField = mapping.getBoundBaseField();
if (boundBaseField == null) {
addUnresolvedBaseMemberError(mapping, status, member);
} else if(boundBaseField.equals(member)){
addAspectBindingWarning(member, status, mapping);
}
}
if (element instanceof ICallinMapping) {
ICallinMapping mapping = (ICallinMapping) element;
for (int j = 0; j < mapping.getBoundBaseMethods().length; j++) {
if(mapping.getBoundBaseMethods()[i].equals(member)){
addAspectBindingWarning(member, status, mapping);
break;
}
}
}
}
}
return status;
}
private void addUnresolvedBaseMemberError(IMethodMapping referencedMapping, RefactoringStatus status, IMember member)
{
status.addEntry(new RefactoringStatusEntry(RefactoringStatus.ERROR,
NLS.bind(RefactoringMessages.PullUpAdaptor_referencedCalloutUnresolvedBaseMember_error,
referencedMapping.getElementName(),
member.getElementName())));
}
/**
* Adds a warning to the given refactoring status that notifies the user about existing aspect bingings.
*
* @param member the member to be pulled up.
* @param status the refactoring status, where the warning should be added.
* @param mapping the method mapping that causes the warning.
*/
private void addAspectBindingWarning(IMember member, RefactoringStatus status,IMethodMapping mapping){
status.addEntry(new RefactoringStatusEntry(RefactoringStatus.WARNING,
NLS.bind(RefactoringMessages.PullUpAdaptor_referencedByMethodBinding_error,
member.getElementName(),
mapping.getDeclaringType().getFullyQualifiedName())));
}
/**
* Adds implicit role super types for roles. Candidate types are the possible super types,
* that are available as the destination type.
*/
callin IType[] getCandidateTypes(final RefactoringStatus status, final IProgressMonitor monitor) throws JavaModelException{
RefactoringStatus jdtStatus = new RefactoringStatus();
IType[] jdtCandidates = base.getCandidateTypes(jdtStatus, monitor);
final IType declaring= getDeclaringType();
// try to get the corresponding OTType that is represented in the declaring type
IOTType otType = OTModelManager.getOTElement(declaring);
if(otType != null && otType instanceof RoleType){
RoleType role = (RoleType) otType;
IType[] otSuperTypes = role.newTypeHierarchy(monitor).getAllSupertypes(declaring);
List<IType> list = new ArrayList<IType>();
int binary = 0;
for (int i = 0; i < otSuperTypes.length; i++) {
IType type = otSuperTypes[i];
if(OTModelManager.hasOTElementFor(otSuperTypes[i])){
IOTType otSuperType = OTModelManager.getOTElement(type);
if(otSuperType instanceof RoleType && type != null && type.exists() && !type.isReadOnly() && !type.isBinary()){
list.add(type);
}else if(type.isBinary()){
binary += 1;
}
}
}
if(!list.isEmpty()){
if(jdtStatus.hasFatalError()){
if (otSuperTypes.length == binary)
status.addFatalError(RefactoringCoreMessages.PullUPRefactoring_no_all_binary);
}else{
status.merge(jdtStatus);
}
Collections.reverse(list);
list.addAll(0,Arrays.asList(jdtCandidates));
return list.toArray(new IType[list.size()]);
}
}
status.merge(jdtStatus);
return jdtCandidates;
}
getCandidateTypes <- replace getCandidateTypes;
/**
* Prevents callin methods from visibility adjustments.
*/
callin boolean needsVisibilityAdjustment(final IMember member, final boolean references, final IProgressMonitor monitor, final RefactoringStatus status) throws JavaModelException {
boolean result = base.needsVisibilityAdjustment(member, references, monitor, status);
if(Flags.isCallin(member.getFlags())){
return false;
}else{
return result;
}
}
needsVisibilityAdjustment <- replace needsVisibilityAdjustment;
void createAbstractMethod(IMethod sourceMethod, CompilationUnitRewrite sourceRewriter, CompilationUnit declaringCuNode, AbstractTypeDeclaration destination, TypeVariableMaplet[] mapping, CompilationUnitRewrite targetRewrite, Map<IMember, IncomingMemberVisibilityAdjustment> adjustments, IProgressMonitor monitor, RefactoringStatus status)
<- replace void createAbstractMethod(IMethod sourceMethod, CompilationUnitRewrite sourceRewriter, CompilationUnit declaringCuNode, AbstractTypeDeclaration destination, TypeVariableMaplet[] mapping, CompilationUnitRewrite targetRewrite, Map<IMember, IncomingMemberVisibilityAdjustment> adjustments, IProgressMonitor monitor, RefactoringStatus status)
base when (sourceMethod instanceof IMethodMapping);
/** support creation of an abstract method from a callout mapping. */
@SuppressWarnings({ "inferredcallout", "basecall" })
callin void createAbstractMethod(IMethod sourceMethod, CompilationUnitRewrite sourceRewriter, CompilationUnit declaringCuNode, AbstractTypeDeclaration destination, TypeVariableMaplet[] mapping, CompilationUnitRewrite targetRewrite, Map<IMember, IncomingMemberVisibilityAdjustment> adjustments, IProgressMonitor monitor, RefactoringStatus status)
throws JavaModelException
{
// search callout decl, not method decl:
final CalloutMappingDeclaration oldCallout= getCalloutDeclarationNode(sourceMethod, declaringCuNode);
if (JavaModelUtil.is50OrHigher(sourceMethod.getJavaProject()) && (fSettings.overrideAnnotation || JavaCore.ERROR.equals(sourceMethod.getJavaProject().getOption(JavaCore.COMPILER_PB_MISSING_OVERRIDE_ANNOTATION, true)))) {
final MarkerAnnotation annotation= sourceRewriter.getAST().newMarkerAnnotation();
annotation.setTypeName(sourceRewriter.getAST().newSimpleName("Override")); //$NON-NLS-1$
sourceRewriter.getASTRewrite().getListRewrite(oldCallout, CalloutMappingDeclaration.MODIFIERS2_PROPERTY).insertFirst(annotation, sourceRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.PullUpRefactoring_add_override_annotation, SET_PULL_UP));
}
final MethodDeclaration newMethod= targetRewrite.getAST().newMethodDeclaration();
newMethod.setBody(null);
newMethod.setConstructor(false);
// callout has no extra dimensions:
// newMethod.setExtraDimensions(oldCallout.getExtraDimensions());
newMethod.setJavadoc(null);
int modifiers= getModifiersWithUpdatedVisibility(sourceMethod, Modifier.ABSTRACT | JdtFlags.clearFlag(Modifier.NATIVE | Modifier.FINAL, sourceMethod.getFlags()), adjustments, monitor, false, status);
// callout doesn't support varargs syntax:
// if (oldCallout.isVarargs())
// modifiers&= ~Flags.AccVarargs;
newMethod.modifiers().addAll(ASTNodeFactory.newModifiers(targetRewrite.getAST(), modifiers));
newMethod.setName(((SimpleName) ASTNode.copySubtree(targetRewrite.getAST(), oldCallout.getRoleMappingElement().getName())));
copyReturnType(targetRewrite.getASTRewrite(), getDeclaringType().getCompilationUnit(), (MethodSpec)oldCallout.getRoleMappingElement(), newMethod, mapping);
copyParameters(targetRewrite.getASTRewrite(), getDeclaringType().getCompilationUnit(), (MethodSpec)oldCallout.getRoleMappingElement(), newMethod, mapping);
// callout does not declare exceptions:
// copyThrownExceptions(oldCallout, newMethod);
ImportRewriteContext context= new ContextSensitiveImportRewriteContext(destination, targetRewrite.getImportRewrite());
ImportRewriteUtil.addImports(targetRewrite, context, newMethod, new HashMap<Name, String>(), new HashMap<Name, String>(), false);
targetRewrite.getASTRewrite().getListRewrite(destination, destination.getBodyDeclarationsProperty()).insertAt(newMethod, BodyDeclarationRewrite.getInsertionIndex(newMethod, destination.bodyDeclarations()), targetRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.PullUpRefactoring_add_abstract_method, SET_PULL_UP));
}
createChangeManager <- replace createChangeManager;
@SuppressWarnings("inferredcallout")
callin void createChangeManager(IProgressMonitor monitor, RefactoringStatus status) throws CoreException {
IType destinationType = getDestinationType();
IType declaringType = getDeclaringType();
this.changeManagerDetails = new ChangeManagerDetails(getCompilationUnitRewrite(fCompilationUnitRewrites, declaringType.getCompilationUnit()),
getCompilationUnitRewrite(fCompilationUnitRewrites, destinationType.getCompilationUnit()),
declaringType,
destinationType,
status,
monitor);
within (this)
base.createChangeManager(monitor, status);
}
void getMatchingCalloutsMapping(IType initial, Map<IMember, Set<IMember>> map)
<- after Map<IMember, Set<IMember>> getMatchingMembersMapping(IType initial)
with { initial <- initial, map <- result }
private void getMatchingCalloutsMapping(IType initial, Map<IMember, Set<IMember>> map) throws JavaModelException {
final IMember[] members= getCreatedDestinationMembers();
for (int i= 0; i < members.length; i++) {
final IMember member= members[i];
if (member instanceof IMethodMapping && !(member instanceof ICallinMapping)) {
IMethodMapping mapping = (IMethodMapping) member;
final IMethod found= findCalloutMethod((IMethod) mapping.getCorrespondingJavaElement(), initial);
if (found != null)
addMatchingMember(map, mapping, found);
}
}
}
private IMethod findCalloutMethod(IMethod roleMethod, IType initial) throws JavaModelException {
if (roleMethod == null) return null;
IOTType otType = OTModelManager.getOTElement(initial);
if (otType != null && otType.isRole()) {
IRoleType roleType = (IRoleType) otType;
String name = roleMethod.getElementName();
String[] paramTypes = roleMethod.getParameterTypes();
for (IMethodMapping mapping : roleType.getMethodMappings(IMethodMapping.CALLOUT_MAPPING|IMethodMapping.CALLOUT_TO_FIELD_MAPPING)) {
if (JavaModelUtil.isSameMethodSignature(name, paramTypes, false, (IMethod) mapping.getCorrespondingJavaElement()))
return (IMethod) mapping;
}
}
return null;
}
/** during createChangeManager we add callouts to the declaration nodes to be removed. */
protected class HierarchyProcRole playedBy HierarchyProcessor {
// Note: when defined in role PullUpRefactoringProcessorRole this currently triggers a VerifyError
// === for removal of old callout declarations: ===
List<ASTNode> getDeclarationNodes(CompilationUnit cuNode, List<IMember> members)
<- replace List<ASTNode> getDeclarationNodes(CompilationUnit cuNode, List<IMember> members);
static callin List<ASTNode> getDeclarationNodes(CompilationUnit cuNode, List<IMember> members)
throws JavaModelException
{
List<ASTNode> result = base.getDeclarationNodes(cuNode, members);
for (IMember member : members) {
ASTNode node= null;
if (member instanceof AbstractCalloutMapping)
node= getCalloutDeclarationNode((IMethod) member, cuNode);
if (node != null)
result.add(node);
}
return result;
}
}
/** during createChangeManager we intercept the visibility adjustments: */
protected class Adjustor playedBy MemberVisibilityAdjustor {
setAdjustments <- after setAdjustments;
private void setAdjustments(Map<IMember, IncomingMemberVisibilityAdjustment> map) {
PullUpRefactoringProcessorRole.this.changeManagerDetails.adjustments = map;
}
}
/** during createChangeManager we hook into getMethodDeclarationNode to handle callouts, too: */
protected class CalloutUtil playedBy ASTNodeSearchUtil {
getMethodDeclarationNode <- replace getMethodDeclarationNode
base when (!PullUpRefactoringProcessorRole.this.isExecutingCallin()); // inhibit callin trigger during getDeclarationNodes()
@SuppressWarnings("basecall")
static callin MethodDeclaration getMethodDeclarationNode(IMethod iMethod, CompilationUnit compilationUnit) throws JavaModelException {
if (iMethod instanceof AbstractCalloutMapping) {
// cf block inside org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoringProcessor.createChangeManager()
// which starts "} else if (member instanceof IMethod) {":
CalloutMappingDeclaration oldCallout = getCalloutDeclarationNode(iMethod, compilationUnit);
if (oldCallout != null) {
CompilationUnitRewrite sourceRewriter = PullUpRefactoringProcessorRole.this.changeManagerDetails.sourceRewrite;
CompilationUnitRewrite rewrite = PullUpRefactoringProcessorRole.this.changeManagerDetails.rewrite;
AbstractTypeDeclaration declaration = PullUpRefactoringProcessorRole.this.changeManagerDetails.declaration;
ImportRewriteContext context = PullUpRefactoringProcessorRole.this.changeManagerDetails.context;
RefactoringStatus status = PullUpRefactoringProcessorRole.this.changeManagerDetails.status;
TypeVariableMaplet[] mapping = PullUpRefactoringProcessorRole.this.changeManagerDetails.mapping;
Map<IMember, IncomingMemberVisibilityAdjustment> adjustments = PullUpRefactoringProcessorRole.this.changeManagerDetails.adjustments;
ASTRewrite rewriter = rewrite.getASTRewrite();
IProgressMonitor subsub = PullUpRefactoringProcessorRole.this.changeManagerDetails.monitor;
if (JdtFlags.isStatic(iMethod) && getDestinationType().isInterface())
status.merge(RefactoringStatus.createErrorStatus(Messages.format(RefactoringCoreMessages.PullUpRefactoring_moving_static_method_to_interface, new String[] { JavaElementLabels.getTextLabel(iMethod, JavaElementLabels.ALL_FULLY_QUALIFIED)}), JavaStatusContext.create(iMethod)));
CalloutMappingDeclaration newMethod= createNewCalloutDeclarationNode(sourceRewriter, rewrite, iMethod, oldCallout, mapping, adjustments, new SubProgressMonitor(subsub, 1), status);
rewriter.getListRewrite(declaration, declaration.getBodyDeclarationsProperty()).insertAt(newMethod, BodyDeclarationRewrite.getInsertionIndex(newMethod, declaration.bodyDeclarations()), rewrite.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_add_member, getSET_PULL_UP()));
ImportRewriteUtil.addImports(rewrite, context, oldCallout, new HashMap<Name, String>(), new HashMap<Name, String>(), false);
}
return null;
}
return base.getMethodDeclarationNode(iMethod, compilationUnit);
}
}
// ==== COPY&PASTE from base class, use MethodSpec as a template rather then MethodDeclaration: ====
@SuppressWarnings("inferredcallout")
protected void copyReturnType(ASTRewrite rewrite, ICompilationUnit unit, MethodSpec oldMethod, IMethodNode newMethod, TypeVariableMaplet[] mapping) throws JavaModelException {
Type newReturnType= null;
if (mapping.length > 0)
newReturnType= createPlaceholderForType(oldMethod.getReturnType2(), unit, mapping, rewrite);
else
newReturnType= createPlaceholderForType(oldMethod.getReturnType2(), unit, rewrite);
newMethod.setReturnType2(newReturnType);
}
@SuppressWarnings("inferredcallout")
protected void copyParameters(ASTRewrite rewrite, ICompilationUnit unit, MethodSpec oldMethod, IMethodNode newMethod, TypeVariableMaplet[] mapping) throws JavaModelException {
SingleVariableDeclaration newDeclaration= null;
for (int index= 0, size= oldMethod.parameters().size(); index < size; index++) {
final SingleVariableDeclaration oldDeclaration= (SingleVariableDeclaration) oldMethod.parameters().get(index);
if (mapping.length > 0)
newDeclaration= createPlaceholderForSingleVariableDeclaration(oldDeclaration, unit, mapping, rewrite);
else
newDeclaration= createPlaceholderForSingleVariableDeclaration(oldDeclaration, unit, rewrite);
newMethod.parameters().add(newDeclaration);
}
}
@SuppressWarnings("inferredcallout")
CalloutMappingDeclaration createNewCalloutDeclarationNode(CompilationUnitRewrite sourceRewrite, CompilationUnitRewrite targetRewrite,
IMethod sourceMethod, CalloutMappingDeclaration oldCallout, TypeVariableMaplet[] mapping, Map<IMember, IncomingMemberVisibilityAdjustment> adjustments, IProgressMonitor monitor, RefactoringStatus status)
throws JavaModelException
{
final ASTRewrite rewrite= targetRewrite.getASTRewrite();
final AST ast= rewrite.getAST();
final CalloutMappingDeclaration newCallout= ast.newCalloutMappingDeclaration();
// TODO: copy parameter mappings:
// if (!getDestinationType().isInterface())
// copyBodyOfPulledUpMethod(sourceRewrite, targetRewrite, sourceMethod, oldCallout, newMethod, mapping, monitor);
copyJavadocNode(rewrite, oldCallout, newCallout);
int modifiers= getModifiersWithUpdatedVisibility(sourceMethod, sourceMethod.getFlags(), adjustments, monitor, true, status);
// TODO
// copyAnnotations(oldCallout, newMethod);
newCallout.modifiers().addAll(ASTNodeFactory.newModifiers(ast, modifiers));
newCallout.setRoleMappingElement(createNewMethodSpec(ast, rewrite, mapping, (MethodSpec) oldCallout.getRoleMappingElement()));
MethodMappingElement baseMappingElement = oldCallout.getBaseMappingElement();
if (baseMappingElement instanceof MethodSpec) {
newCallout.setBaseMappingElement(createNewMethodSpec(ast, rewrite, mapping, (MethodSpec) baseMappingElement));
} else {
newCallout.setBaseMappingElement(createNewFieldSpec(ast, rewrite, mapping, (FieldAccessSpec) baseMappingElement));
newCallout.bindingOperator().setBindingModifier(ast.newModifier(oldCallout.bindingOperator().bindingModifier().getKeyword()));
}
newCallout.setSignatureFlag(oldCallout.hasSignature());
return newCallout;
}
MethodSpec createNewMethodSpec(AST ast, ASTRewrite rewrite, TypeVariableMaplet[] mapping, MethodSpec oldMethodSpec) throws JavaModelException {
MethodSpec newMethodSpec = ast.newMethodSpec();
newMethodSpec.setName(((SimpleName) ASTNode.copySubtree(ast, oldMethodSpec.getName())));
if (oldMethodSpec.hasSignature()) {
copyReturnType(rewrite, getDeclaringType().getCompilationUnit(), oldMethodSpec, newMethodSpec, mapping);
copyParameters(rewrite, getDeclaringType().getCompilationUnit(), oldMethodSpec, newMethodSpec, mapping);
newMethodSpec.setSignatureFlag(oldMethodSpec.hasSignature());
// copyTypeParameters(oldMethodSpec, newMethodSpec);
}
return newMethodSpec;
}
@SuppressWarnings("inferredcallout")
FieldAccessSpec createNewFieldSpec(AST ast, ASTRewrite rewrite, TypeVariableMaplet[] mapping, FieldAccessSpec oldFieldSpec) throws JavaModelException {
FieldAccessSpec newFieldSpec = ast.newFieldAccessSpec();
newFieldSpec.setName(((SimpleName) ASTNode.copySubtree(ast, oldFieldSpec.getName())));
if (oldFieldSpec.hasSignature()) {
Type newFielType= null;
if (mapping.length > 0)
newFielType= createPlaceholderForType(oldFieldSpec.getFieldType(), getDeclaringType().getCompilationUnit(), mapping, rewrite);
else
newFielType= createPlaceholderForType(oldFieldSpec.getFieldType(), getDeclaringType().getCompilationUnit(), rewrite);
newFieldSpec.setFieldType(newFielType);
newFieldSpec.setSignatureFlag(oldFieldSpec.hasSignature());
}
return newFieldSpec;
}
}
static CalloutMappingDeclaration getCalloutDeclarationNode(IMethod iMethod, CompilationUnit cuNode) throws JavaModelException {
ASTNode node = NodeFinder.perform(cuNode, iMethod.getNameRange());
return (CalloutMappingDeclaration)ASTNodes.getParent(node, CalloutMappingDeclaration.class);
}
/**
* Enable pull-up also for callout mappings.
*/
protected class Availability playedBy RefactoringAvailabilityTester {
boolean isPullUpAvailable(IMember member) <- replace boolean isPullUpAvailable(IMember member);
static callin boolean isPullUpAvailable(IMember member) throws JavaModelException {
if (base.isPullUpAvailable(member))
return true;
int kind = member.getElementType();
switch (kind) {
case IOTJavaElement.CALLOUT_MAPPING:
case IOTJavaElement.CALLOUT_TO_FIELD_MAPPING:
// extract from base method:
if (!member.exists())
return false;
if (!Checks.isAvailable(member))
return false;
return true;
default:
return false;
}
}
IMember[] getPullUpMembers(IType type) <- replace IMember[] getPullUpMembers(IType type);
static callin IMember[] getPullUpMembers(IType type) throws JavaModelException {
IMember[] result = base.getPullUpMembers(type);
if (OTModelManager.isRole(type)) {
List<IMember> callouts = new ArrayList<IMember>();
for (IJavaElement elem : type.getChildren()) {
switch (elem.getElementType()) {
case IOTJavaElement.CALLOUT_MAPPING:
case IOTJavaElement.CALLOUT_TO_FIELD_MAPPING:
callouts.add((IMember) elem);
}
}
if (callouts.size() > 0) {
int l1 = result.length, l2 = callouts.size();
IMember[] combined = new IMember[l1+l2];
callouts.toArray(combined);
System.arraycopy(result, 0, combined, l2, l1);
return combined;
}
}
return result;
}
}
/** Visibility checking for callout mappings. */
protected team class Visibility playedBy MemberVisibilityAdjustor {
IJavaElement getFReferencing() -> get IJavaElement fReferencing;
void adjustOutgoingVisibility(IMember member, ModifierKeyword threshold, String template)
-> void adjustOutgoingVisibility(IMember member, ModifierKeyword threshold, String template);
ModifierKeyword thresholdTypeToMethod(IType referencing, IMethod referenced, IProgressMonitor monitor)
-> ModifierKeyword thresholdTypeToMethod(IType referencing, IMethod referenced, IProgressMonitor monitor);
checkOTMember <- replace adjustOutgoingVisibilityChain;
@SuppressWarnings("basecall")
callin void checkOTMember(IMember member, IProgressMonitor monitor) throws JavaModelException {
try {
base.checkOTMember(member, monitor);
} catch (JavaModelException jme) {
// when a MethodDeclarationMatch reports a SourceMethod representation actually a callout mapping
// the method answers that it doesn't exist, that's what we intercept here:
if (jme.getJavaModelStatus().isDoesNotExist()) {
IType type = member.getDeclaringType();
IOTType ottype = OTModelManager.getOTElement(type);
if (ottype != null) {
if (ottype.isRole() && member instanceof IMethod) {
for (IMethodMapping map : ((IRoleType)ottype).getMethodMappings()) {
if (map.getElementType() != IMethodMapping.CALLIN_MAPPING
&& member.equals(map.getCorrespondingJavaElement()))
{
if (!Modifier.isPublic(map.getFlags())) {
final ModifierKeyword threshold= computeOutgoingVisibilityThreshold(map, monitor);
adjustOutgoingVisibility(map, threshold, RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_method_warning);
}
if (member.getDeclaringType() != null)
base.checkOTMember(member.getDeclaringType(), monitor);
return;
}
}
}
}
}
throw jme;
}
}
// adjusted copy, base version cannot handle OT elements
private ModifierKeyword computeOutgoingVisibilityThreshold(final IMember referenced, final IProgressMonitor monitor) throws JavaModelException {
final IJavaElement referencing = getFReferencing();
Assert.isTrue(referencing instanceof ICompilationUnit || referencing instanceof IType || referencing instanceof IPackageFragment);
ModifierKeyword keyword= ModifierKeyword.PUBLIC_KEYWORD;
try {
monitor.beginTask("", 1); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_checking);
final int referencingType= referencing.getElementType();
final int referencedType= referenced.getElementType();
switch (referencedType) {
case IOTJavaElement.CALLOUT_TO_FIELD_MAPPING:
case IOTJavaElement.CALLOUT_MAPPING: {
final IMethodMapping calloutReferenced= (IMethodMapping) referenced;
final ICompilationUnit referencedUnit= calloutReferenced.getCompilationUnit();
switch (referencingType) {
case IJavaElement.COMPILATION_UNIT: {
final ICompilationUnit unit= (ICompilationUnit) referencing;
if (referencedUnit != null && referencedUnit.equals(unit))
keyword= ModifierKeyword.PRIVATE_KEYWORD;
else if (referencedUnit != null && referencedUnit.getParent().equals(unit.getParent()))
keyword= null;
break;
}
case IJavaElement.TYPE: {
keyword= thresholdTypeToMethod((IType) referencing,
(IMethod) calloutReferenced.getCorrespondingJavaElement(), monitor);
break;
}
case IJavaElement.PACKAGE_FRAGMENT: {
final IPackageFragment fragment= (IPackageFragment) referencing;
if (calloutReferenced.getDeclaringType().getPackageFragment().equals(fragment))
keyword= null;
break;
}
default:
Assert.isTrue(false);
}
break;
}
default:
Assert.isTrue(false);
}
} finally {
monitor.done();
}
return keyword;
}
// simple adjustment: for visibility checks in incoming direction the corresponding IMethod suffices:
ModifierKeyword getVisibilityThreshold(IMember referenced)
<- replace ModifierKeyword getVisibilityThreshold(IJavaElement referencing, IMember referenced, IProgressMonitor monitor)
base when(referenced instanceof AbstractCalloutMapping)
with { referenced <- referenced, result -> result }
callin ModifierKeyword getVisibilityThreshold(IMember referencedMovedElement) throws JavaModelException {
IMethod method = (IMethod) ((AbstractCalloutMapping)referencedMovedElement).getCorrespondingJavaElement();
return base.getVisibilityThreshold(method);
}
adjustVisibility <- replace adjustVisibility;
// --- during adjustMemberVisibility don't find decapsulating base method references:
callin void adjustVisibility() throws JavaModelException {
within (this) base.adjustVisibility();
}
protected class Search playedBy BasicSearchEngine {
searchDeclarations <- before searchDeclarations;
private void searchDeclarations(IJavaElement element, SearchRequestor requestor, SearchPattern pattern, IProgressMonitor monitor) {
if (pattern instanceof MethodPattern)
((MethodPattern) pattern).findDecapsulationReferences = false;
}
}
// ---
}
/**
* Method ReferenceFinderUtil.getMethodsReferencedIn
* should also report callout mappings as methods.
*/
protected class ReferenceFinder playedBy ReferenceFinderUtil {
/** Adapt the method that filters METHOD elements. */
Set<IJavaElement> extractMethods(SearchMatch[] searchResults)
<- replace Set<IJavaElement> extractElements(SearchMatch[] searchResults, int elementType)
base when (elementType == IJavaElement.METHOD);
@SuppressWarnings("basecall")
static callin Set<IJavaElement> extractMethods( SearchMatch[] searchResults) {
Set<IJavaElement> elements= new HashSet<IJavaElement>();
for (int i= 0; i < searchResults.length; i++) {
IJavaElement el= SearchUtils.getEnclosingJavaElement(searchResults[i]);
if (el instanceof IMember) {
el = methodOrCallout((IMember) el);
if (el != null)
elements.add(el);
}
}
return elements;
}
static IJavaElement methodOrCallout(IMember member) {
int memberType = member.getElementType();
if (member.exists()) {
switch (memberType) {
case IJavaElement.METHOD:
case IOTJavaElement.CALLOUT_MAPPING:
case IOTJavaElement.CALLOUT_TO_FIELD_MAPPING:
return member;
default:
return null;
}
}
if (memberType == IJavaElement.METHOD) {
// search a callout mapping that might be "equal" to this method:
IType type = member.getDeclaringType();
try {
for (IJavaElement child : type.getChildren()) {
int elementType = child.getElementType();
if (elementType == IOTJavaElement.CALLOUT_MAPPING || elementType == IOTJavaElement.CALLOUT_TO_FIELD_MAPPING) {
AbstractCalloutMapping map = (AbstractCalloutMapping) child;
if (member.equals(map.getCorrespondingJavaElement())) {
return map;
}
}
}
} catch (JavaModelException e) {
return null;
}
}
return null;
}
}
/** Help the first wizard page to avoid illegal settings (impossible pull-up of callout). */
protected team class WizardPage playedBy PullUpMemberPage {
/** Gateway to a private inner class: */
protected class MemberActionInfo playedBy MemberActionInfo {
int getNO_ACTION() -> get int NO_ACTION;
protected IMember getMember() -> IMember getMember();
protected boolean hasAction() -> int getAction()
with { result <- result != getNO_ACTION() }
protected void setAction(int action) -> void setAction(int action);
}
int getDECLARE_ABSTRACT_ACTION() -> get int DECLARE_ABSTRACT_ACTION;
int getPULL_UP_ACTION() -> get int PULL_UP_ACTION;
MemberActionInfo[] getTableInput() -> MemberActionInfo[] getTableInput();
IType getDestinationType() -> IType getDestinationType();
checkActionForCallouts <- before updateWizardPage;
void checkActionForCallouts() {
MemberActionInfo[] infos = getTableInput();
for (MemberActionInfo info : infos) {
if (!info.hasAction()) continue;
IMember member = info.getMember();
if (member instanceof AbstractCalloutMapping) {
RefactoringStatus status = new RefactoringStatus();
boolean haveError = false;
try {
PullUpRefactoringProcessorRole.checkDestinationForCallout((IMethod)member, getDestinationType(), status, new NullProgressMonitor());
haveError = status.hasFatalError();
} catch (JavaModelException e) {
haveError = true;
}
if (haveError) {
info.setAction(getDECLARE_ABSTRACT_ACTION());
}
}
}
}
}
protected class UseSuperTypeFix playedBy SuperTypeRefactoringProcessor {
// === tell the base class how to cope with LiftingType references: ===
void rewriteTypeOccurrence(TType arg0, CompilationUnitRewrite arg1, ASTNode arg2, TextEditGroup arg3)
-> void rewriteTypeOccurrence(TType arg0, CompilationUnitRewrite arg1, ASTNode arg2, TextEditGroup arg3);
void rewriteTypeOccurrence(final CompilationUnitRange range, final TType estimate, final ASTRequestor requestor, final CompilationUnitRewrite rewrite, final CompilationUnit copy, final Set<String> replacements, final TextEditGroup group)
<- after
void rewriteTypeOccurrence(final CompilationUnitRange range, final TType estimate, final ASTRequestor requestor, final CompilationUnitRewrite rewrite, final CompilationUnit copy, final Set<String> replacements, final TextEditGroup group);
private void rewriteTypeOccurrence(CompilationUnitRange range, TType estimate, ASTRequestor requestor, CompilationUnitRewrite rewrite, CompilationUnit copy, Set<String> replacements, TextEditGroup group)
{
ASTNode node= null;
IBinding binding= null;
final CompilationUnit target= rewrite.getRoot();
node= NodeFinder.perform(copy, range.getSourceRange());
if (node != null) {
node= ASTNodes.getNormalizedNode(node);
// OT: remember whether we saw the base side or the role side of a LiftingType:
StructuralPropertyDescriptor locationInParent = node.getLocationInParent();
node = node.getParent();
if (node instanceof LiftingType) {
// climb up one more step than base method does to find the argument (LT only occurs as an argument's type):
VariableDeclaration argument = (VariableDeclaration) node.getParent();
binding= argument.resolveBinding();
node= target.findDeclaringNode(binding.getKey());
if (node instanceof SingleVariableDeclaration) {
// OT: drill into detail of LiftingType:
ASTNode oldTypeNode = (ASTNode)((SingleVariableDeclaration)node).getType().getStructuralProperty(locationInParent);
rewriteTypeOccurrence(estimate, rewrite, oldTypeNode, group);
if (node.getParent() instanceof MethodDeclaration) {
binding= ((VariableDeclaration) node).resolveBinding();
if (binding != null)
replacements.add(binding.getKey());
}
}
}
}
}
}
}