0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.jdt.internal.corext.refactoring.code;
0011:
0012: import java.lang.reflect.Modifier;
0013: import java.util.ArrayList;
0014: import java.util.Arrays;
0015: import java.util.HashMap;
0016: import java.util.Iterator;
0017: import java.util.List;
0018: import java.util.Map;
0019:
0020: import org.eclipse.core.runtime.Assert;
0021: import org.eclipse.core.runtime.CoreException;
0022: import org.eclipse.core.runtime.IProgressMonitor;
0023: import org.eclipse.core.runtime.NullProgressMonitor;
0024: import org.eclipse.core.runtime.OperationCanceledException;
0025: import org.eclipse.core.runtime.SubProgressMonitor;
0026:
0027: import org.eclipse.core.resources.IFile;
0028:
0029: import org.eclipse.ltk.core.refactoring.Change;
0030: import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
0031: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
0032: import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
0033:
0034: import org.eclipse.jdt.core.Flags;
0035: import org.eclipse.jdt.core.IClassFile;
0036: import org.eclipse.jdt.core.ICompilationUnit;
0037: import org.eclipse.jdt.core.IJavaElement;
0038: import org.eclipse.jdt.core.IJavaProject;
0039: import org.eclipse.jdt.core.IMember;
0040: import org.eclipse.jdt.core.IMethod;
0041: import org.eclipse.jdt.core.IPackageFragment;
0042: import org.eclipse.jdt.core.IType;
0043: import org.eclipse.jdt.core.ITypeHierarchy;
0044: import org.eclipse.jdt.core.JavaModelException;
0045: import org.eclipse.jdt.core.dom.AST;
0046: import org.eclipse.jdt.core.dom.ASTNode;
0047: import org.eclipse.jdt.core.dom.ASTParser;
0048: import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
0049: import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
0050: import org.eclipse.jdt.core.dom.Block;
0051: import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
0052: import org.eclipse.jdt.core.dom.CompilationUnit;
0053: import org.eclipse.jdt.core.dom.Expression;
0054: import org.eclipse.jdt.core.dom.ExpressionStatement;
0055: import org.eclipse.jdt.core.dom.IBinding;
0056: import org.eclipse.jdt.core.dom.IMethodBinding;
0057: import org.eclipse.jdt.core.dom.ITypeBinding;
0058: import org.eclipse.jdt.core.dom.Javadoc;
0059: import org.eclipse.jdt.core.dom.MethodDeclaration;
0060: import org.eclipse.jdt.core.dom.MethodInvocation;
0061: import org.eclipse.jdt.core.dom.Name;
0062: import org.eclipse.jdt.core.dom.ParameterizedType;
0063: import org.eclipse.jdt.core.dom.PrimitiveType;
0064: import org.eclipse.jdt.core.dom.ReturnStatement;
0065: import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
0066: import org.eclipse.jdt.core.dom.Statement;
0067: import org.eclipse.jdt.core.dom.SuperMethodInvocation;
0068: import org.eclipse.jdt.core.dom.ThisExpression;
0069: import org.eclipse.jdt.core.dom.Type;
0070: import org.eclipse.jdt.core.dom.TypeParameter;
0071: import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
0072: import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
0073: import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
0074: import org.eclipse.jdt.core.refactoring.descriptors.IntroduceIndirectionDescriptor;
0075: import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
0076: import org.eclipse.jdt.core.search.IJavaSearchConstants;
0077: import org.eclipse.jdt.core.search.IJavaSearchScope;
0078: import org.eclipse.jdt.core.search.SearchMatch;
0079: import org.eclipse.jdt.core.search.SearchPattern;
0080:
0081: import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
0082: import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
0083: import org.eclipse.jdt.internal.corext.dom.ASTNodes;
0084: import org.eclipse.jdt.internal.corext.dom.Bindings;
0085: import org.eclipse.jdt.internal.corext.dom.NodeFinder;
0086: import org.eclipse.jdt.internal.corext.refactoring.Checks;
0087: import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
0088: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
0089: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
0090: import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
0091: import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
0092: import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
0093: import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
0094: import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
0095: import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
0096: import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange;
0097: import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
0098: import org.eclipse.jdt.internal.corext.refactoring.rename.RippleMethodFinder2;
0099: import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil;
0100: import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
0101: import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor;
0102: import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
0103: import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
0104: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
0105: import org.eclipse.jdt.internal.corext.util.JdtFlags;
0106: import org.eclipse.jdt.internal.corext.util.Messages;
0107: import org.eclipse.jdt.internal.corext.util.MethodOverrideTester;
0108:
0109: import org.eclipse.jdt.ui.CodeGeneration;
0110: import org.eclipse.jdt.ui.JavaElementLabels;
0111:
0112: import org.eclipse.jdt.internal.ui.JavaPlugin;
0113:
0114: /**
0115: *
0116: * This refactoring creates a wrapper around a certain method and redirects callers of the original
0117: * method to the newly created method (called "intermediary method").
0118: *
0119: * If invoked on a method call, the user may select whether to only update the selected call or
0120: * all other calls as well. If invoked on a method declaration, the user may select whether to
0121: * update calls at all. An intermediary method will be created in both cases.
0122: *
0123: * Creating indirections is possible for both source and binary methods. Select an invocation of the method or
0124: * the declaring method itself, for example in the outline view.
0125: *
0126: * Note that in case of methods inside generic types, the parameters of the declaring type of the selected method
0127: * will be added to the method definition, rendering it generic as well.
0128: *
0129: * If any of the calls cannot see the intermediary method due to visibility problems with enclosing types
0130: * of the intermediary method, visibility will be adjusted. If the intermediary method is not able to
0131: * see the target method, this refactoring will try to adjust the visibility of the target method and
0132: * enclosing types as well. However, the latter is only possible if the target method is from source.
0133: *
0134: * @since 3.2
0135: *
0136: */
0137: public class IntroduceIndirectionRefactoring extends
0138: ScriptableRefactoring {
0139:
0140: /**
0141: * The compilation unit in which the user invoked this refactoring (if any)
0142: */
0143: private ICompilationUnit fSelectionCompilationUnit;
0144: /**
0145: * The class file (with source) in which the user invoked this refactoring (if any)
0146: */
0147: private IClassFile fSelectionClassFile;
0148: /**
0149: * The start of the user selection inside the selected
0150: * compilation unit (if any)
0151: */
0152: private int fSelectionStart;
0153: /**
0154: * The length of the user selection inside the selected
0155: * compilation unit (if any)
0156: */
0157: private int fSelectionLength;
0158: /**
0159: * The selected MethodInvocation (if any). This field is used
0160: * to update this particular invocation in non-reference mode.
0161: */
0162: private MethodInvocation fSelectionMethodInvocation;
0163:
0164: // Intermediary information:
0165:
0166: /**
0167: * The class in which to place the intermediary method
0168: */
0169: private IType fIntermediaryClass;
0170: /**
0171: * The binding of the intermediary class
0172: */
0173: private ITypeBinding fIntermediaryClassBinding;
0174: /**
0175: * The name of the intermediary method
0176: */
0177: private String fIntermediaryMethodName;
0178: /**
0179: * The type for the additional parameter for the intermediary. This
0180: * type is determined from all known references.
0181: */
0182: private ITypeBinding fIntermediaryFirstParameterType;
0183:
0184: // Target information:
0185:
0186: /**
0187: * The originally selected target method (i.e., the one to be encapsulated)
0188: */
0189: private IMethod fTargetMethod;
0190: /**
0191: * The binding of the originally selected target method
0192: */
0193: private IMethodBinding fTargetMethodBinding;
0194:
0195: // Other information:
0196:
0197: /**
0198: * If true, all references to the target method are replaced with calls to
0199: * the intermediary.
0200: */
0201: private boolean fUpdateReferences;
0202: /**
0203: * CompilationUnitRewrites for all affected cus
0204: */
0205: private Map/* <ICompilationUnit,CompilationUnitRewrite> */fRewrites;
0206: /**
0207: * Text change manager (actually a CompilationUnitChange manager) which
0208: * manages all changes.
0209: */
0210: private TextChangeManager fTextChangeManager;
0211:
0212: // Visibility
0213:
0214: /**
0215: * The visibility adjustor
0216: */
0217: private MemberVisibilityAdjustor fAdjustor;
0218: /**
0219: * Visibility adjustments for the intermediary
0220: */
0221: private Map/*IMember, IVisibilityAdjustment*/fIntermediaryAdjustments;
0222:
0223: private class NoOverrideProgressMonitor extends SubProgressMonitor {
0224:
0225: public NoOverrideProgressMonitor(IProgressMonitor monitor,
0226: int ticks) {
0227: super (monitor, ticks,
0228: SubProgressMonitor.SUPPRESS_SUBTASK_LABEL);
0229: }
0230:
0231: public void setTaskName(String name) {
0232: // do nothing
0233: }
0234: }
0235:
0236: // ********* CONSTRUCTORS AND CLASS CREATION ************
0237:
0238: public IntroduceIndirectionRefactoring(ICompilationUnit unit,
0239: int offset, int length) {
0240: fSelectionCompilationUnit = unit;
0241: initialize(offset, length);
0242: }
0243:
0244: public IntroduceIndirectionRefactoring(IClassFile file, int offset,
0245: int length) {
0246: fSelectionClassFile = file;
0247: initialize(offset, length);
0248: }
0249:
0250: public IntroduceIndirectionRefactoring(IMethod method) {
0251: fTargetMethod = method;
0252: initialize(0, 0);
0253: }
0254:
0255: private void initialize(int offset, int length) {
0256: fSelectionStart = offset;
0257: fSelectionLength = length;
0258: fUpdateReferences = true;
0259: }
0260:
0261: // ********* UI INTERACTION AND STARTUP OPTIONS ************
0262:
0263: public String getName() {
0264: return RefactoringCoreMessages.IntroduceIndirectionRefactoring_introduce_indirection_name;
0265: }
0266:
0267: public IJavaProject getProject() {
0268: if (fSelectionCompilationUnit != null)
0269: return fSelectionCompilationUnit.getJavaProject();
0270: if (fSelectionClassFile != null)
0271: return fSelectionClassFile.getJavaProject();
0272: if (fTargetMethod != null)
0273: return fTargetMethod.getJavaProject();
0274: return null;
0275: }
0276:
0277: public IPackageFragment getInvocationPackage() {
0278: return fSelectionCompilationUnit != null ? (IPackageFragment) fSelectionCompilationUnit
0279: .getAncestor(IJavaElement.PACKAGE_FRAGMENT)
0280: : null;
0281: }
0282:
0283: public boolean canEnableUpdateReferences() {
0284: return true;
0285: }
0286:
0287: public void setEnableUpdateReferences(boolean updateReferences) {
0288: fUpdateReferences = updateReferences;
0289: }
0290:
0291: public RefactoringStatus setIntermediaryMethodName(
0292: String newMethodName) {
0293: Assert.isNotNull(newMethodName);
0294: fIntermediaryMethodName = newMethodName;
0295: IJavaElement context = fIntermediaryClass != null ? fIntermediaryClass
0296: : (IMember) fTargetMethod;
0297: RefactoringStatus stat = Checks.checkMethodName(newMethodName,
0298: context);
0299: stat.merge(checkOverloading());
0300: return stat;
0301: }
0302:
0303: private RefactoringStatus checkOverloading() {
0304: try {
0305: if (fIntermediaryClass != null) {
0306: IMethod[] toCheck = fIntermediaryClass.getMethods();
0307: for (int i = 0; i < toCheck.length; i++) {
0308: IMethod method = toCheck[i];
0309: if (method.getElementName().equals(
0310: fIntermediaryMethodName))
0311: return RefactoringStatus
0312: .createWarningStatus(Messages
0313: .format(
0314: RefactoringCoreMessages.IntroduceIndirectionRefactoring_duplicate_method_name_in_declaring_class_error,
0315: fIntermediaryMethodName));
0316: }
0317: }
0318: } catch (JavaModelException e) {
0319: return RefactoringStatus
0320: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_could_not_parse_declaring_class_error);
0321: }
0322: return new RefactoringStatus();
0323: }
0324:
0325: public String getIntermediaryMethodName() {
0326: return fIntermediaryMethodName;
0327: }
0328:
0329: /**
0330: * @param fullyQualifiedTypeName
0331: * @return status for type name. Use {@link #setIntermediaryMethodName(String)} to check for overridden methods.
0332: */
0333: public RefactoringStatus setIntermediaryClassName(
0334: String fullyQualifiedTypeName) {
0335: IType target = null;
0336:
0337: try {
0338: if (fullyQualifiedTypeName.length() == 0)
0339: return RefactoringStatus
0340: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_class_not_selected_error);
0341:
0342: // find type (now including secondaries)
0343: target = getProject().findType(fullyQualifiedTypeName,
0344: new NullProgressMonitor());
0345: if (target == null || !target.exists())
0346: return RefactoringStatus
0347: .createErrorStatus(Messages
0348: .format(
0349: RefactoringCoreMessages.IntroduceIndirectionRefactoring_class_does_not_exist_error,
0350: fullyQualifiedTypeName));
0351: if (target.isAnnotation())
0352: return RefactoringStatus
0353: .createErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_create_in_annotation);
0354: if (target.isInterface())
0355: return RefactoringStatus
0356: .createErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_create_on_interface);
0357: } catch (JavaModelException e) {
0358: return RefactoringStatus
0359: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_unable_determine_declaring_type);
0360: }
0361:
0362: if (target.isReadOnly())
0363: return RefactoringStatus
0364: .createErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_create_in_readonly);
0365:
0366: if (target.isBinary())
0367: return RefactoringStatus
0368: .createErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_create_in_binary);
0369:
0370: fIntermediaryClass = target;
0371:
0372: return new RefactoringStatus();
0373: }
0374:
0375: /**
0376: * Returns the class name of the intermediary class, or the empty string if none has been set yet.
0377: * @return the intermediary class name or the empty string
0378: */
0379: public String getIntermediaryClassName() {
0380: return fIntermediaryClass != null ? JavaModelUtil
0381: .getFullyQualifiedName(fIntermediaryClass) : ""; //$NON-NLS-1$
0382: }
0383:
0384: // ********** CONDITION CHECKING **********
0385:
0386: public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
0387: throws CoreException, OperationCanceledException {
0388: try {
0389: pm
0390: .beginTask(
0391: RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_activation,
0392: 1);
0393: fRewrites = new HashMap();
0394:
0395: // This refactoring has been invoked on
0396: // (1) a TextSelection inside an ICompilationUnit or inside an IClassFile (definitely with source), or
0397: // (2) an IMethod inside a ICompilationUnit or inside an IClassFile (with or without source)
0398:
0399: if (fTargetMethod == null) {
0400: // (1) invoked on a text selection
0401:
0402: if (fSelectionStart == 0)
0403: return RefactoringStatus
0404: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_on_this _selection);
0405:
0406: // if a text selection exists, source is available.
0407: CompilationUnit selectionCURoot;
0408: ASTNode selectionNode;
0409: if (fSelectionCompilationUnit != null) {
0410: // compilation unit - could use CuRewrite later on
0411: selectionCURoot = getCachedCURewrite(
0412: fSelectionCompilationUnit).getRoot();
0413: selectionNode = getSelectedNode(
0414: fSelectionCompilationUnit, selectionCURoot,
0415: fSelectionStart, fSelectionLength);
0416: } else {
0417: // binary class file - no cu rewrite
0418: ASTParser parser = ASTParser.newParser(AST.JLS3);
0419: parser.setResolveBindings(true);
0420: parser.setSource(fSelectionClassFile);
0421: selectionCURoot = (CompilationUnit) parser
0422: .createAST(null);
0423: selectionNode = getSelectedNode(null,
0424: selectionCURoot, fSelectionStart,
0425: fSelectionLength);
0426: }
0427:
0428: if (selectionNode == null)
0429: return RefactoringStatus
0430: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_on_this _selection);
0431:
0432: IMethodBinding targetMethodBinding = null;
0433:
0434: if (selectionNode.getNodeType() == ASTNode.METHOD_INVOCATION) {
0435: targetMethodBinding = ((MethodInvocation) selectionNode)
0436: .resolveMethodBinding();
0437: } else if (selectionNode.getNodeType() == ASTNode.METHOD_DECLARATION) {
0438: targetMethodBinding = ((MethodDeclaration) selectionNode)
0439: .resolveBinding();
0440: } else if (selectionNode.getNodeType() == ASTNode.SUPER_METHOD_INVOCATION) {
0441: // Allow invocation on super methods calls. makes sense as other
0442: // calls or even only the declaration can be updated.
0443: targetMethodBinding = ((SuperMethodInvocation) selectionNode)
0444: .resolveMethodBinding();
0445: } else {
0446: return RefactoringStatus
0447: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_on_this _selection);
0448: }
0449: fTargetMethodBinding = targetMethodBinding
0450: .getMethodDeclaration(); // resolve generics
0451: fTargetMethod = (IMethod) fTargetMethodBinding
0452: .getJavaElement();
0453:
0454: //allow single updating mode if an invocation was selected and the invocation can be updated
0455: if (selectionNode instanceof MethodInvocation
0456: && fSelectionCompilationUnit != null)
0457: fSelectionMethodInvocation = (MethodInvocation) selectionNode;
0458:
0459: } else {
0460: // (2) invoked on an IMethod: Source may not be available
0461:
0462: if (fTargetMethod.getDeclaringType().isAnnotation())
0463: return RefactoringStatus
0464: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_on_annotation);
0465:
0466: if (fTargetMethod.getCompilationUnit() != null) {
0467: // source method
0468: CompilationUnit selectionCURoot = getCachedCURewrite(
0469: fTargetMethod.getCompilationUnit())
0470: .getRoot();
0471: MethodDeclaration declaration = ASTNodeSearchUtil
0472: .getMethodDeclarationNode(fTargetMethod,
0473: selectionCURoot);
0474: fTargetMethodBinding = declaration.resolveBinding()
0475: .getMethodDeclaration();
0476: } else {
0477: // binary method - no CURewrite available (and none needed as we cannot update the method anyway)
0478: ASTParser parser = ASTParser.newParser(AST.JLS3);
0479: parser.setProject(fTargetMethod.getJavaProject());
0480: IBinding[] bindings = parser.createBindings(
0481: new IJavaElement[] { fTargetMethod }, null);
0482: fTargetMethodBinding = ((IMethodBinding) bindings[0])
0483: .getMethodDeclaration();
0484: }
0485: }
0486:
0487: if (fTargetMethod == null
0488: || fTargetMethodBinding == null
0489: || (!RefactoringAvailabilityTester
0490: .isIntroduceIndirectionAvailable(fTargetMethod)))
0491: return RefactoringStatus
0492: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_on_this _selection);
0493:
0494: if (fTargetMethod.getDeclaringType().isLocal()
0495: || fTargetMethod.getDeclaringType().isAnonymous())
0496: return RefactoringStatus
0497: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_for_local_or_anonymous_types);
0498:
0499: if (fTargetMethod.isConstructor())
0500: return RefactoringStatus
0501: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_for_constructors);
0502:
0503: if (fIntermediaryMethodName == null)
0504: fIntermediaryMethodName = fTargetMethod
0505: .getElementName();
0506:
0507: if (fIntermediaryClass == null) {
0508: if (fSelectionCompilationUnit != null
0509: && !fSelectionCompilationUnit.isReadOnly())
0510: fIntermediaryClass = getEnclosingInitialSelectionMember()
0511: .getDeclaringType();
0512: else if (!fTargetMethod.isBinary()
0513: && !fTargetMethod.isReadOnly())
0514: fIntermediaryClass = fTargetMethod
0515: .getDeclaringType();
0516: }
0517:
0518: return new RefactoringStatus();
0519: } finally {
0520: pm.done();
0521: }
0522: }
0523:
0524: public RefactoringStatus checkFinalConditions(IProgressMonitor pm)
0525: throws CoreException, OperationCanceledException {
0526:
0527: RefactoringStatus result = new RefactoringStatus();
0528: fTextChangeManager = new TextChangeManager();
0529: fIntermediaryFirstParameterType = null;
0530: fIntermediaryClassBinding = null;
0531: for (Iterator iter = fRewrites.values().iterator(); iter
0532: .hasNext();)
0533: ((CompilationUnitRewrite) iter.next())
0534: .clearASTAndImportRewrites();
0535:
0536: int startupTicks = 5;
0537: int hierarchyTicks = 5;
0538: int visibilityTicks = 5;
0539: int referenceTicks = fUpdateReferences ? 30 : 5;
0540: int creationTicks = 5;
0541:
0542: pm
0543: .beginTask(
0544: "", startupTicks + hierarchyTicks + visibilityTicks + referenceTicks + creationTicks); //$NON-NLS-1$
0545: pm
0546: .setTaskName(RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_conditions);
0547:
0548: result.merge(Checks.checkMethodName(fIntermediaryMethodName,
0549: fIntermediaryClass));
0550: if (result.hasFatalError())
0551: return result;
0552:
0553: if (fIntermediaryClass == null)
0554: return RefactoringStatus
0555: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_run_without_intermediary_type);
0556:
0557: // intermediary class is already non binary/non-enum/non-interface.
0558: CompilationUnitRewrite imRewrite = getCachedCURewrite(fIntermediaryClass
0559: .getCompilationUnit());
0560: fIntermediaryClassBinding = typeToBinding(fIntermediaryClass,
0561: imRewrite.getRoot());
0562:
0563: fAdjustor = new MemberVisibilityAdjustor(fIntermediaryClass,
0564: fIntermediaryClass);
0565: fIntermediaryAdjustments = new HashMap();
0566:
0567: // check static method in non-static nested type
0568: if (fIntermediaryClassBinding.isNested()
0569: && !Modifier.isStatic(fIntermediaryClassBinding
0570: .getModifiers()))
0571: return RefactoringStatus
0572: .createFatalErrorStatus(
0573: RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_create_in_nested_nonstatic,
0574: JavaStatusContext
0575: .create(fIntermediaryClass));
0576:
0577: pm.worked(startupTicks);
0578: if (pm.isCanceled())
0579: throw new OperationCanceledException();
0580:
0581: if (fUpdateReferences) {
0582: pm
0583: .setTaskName(RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_conditions
0584: + " " + RefactoringCoreMessages.IntroduceIndirectionRefactoring_looking_for_references); //$NON-NLS-1$
0585: result
0586: .merge(updateReferences(new NoOverrideProgressMonitor(
0587: pm, referenceTicks)));
0588: pm
0589: .setTaskName(RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_conditions);
0590: } else {
0591: // only update the declaration and/or a selected method invocation
0592: if (fSelectionMethodInvocation != null) {
0593: fIntermediaryFirstParameterType = getExpressionType(fSelectionMethodInvocation);
0594: final IMember enclosing = getEnclosingInitialSelectionMember();
0595: // create an edit for this particular call
0596: result.merge(updateMethodInvocation(
0597: fSelectionMethodInvocation, enclosing,
0598: getCachedCURewrite(fSelectionCompilationUnit)));
0599:
0600: if (!isRewriteKept(fSelectionCompilationUnit))
0601: createChangeAndDiscardRewrite(fSelectionCompilationUnit);
0602:
0603: // does call see the intermediary method?
0604: // => increase visibility of the type of the intermediary method.
0605: result.merge(adjustVisibility(fIntermediaryClass,
0606: enclosing.getDeclaringType(),
0607: new NoOverrideProgressMonitor(pm, 0)));
0608: }
0609: pm.worked(referenceTicks);
0610: }
0611:
0612: if (pm.isCanceled())
0613: throw new OperationCanceledException();
0614:
0615: if (fIntermediaryFirstParameterType == null)
0616: fIntermediaryFirstParameterType = fTargetMethodBinding
0617: .getDeclaringClass();
0618:
0619: // The target type and method may have changed - update them
0620:
0621: IType actualTargetType = (IType) fIntermediaryFirstParameterType
0622: .getJavaElement();
0623: if (!fTargetMethod.getDeclaringType().equals(actualTargetType)) {
0624: IMethod actualTargetMethod = new MethodOverrideTester(
0625: actualTargetType, actualTargetType
0626: .newSupertypeHierarchy(null))
0627: .findOverriddenMethodInHierarchy(actualTargetType,
0628: fTargetMethod);
0629: fTargetMethod = actualTargetMethod;
0630: fTargetMethodBinding = findMethodBindingInHierarchy(
0631: fIntermediaryFirstParameterType, actualTargetMethod);
0632: Assert.isNotNull(fTargetMethodBinding);
0633: }
0634:
0635: result.merge(checkCanCreateIntermediaryMethod());
0636: createIntermediaryMethod();
0637: pm.worked(creationTicks);
0638:
0639: pm
0640: .setTaskName(RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_conditions
0641: + " " + RefactoringCoreMessages.IntroduceIndirectionRefactoring_adjusting_visibility); //$NON-NLS-1$
0642: result
0643: .merge(updateTargetVisibility(new NoOverrideProgressMonitor(
0644: pm, 0)));
0645: result
0646: .merge(updateIntermediaryVisibility(new NoOverrideProgressMonitor(
0647: pm, 0)));
0648: pm.worked(visibilityTicks);
0649: pm
0650: .setTaskName(RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_conditions);
0651:
0652: createChangeAndDiscardRewrite(fIntermediaryClass
0653: .getCompilationUnit());
0654:
0655: result.merge(Checks.validateModifiesFiles(
0656: getAllFilesToModify(), getValidationContext()));
0657: pm.done();
0658:
0659: return result;
0660: }
0661:
0662: private RefactoringStatus updateTargetVisibility(
0663: IProgressMonitor monitor) throws JavaModelException,
0664: CoreException {
0665:
0666: RefactoringStatus result = new RefactoringStatus();
0667:
0668: // Adjust the visibility of the method and of the referenced type. Note that
0669: // the target method may not be in the target type; and in this case, the type
0670: // of the target method does not need a visibility adjustment.
0671:
0672: // This method is called after all other changes have been
0673: // created. Changes induced by this method will be attached to those changes.
0674:
0675: result
0676: .merge(adjustVisibility(
0677: (IType) fIntermediaryFirstParameterType
0678: .getJavaElement(), fIntermediaryClass,
0679: monitor));
0680: if (result.hasError())
0681: return result; // binary
0682:
0683: ModifierKeyword neededVisibility = getNeededVisibility(
0684: fTargetMethod, fIntermediaryClass);
0685: if (neededVisibility != null) {
0686:
0687: result.merge(adjustVisibility(fTargetMethod,
0688: neededVisibility, monitor));
0689: if (result.hasError())
0690: return result; // binary
0691:
0692: // Need to adjust the overridden methods of the target method.
0693: ITypeHierarchy hierarchy = fTargetMethod.getDeclaringType()
0694: .newTypeHierarchy(null);
0695: MethodOverrideTester tester = new MethodOverrideTester(
0696: fTargetMethod.getDeclaringType(), hierarchy);
0697: IType[] subtypes = hierarchy.getAllSubtypes(fTargetMethod
0698: .getDeclaringType());
0699: for (int i = 0; i < subtypes.length; i++) {
0700: IMethod method = tester.findOverridingMethodInType(
0701: subtypes[i], fTargetMethod);
0702: if (method != null && method.exists()) {
0703: result.merge(adjustVisibility(method,
0704: neededVisibility, monitor));
0705: if (monitor.isCanceled())
0706: throw new OperationCanceledException();
0707:
0708: if (result.hasError())
0709: return result; // binary
0710: }
0711: }
0712: }
0713:
0714: return result;
0715: }
0716:
0717: private RefactoringStatus updateIntermediaryVisibility(
0718: NoOverrideProgressMonitor monitor)
0719: throws JavaModelException {
0720: return rewriteVisibility(fIntermediaryAdjustments, fRewrites,
0721: monitor);
0722: }
0723:
0724: private RefactoringStatus updateReferences(IProgressMonitor monitor)
0725: throws CoreException {
0726:
0727: RefactoringStatus result = new RefactoringStatus();
0728:
0729: monitor.beginTask("", 90); //$NON-NLS-1$
0730:
0731: if (monitor.isCanceled())
0732: throw new OperationCanceledException();
0733:
0734: IMethod[] ripple = RippleMethodFinder2.getRelatedMethods(
0735: fTargetMethod, false, new NoOverrideProgressMonitor(
0736: monitor, 10), null);
0737:
0738: if (monitor.isCanceled())
0739: throw new OperationCanceledException();
0740:
0741: SearchResultGroup[] references = Checks
0742: .excludeCompilationUnits(getReferences(ripple,
0743: new NoOverrideProgressMonitor(monitor, 10),
0744: result), result);
0745:
0746: if (result.hasFatalError())
0747: return result;
0748:
0749: result.merge(Checks
0750: .checkCompileErrorsInAffectedFiles(references));
0751:
0752: if (monitor.isCanceled())
0753: throw new OperationCanceledException();
0754:
0755: int ticksPerCU = references.length == 0 ? 0
0756: : 70 / references.length;
0757:
0758: for (int i = 0; i < references.length; i++) {
0759: SearchResultGroup group = references[i];
0760: SearchMatch[] searchResults = group.getSearchResults();
0761: CompilationUnitRewrite currentCURewrite = getCachedCURewrite(group
0762: .getCompilationUnit());
0763:
0764: for (int j = 0; j < searchResults.length; j++) {
0765:
0766: SearchMatch match = searchResults[j];
0767: if (match.isInsideDocComment())
0768: continue;
0769:
0770: IMember enclosingMember = (IMember) match.getElement();
0771: ASTNode target = getSelectedNode(group
0772: .getCompilationUnit(), currentCURewrite
0773: .getRoot(), match.getOffset(), match
0774: .getLength());
0775:
0776: if (target instanceof SuperMethodInvocation) {
0777: // Cannot retarget calls to super - add a warning
0778: result
0779: .merge(createWarningAboutCall(
0780: enclosingMember,
0781: target,
0782: RefactoringCoreMessages.IntroduceIndirectionRefactoring_call_warning_super _keyword));
0783: continue;
0784: }
0785:
0786: Assert
0787: .isTrue(target instanceof MethodInvocation,
0788: "Element of call should be a MethodInvocation."); //$NON-NLS-1$
0789:
0790: MethodInvocation invocation = (MethodInvocation) target;
0791: ITypeBinding typeBinding = getExpressionType(invocation);
0792:
0793: if (fIntermediaryFirstParameterType == null) {
0794: // no highest type yet
0795: fIntermediaryFirstParameterType = typeBinding
0796: .getTypeDeclaration();
0797: } else {
0798: // check if current type is higher
0799: result.merge(findCommonParent(typeBinding
0800: .getTypeDeclaration()));
0801: }
0802:
0803: if (result.hasFatalError())
0804: return result;
0805:
0806: // create an edit for this particular call
0807: result.merge(updateMethodInvocation(invocation,
0808: enclosingMember, currentCURewrite));
0809:
0810: // does call see the intermediary method?
0811: // => increase visibility of the type of the intermediary method.
0812: result.merge(adjustVisibility(fIntermediaryClass,
0813: enclosingMember.getDeclaringType(),
0814: new NoOverrideProgressMonitor(monitor, 0)));
0815:
0816: if (monitor.isCanceled())
0817: throw new OperationCanceledException();
0818: }
0819:
0820: if (!isRewriteKept(group.getCompilationUnit()))
0821: createChangeAndDiscardRewrite(group
0822: .getCompilationUnit());
0823:
0824: monitor.worked(ticksPerCU);
0825: }
0826:
0827: monitor.done();
0828: return result;
0829: }
0830:
0831: private RefactoringStatus findCommonParent(ITypeBinding typeBinding)
0832: throws JavaModelException {
0833:
0834: RefactoringStatus status = new RefactoringStatus();
0835:
0836: ITypeBinding highest = fIntermediaryFirstParameterType;
0837: ITypeBinding current = typeBinding;
0838:
0839: if (current.equals(highest)
0840: || Bindings.isSuperType(highest, current))
0841: // current is the same as highest or highest is already a supertype of current in the same hierarchy => no change
0842: return status;
0843:
0844: // find lowest common supertype with the method
0845: // search in bottom-up order
0846: ITypeBinding[] currentAndSupers = getTypeAndAllSuperTypes(current);
0847: ITypeBinding[] highestAndSupers = getTypeAndAllSuperTypes(highest);
0848:
0849: ITypeBinding foundBinding = null;
0850: for (int i1 = 0; i1 < currentAndSupers.length; i1++) {
0851: for (int i2 = 0; i2 < highestAndSupers.length; i2++) {
0852: if (highestAndSupers[i2]
0853: .isEqualTo(currentAndSupers[i1])
0854: && (Bindings.findMethodInHierarchy(
0855: highestAndSupers[i2],
0856: fTargetMethodBinding.getName(),
0857: fTargetMethodBinding
0858: .getParameterTypes()) != null)) {
0859: foundBinding = highestAndSupers[i2];
0860: break;
0861: }
0862: }
0863: if (foundBinding != null)
0864: break;
0865: }
0866:
0867: if (foundBinding != null) {
0868: fIntermediaryFirstParameterType = foundBinding;
0869: } else {
0870: String type1 = fIntermediaryFirstParameterType
0871: .getQualifiedName();
0872: String type2 = current.getQualifiedName();
0873: status
0874: .addFatalError(Messages
0875: .format(
0876: RefactoringCoreMessages.IntroduceIndirectionRefactoring_open_hierarchy_error,
0877: new String[] { type1, type2 }));
0878: }
0879:
0880: return status;
0881: }
0882:
0883: // ******************** CHANGE CREATION ***********************
0884:
0885: public Change createChange(IProgressMonitor pm)
0886: throws CoreException, OperationCanceledException {
0887: final Map arguments = new HashMap();
0888: String project = null;
0889: IJavaProject javaProject = fTargetMethod.getJavaProject();
0890: if (javaProject != null)
0891: project = javaProject.getElementName();
0892: int flags = JavaRefactoringDescriptor.JAR_MIGRATION
0893: | JavaRefactoringDescriptor.JAR_REFACTORING
0894: | RefactoringDescriptor.STRUCTURAL_CHANGE
0895: | RefactoringDescriptor.MULTI_CHANGE;
0896: final IType declaring = fTargetMethod.getDeclaringType();
0897: try {
0898: if (declaring.isLocal() || declaring.isAnonymous())
0899: flags |= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
0900: } catch (JavaModelException exception) {
0901: JavaPlugin.log(exception);
0902: }
0903: final String description = Messages
0904: .format(
0905: RefactoringCoreMessages.IntroduceIndirectionRefactoring_descriptor_description_short,
0906: fTargetMethod.getElementName());
0907: final String header = Messages
0908: .format(
0909: RefactoringCoreMessages.IntroduceIndirectionRefactoring_descriptor_description,
0910: new String[] {
0911: JavaElementLabels
0912: .getTextLabel(
0913: fTargetMethod,
0914: JavaElementLabels.ALL_FULLY_QUALIFIED),
0915: JavaElementLabels
0916: .getTextLabel(
0917: declaring,
0918: JavaElementLabels.ALL_FULLY_QUALIFIED) });
0919: final JDTRefactoringDescriptorComment comment = new JDTRefactoringDescriptorComment(
0920: project, this , header);
0921: comment
0922: .addSetting(Messages
0923: .format(
0924: RefactoringCoreMessages.IntroduceIndirectionRefactoring_original_pattern,
0925: JavaElementLabels
0926: .getTextLabel(
0927: fTargetMethod,
0928: JavaElementLabels.ALL_FULLY_QUALIFIED)));
0929: comment
0930: .addSetting(Messages
0931: .format(
0932: RefactoringCoreMessages.IntroduceIndirectionRefactoring_method_pattern,
0933: fIntermediaryMethodName));
0934: comment
0935: .addSetting(Messages
0936: .format(
0937: RefactoringCoreMessages.IntroduceIndirectionRefactoring_declaring_pattern,
0938: JavaElementLabels
0939: .getTextLabel(
0940: fIntermediaryClass,
0941: JavaElementLabels.ALL_FULLY_QUALIFIED)));
0942: if (fUpdateReferences)
0943: comment
0944: .addSetting(RefactoringCoreMessages.JavaRefactoringDescriptor_update_references);
0945: final IntroduceIndirectionDescriptor descriptor = new IntroduceIndirectionDescriptor(
0946: project, description, comment.asString(), arguments,
0947: flags);
0948: arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT,
0949: JavaRefactoringDescriptorUtil.elementToHandle(project,
0950: fTargetMethod));
0951: arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME,
0952: fIntermediaryMethodName);
0953: arguments.put(
0954: JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + 1,
0955: JavaRefactoringDescriptorUtil.elementToHandle(project,
0956: fIntermediaryClass));
0957: arguments.put(
0958: JavaRefactoringDescriptorUtil.ATTRIBUTE_REFERENCES,
0959: Boolean.valueOf(fUpdateReferences).toString());
0960: return new DynamicValidationRefactoringChange(
0961: descriptor,
0962: RefactoringCoreMessages.IntroduceIndirectionRefactoring_introduce_indirection,
0963: fTextChangeManager.getAllChanges());
0964: }
0965:
0966: // ******************* CREATE INTERMEDIARY **********************
0967:
0968: /**
0969: * Checks whether the target method can be created. Note that this
0970: * can only be done after fDelegateParameterType has been initialized.
0971: * @return resulting status
0972: * @throws JavaModelException
0973: */
0974: private RefactoringStatus checkCanCreateIntermediaryMethod()
0975: throws JavaModelException {
0976: // check if method already exists:
0977: List parameterBindings = new ArrayList();
0978: if (!isStaticTarget())
0979: parameterBindings.add(fIntermediaryFirstParameterType);
0980: parameterBindings.addAll(Arrays.asList(fTargetMethodBinding
0981: .getParameterTypes()));
0982: return Checks.checkMethodInType(fIntermediaryClassBinding,
0983: fIntermediaryMethodName,
0984: (ITypeBinding[]) parameterBindings
0985: .toArray(new ITypeBinding[parameterBindings
0986: .size()]));
0987: }
0988:
0989: private void createIntermediaryMethod() throws CoreException {
0990:
0991: CompilationUnitRewrite imRewrite = getCachedCURewrite(fIntermediaryClass
0992: .getCompilationUnit());
0993: AST ast = imRewrite.getAST();
0994: MethodDeclaration intermediary = ast.newMethodDeclaration();
0995:
0996: // Name
0997: intermediary
0998: .setName(ast.newSimpleName(fIntermediaryMethodName));
0999:
1000: // Flags
1001: List modifiers = intermediary.modifiers();
1002: modifiers.add(imRewrite.getAST().newModifier(
1003: ModifierKeyword.PUBLIC_KEYWORD));
1004: modifiers.add(imRewrite.getAST().newModifier(
1005: ModifierKeyword.STATIC_KEYWORD));
1006:
1007: // Parameters
1008: String targetParameterName = StubUtility.suggestArgumentName(
1009: getProject(),
1010: fIntermediaryFirstParameterType.getName(),
1011: fTargetMethod.getParameterNames());
1012:
1013: if (!isStaticTarget()) {
1014: // Add first param
1015: SingleVariableDeclaration parameter = imRewrite.getAST()
1016: .newSingleVariableDeclaration();
1017: Type t = imRewrite.getImportRewrite()
1018: .addImport(fIntermediaryFirstParameterType,
1019: imRewrite.getAST());
1020: if (fIntermediaryFirstParameterType.isGenericType()) {
1021: ParameterizedType parameterized = imRewrite.getAST()
1022: .newParameterizedType(t);
1023: ITypeBinding[] typeParameters = fIntermediaryFirstParameterType
1024: .getTypeParameters();
1025: for (int i = 0; i < typeParameters.length; i++)
1026: parameterized.typeArguments().add(
1027: imRewrite.getImportRewrite().addImport(
1028: typeParameters[i],
1029: imRewrite.getAST()));
1030: t = parameterized;
1031: }
1032: parameter.setType(t);
1033: parameter.setName(imRewrite.getAST().newSimpleName(
1034: targetParameterName));
1035: intermediary.parameters().add(parameter);
1036: }
1037: // Add other params
1038: copyArguments(intermediary, imRewrite);
1039:
1040: // Add type parameters of declaring class (and enclosing classes)
1041: if (!isStaticTarget()
1042: && fIntermediaryFirstParameterType.isGenericType())
1043: addTypeParameters(imRewrite, intermediary.typeParameters(),
1044: fIntermediaryFirstParameterType);
1045:
1046: // Add type params of method
1047: copyTypeParameters(intermediary, imRewrite);
1048:
1049: // Return type
1050: intermediary.setReturnType2(imRewrite.getImportRewrite()
1051: .addImport(fTargetMethodBinding.getReturnType(), ast));
1052:
1053: // Exceptions
1054: copyExceptions(intermediary, imRewrite);
1055:
1056: // Body
1057: MethodInvocation invocation = imRewrite.getAST()
1058: .newMethodInvocation();
1059: invocation.setName(imRewrite.getAST().newSimpleName(
1060: fTargetMethod.getElementName()));
1061: if (isStaticTarget()) {
1062: Type type = imRewrite.getImportRewrite().addImport(
1063: fTargetMethodBinding.getDeclaringClass(), ast);
1064: invocation.setExpression(ASTNodeFactory.newName(ast,
1065: ASTNodes.asString(type)));
1066: } else {
1067: invocation.setExpression(imRewrite.getAST().newSimpleName(
1068: targetParameterName));
1069: }
1070: copyInvocationParameters(invocation, ast);
1071: Statement call = encapsulateInvocation(intermediary, invocation);
1072:
1073: final Block body = imRewrite.getAST().newBlock();
1074: body.statements().add(call);
1075: intermediary.setBody(body);
1076:
1077: // method comment
1078: ICompilationUnit targetCU = imRewrite.getCu();
1079: if (StubUtility.doAddComments(targetCU.getJavaProject())) {
1080: String comment = CodeGeneration.getMethodComment(targetCU,
1081: getIntermediaryClassName(), intermediary, null,
1082: StubUtility.getLineDelimiterUsed(targetCU));
1083: if (comment != null) {
1084: Javadoc javadoc = (Javadoc) imRewrite.getASTRewrite()
1085: .createStringPlaceholder(comment,
1086: ASTNode.JAVADOC);
1087: intermediary.setJavadoc(javadoc);
1088: }
1089: }
1090:
1091: // Add the completed method to the intermediary type:
1092:
1093: // Intermediary class is non-anonymous
1094: AbstractTypeDeclaration type = (AbstractTypeDeclaration) typeToDeclaration(
1095: fIntermediaryClass, imRewrite.getRoot());
1096: ChildListPropertyDescriptor typeBodyDeclarationsProperty = typeToBodyDeclarationProperty(
1097: fIntermediaryClass, imRewrite.getRoot());
1098:
1099: ListRewrite bodyDeclarationsListRewrite = imRewrite
1100: .getASTRewrite().getListRewrite(type,
1101: typeBodyDeclarationsProperty);
1102: bodyDeclarationsListRewrite
1103: .insertAt(
1104: intermediary,
1105: ASTNodes.getInsertionIndex(intermediary, type
1106: .bodyDeclarations()),
1107: imRewrite
1108: .createGroupDescription(RefactoringCoreMessages.IntroduceIndirectionRefactoring_group_description_create_new_method));
1109: }
1110:
1111: private void addTypeParameters(CompilationUnitRewrite imRewrite,
1112: List newTypeParameters, ITypeBinding parent) {
1113:
1114: ITypeBinding enclosing = parent.getDeclaringClass();
1115: if (enclosing != null)
1116: addTypeParameters(imRewrite, newTypeParameters, enclosing);
1117:
1118: ITypeBinding[] typeParameters = parent.getTypeParameters();
1119: for (int i = 0; i < typeParameters.length; i++) {
1120: TypeParameter ntp = imRewrite.getAST().newTypeParameter();
1121: ntp.setName(imRewrite.getAST().newSimpleName(
1122: typeParameters[i].getName()));
1123: ITypeBinding[] bounds = typeParameters[i].getTypeBounds();
1124: for (int j = 0; j < bounds.length; j++)
1125: if (!"java.lang.Object".equals(bounds[j].getQualifiedName())) //$NON-NLS-1$
1126: ntp.typeBounds().add(
1127: imRewrite.getImportRewrite().addImport(
1128: bounds[j], imRewrite.getAST()));
1129: newTypeParameters.add(ntp);
1130: }
1131: }
1132:
1133: private Statement encapsulateInvocation(
1134: MethodDeclaration declaration, MethodInvocation invocation) {
1135: final Type type = declaration.getReturnType2();
1136:
1137: if (type == null
1138: || (type instanceof PrimitiveType && PrimitiveType.VOID
1139: .equals(((PrimitiveType) type)
1140: .getPrimitiveTypeCode())))
1141: return invocation.getAST().newExpressionStatement(
1142: invocation);
1143:
1144: ReturnStatement statement = invocation.getAST()
1145: .newReturnStatement();
1146: statement.setExpression(invocation);
1147: return statement;
1148: }
1149:
1150: private void copyInvocationParameters(MethodInvocation invocation,
1151: AST ast) throws JavaModelException {
1152: String[] names = fTargetMethod.getParameterNames();
1153: for (int i = 0; i < names.length; i++)
1154: invocation.arguments().add(ast.newSimpleName(names[i]));
1155: }
1156:
1157: private void copyArguments(MethodDeclaration intermediary,
1158: CompilationUnitRewrite rew) throws JavaModelException {
1159: String[] names = fTargetMethod.getParameterNames();
1160: ITypeBinding[] types = fTargetMethodBinding.getParameterTypes();
1161: for (int i = 0; i < names.length; i++) {
1162: ITypeBinding typeBinding = types[i];
1163: SingleVariableDeclaration newElement = rew.getAST()
1164: .newSingleVariableDeclaration();
1165: newElement.setName(rew.getAST().newSimpleName(names[i]));
1166:
1167: if (i == (names.length - 1)
1168: && fTargetMethodBinding.isVarargs()) {
1169: newElement.setVarargs(true);
1170: if (typeBinding.isArray())
1171: typeBinding = typeBinding.getComponentType();
1172: }
1173:
1174: newElement.setType(rew.getImportRewrite().addImport(
1175: typeBinding, rew.getAST()));
1176: intermediary.parameters().add(newElement);
1177: }
1178: }
1179:
1180: private void copyTypeParameters(MethodDeclaration intermediary,
1181: CompilationUnitRewrite rew) {
1182: ITypeBinding[] typeParameters = fTargetMethodBinding
1183: .getTypeParameters();
1184: for (int i = 0; i < typeParameters.length; i++) {
1185: ITypeBinding current = typeParameters[i];
1186:
1187: TypeParameter parameter = rew.getAST().newTypeParameter();
1188: parameter.setName(rew.getAST().newSimpleName(
1189: current.getName()));
1190: ITypeBinding[] bounds = current.getTypeBounds();
1191: for (int j = 0; j < bounds.length; j++)
1192: if (!"java.lang.Object".equals(bounds[j].getQualifiedName())) //$NON-NLS-1$
1193: parameter.typeBounds().add(
1194: rew.getImportRewrite().addImport(bounds[j],
1195: rew.getAST()));
1196:
1197: intermediary.typeParameters().add(parameter);
1198: }
1199: }
1200:
1201: private void copyExceptions(MethodDeclaration intermediary,
1202: CompilationUnitRewrite imRewrite) {
1203: ITypeBinding[] exceptionTypes = fTargetMethodBinding
1204: .getExceptionTypes();
1205: for (int i = 0; i < exceptionTypes.length; i++) {
1206: final String qualifiedName = imRewrite.getImportRewrite()
1207: .addImport(exceptionTypes[i]);
1208: intermediary.thrownExceptions().add(
1209: ASTNodeFactory.newName(imRewrite.getAST(),
1210: qualifiedName));
1211: }
1212: }
1213:
1214: // ******************* UPDATE CALLS **********************
1215:
1216: private RefactoringStatus updateMethodInvocation(
1217: MethodInvocation originalInvocation, IMember enclosing,
1218: CompilationUnitRewrite unitRewriter)
1219: throws JavaModelException {
1220:
1221: RefactoringStatus status = new RefactoringStatus();
1222:
1223: // If the method invocation utilizes type arguments, skip this
1224: // call as the new target method may have additional parameters
1225: if (originalInvocation.typeArguments().size() > 0)
1226: return createWarningAboutCall(
1227: enclosing,
1228: originalInvocation,
1229: RefactoringCoreMessages.IntroduceIndirectionRefactoring_call_warning_type_arguments);
1230:
1231: MethodInvocation newInvocation = unitRewriter.getAST()
1232: .newMethodInvocation();
1233: List newInvocationArgs = newInvocation.arguments();
1234: List originalInvocationArgs = originalInvocation.arguments();
1235:
1236: // static call => always use a qualifier
1237: String qualifier = unitRewriter.getImportRewrite().addImport(
1238: fIntermediaryClassBinding);
1239: newInvocation.setExpression(ASTNodeFactory.newName(unitRewriter
1240: .getAST(), qualifier));
1241: newInvocation.setName(unitRewriter.getAST().newSimpleName(
1242: getIntermediaryMethodName()));
1243:
1244: final Expression expression = originalInvocation
1245: .getExpression();
1246:
1247: if (!isStaticTarget()) {
1248: // Add the expression as the first parameter
1249: if (expression == null) {
1250: // There is no expression for this call. Use a (possibly qualified) "this" expression.
1251: ThisExpression expr = unitRewriter.getAST()
1252: .newThisExpression();
1253: RefactoringStatus qualifierStatus = qualifyThisExpression(
1254: expr, originalInvocation, enclosing,
1255: unitRewriter);
1256: status.merge(qualifierStatus);
1257: if (qualifierStatus.hasEntries())
1258: // warning means don't include this invocation
1259: return status;
1260: newInvocationArgs.add(expr);
1261: } else {
1262: ASTNode expressionAsParam = unitRewriter
1263: .getASTRewrite().createMoveTarget(expression);
1264: newInvocationArgs.add(expressionAsParam);
1265: }
1266: } else {
1267: if (expression != null) {
1268: // Check if expression is the class name. If not, there may
1269: // be side effects (e.g. inside methods) -> don't update
1270: if (!(expression instanceof Name)
1271: || ASTNodes.getTypeBinding((Name) expression) == null)
1272: return createWarningAboutCall(
1273: enclosing,
1274: originalInvocation,
1275: RefactoringCoreMessages.IntroduceIndirectionRefactoring_call_warning_static_expression_access);
1276: }
1277: }
1278:
1279: for (int i = 0; i < originalInvocationArgs.size(); i++) {
1280: Expression originalInvocationArg = (Expression) originalInvocationArgs
1281: .get(i);
1282: ASTNode movedArg = unitRewriter.getASTRewrite()
1283: .createMoveTarget(originalInvocationArg);
1284: newInvocationArgs.add(movedArg);
1285: }
1286:
1287: unitRewriter
1288: .getASTRewrite()
1289: .replace(
1290: originalInvocation,
1291: newInvocation,
1292: unitRewriter
1293: .createGroupDescription(RefactoringCoreMessages.IntroduceIndirectionRefactoring_group_description_replace_call));
1294:
1295: return status;
1296: }
1297:
1298: /**
1299: * Attempts to qualify a "this" expression for a method invocation with an appropriate qualifier.
1300: * The invoked method is analyzed according to the following specs:
1301: *
1302: * 'this' must be qualified iff method is declared in an enclosing type or a supertype of an enclosing type
1303: *
1304: * 1) The method is declared somewhere outside of the cu of the invocation
1305: * 1a) inside a supertype of the current type
1306: * 1b) inside a supertype of an enclosing type
1307: * 2) The method is declared inside of the cu of the invocation
1308: * 2a) inside the type of the invocation
1309: * 2b) outside the type of the invocation
1310: *
1311: * In case of 1a) and 2b), qualify with the enclosing type.
1312: * @param expr
1313: * @param originalInvocation
1314: * @param enclosing
1315: * @param unitRewriter
1316: * @return resulting status
1317: *
1318: */
1319: private RefactoringStatus qualifyThisExpression(
1320: ThisExpression expr, MethodInvocation originalInvocation,
1321: IMember enclosing, CompilationUnitRewrite unitRewriter) {
1322:
1323: RefactoringStatus status = new RefactoringStatus();
1324:
1325: IMethodBinding methodBinding = originalInvocation
1326: .resolveMethodBinding();
1327: MethodDeclaration methodDeclaration = (MethodDeclaration) ASTNodes
1328: .findDeclaration(methodBinding, originalInvocation
1329: .getRoot());
1330:
1331: ITypeBinding currentTypeBinding = null;
1332: if (methodDeclaration != null) {
1333: // Case 1) : Declaring class is inside this cu => use its name if it's declared in an enclosing type
1334: if (ASTNodes.isParent(originalInvocation, methodDeclaration
1335: .getParent()))
1336: currentTypeBinding = methodBinding.getDeclaringClass();
1337: else
1338: currentTypeBinding = ASTNodes
1339: .getEnclosingType(originalInvocation);
1340: } else {
1341: // Case 2) : Declaring class is outside of this cu => find subclass in this cu
1342: ASTNode currentTypeDeclaration = getEnclosingTypeDeclaration(originalInvocation);
1343: currentTypeBinding = ASTNodes
1344: .getEnclosingType(currentTypeDeclaration);
1345: while (currentTypeDeclaration != null
1346: && (Bindings.findMethodInHierarchy(
1347: currentTypeBinding,
1348: methodBinding.getName(), methodBinding
1349: .getParameterTypes()) == null)) {
1350: currentTypeDeclaration = getEnclosingTypeDeclaration(currentTypeDeclaration
1351: .getParent());
1352: currentTypeBinding = ASTNodes
1353: .getEnclosingType(currentTypeDeclaration);
1354: }
1355: }
1356:
1357: if (currentTypeBinding == null) {
1358: status
1359: .merge(createWarningAboutCall(
1360: enclosing,
1361: originalInvocation,
1362: RefactoringCoreMessages.IntroduceIndirectionRefactoring_call_warning_declaring_type_not_found));
1363: return status;
1364: }
1365:
1366: ITypeBinding typeOfCall = ASTNodes
1367: .getEnclosingType(originalInvocation);
1368: if (!typeOfCall.equals(currentTypeBinding)) {
1369: if (currentTypeBinding.isAnonymous()) {
1370: // Cannot qualify, see bug 115277
1371: status
1372: .merge(createWarningAboutCall(
1373: enclosing,
1374: originalInvocation,
1375: RefactoringCoreMessages.IntroduceIndirectionRefactoring_call_warning_anonymous_cannot_qualify));
1376: } else {
1377: expr.setQualifier(unitRewriter.getAST().newSimpleName(
1378: currentTypeBinding.getName()));
1379: }
1380: } else {
1381: // do not qualify, only use "this.".
1382: }
1383:
1384: return status;
1385: }
1386:
1387: // ********* SMALL HELPERS ********************
1388:
1389: /*
1390: * Helper method for finding an IMethod inside a binding hierarchy
1391: */
1392: private IMethodBinding findMethodBindingInHierarchy(
1393: ITypeBinding currentTypeBinding, IMethod methodDeclaration) {
1394: IMethodBinding[] bindings = currentTypeBinding
1395: .getDeclaredMethods();
1396: for (int i = 0; i < bindings.length; i++)
1397: if (methodDeclaration.equals(bindings[i].getJavaElement()))
1398: return bindings[i];
1399:
1400: ITypeBinding super Class = currentTypeBinding.getSuperclass();
1401: if (super Class != null) {
1402: IMethodBinding b = findMethodBindingInHierarchy(super Class,
1403: methodDeclaration);
1404: if (b != null)
1405: return b;
1406: }
1407: ITypeBinding[] interfaces = currentTypeBinding.getInterfaces();
1408: for (int i = 0; i < interfaces.length; i++) {
1409: IMethodBinding b = findMethodBindingInHierarchy(
1410: interfaces[i], methodDeclaration);
1411: if (b != null)
1412: return b;
1413: }
1414: return null;
1415: }
1416:
1417: /*
1418: * Helper method for retrieving a *bottom-up* list of super type bindings
1419: */
1420: private ITypeBinding[] getTypeAndAllSuperTypes(ITypeBinding type) {
1421: List result = new ArrayList();
1422: collectSuperTypes(type, result);
1423: return (ITypeBinding[]) result.toArray(new ITypeBinding[result
1424: .size()]);
1425: }
1426:
1427: private void collectSuperTypes(ITypeBinding curr, List list) {
1428: if (list.add(curr.getTypeDeclaration())) {
1429: ITypeBinding[] interfaces = curr.getInterfaces();
1430: for (int i = 0; i < interfaces.length; i++) {
1431: collectSuperTypes(interfaces[i], list);
1432: }
1433: ITypeBinding super Class = curr.getSuperclass();
1434: if (super Class != null) {
1435: collectSuperTypes(super Class, list);
1436: }
1437: }
1438: }
1439:
1440: private CompilationUnitRewrite getCachedCURewrite(
1441: ICompilationUnit unit) {
1442: CompilationUnitRewrite rewrite = (CompilationUnitRewrite) fRewrites
1443: .get(unit);
1444: if (rewrite == null) {
1445: rewrite = new CompilationUnitRewrite(unit);
1446: fRewrites.put(unit, rewrite);
1447: }
1448: return rewrite;
1449: }
1450:
1451: private boolean isRewriteKept(ICompilationUnit compilationUnit) {
1452: return fIntermediaryClass.getCompilationUnit().equals(
1453: compilationUnit);
1454: }
1455:
1456: private void createChangeAndDiscardRewrite(
1457: ICompilationUnit compilationUnit) throws CoreException {
1458: CompilationUnitRewrite rewrite = (CompilationUnitRewrite) fRewrites
1459: .get(compilationUnit);
1460: if (rewrite != null) {
1461: fTextChangeManager.manage(compilationUnit, rewrite
1462: .createChange());
1463: fRewrites.remove(compilationUnit);
1464: }
1465: }
1466:
1467: private SearchResultGroup[] getReferences(IMethod[] methods,
1468: IProgressMonitor pm, RefactoringStatus status)
1469: throws CoreException {
1470: SearchPattern pattern = RefactoringSearchEngine
1471: .createOrPattern(methods,
1472: IJavaSearchConstants.REFERENCES);
1473: IJavaSearchScope scope = RefactoringScopeFactory.create(
1474: fIntermediaryClass, false);
1475: return RefactoringSearchEngine.search(pattern, scope, pm,
1476: status);
1477: }
1478:
1479: private ITypeBinding typeToBinding(IType type, CompilationUnit root)
1480: throws JavaModelException {
1481: ASTNode typeNode = typeToDeclaration(type, root);
1482: if (type.isAnonymous()) {
1483: return ((AnonymousClassDeclaration) typeNode)
1484: .resolveBinding();
1485: } else {
1486: return ((AbstractTypeDeclaration) typeNode)
1487: .resolveBinding();
1488: }
1489: }
1490:
1491: private ASTNode typeToDeclaration(IType type, CompilationUnit root)
1492: throws JavaModelException {
1493: Name intermediateName = (Name) NodeFinder.perform(root, type
1494: .getNameRange());
1495: if (type.isAnonymous()) {
1496: return ASTNodes.getParent(intermediateName,
1497: AnonymousClassDeclaration.class);
1498: } else {
1499: return ASTNodes.getParent(intermediateName,
1500: AbstractTypeDeclaration.class);
1501: }
1502: }
1503:
1504: private ASTNode getEnclosingTypeDeclaration(ASTNode node) {
1505: while (node != null) {
1506: if (node instanceof AbstractTypeDeclaration) {
1507: return node;
1508: } else if (node instanceof AnonymousClassDeclaration) {
1509: return node;
1510: }
1511: node = node.getParent();
1512: }
1513: return null;
1514: }
1515:
1516: private ChildListPropertyDescriptor typeToBodyDeclarationProperty(
1517: IType type, CompilationUnit root) throws JavaModelException {
1518: ASTNode typeDeclaration = typeToDeclaration(type, root);
1519: if (typeDeclaration instanceof AbstractTypeDeclaration)
1520: return ((AbstractTypeDeclaration) typeDeclaration)
1521: .getBodyDeclarationsProperty();
1522: else if (typeDeclaration instanceof AnonymousClassDeclaration)
1523: return AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY;
1524:
1525: Assert.isTrue(false);
1526: return null;
1527: }
1528:
1529: private RefactoringStatus createWarningAboutCall(IMember enclosing,
1530: ASTNode concreteNode, String message) {
1531: String name = JavaElementLabels.getElementLabel(enclosing,
1532: JavaElementLabels.ALL_DEFAULT);
1533: String container = JavaElementLabels.getElementLabel(enclosing
1534: .getDeclaringType(),
1535: JavaElementLabels.ALL_FULLY_QUALIFIED);
1536: return RefactoringStatus.createWarningStatus(Messages.format(
1537: message, new String[] { name, container }),
1538: JavaStatusContext.create(
1539: enclosing.getCompilationUnit(), concreteNode));
1540: }
1541:
1542: private ITypeBinding getExpressionType(MethodInvocation invocation) {
1543: Expression expression = invocation.getExpression();
1544: ITypeBinding typeBinding = null;
1545: if (expression == null) {
1546: typeBinding = invocation.resolveMethodBinding()
1547: .getDeclaringClass();
1548: } else {
1549: typeBinding = expression.resolveTypeBinding();
1550: }
1551:
1552: Assert.isNotNull(typeBinding,
1553: "Type binding of target expression may not be null"); //$NON-NLS-1$
1554: return typeBinding;
1555: }
1556:
1557: private IFile[] getAllFilesToModify() {
1558: List cus = new ArrayList();
1559: cus.addAll(Arrays.asList(fTextChangeManager
1560: .getAllCompilationUnits()));
1561: return ResourceUtil.getFiles((ICompilationUnit[]) cus
1562: .toArray(new ICompilationUnit[cus.size()]));
1563: }
1564:
1565: private boolean isStaticTarget() throws JavaModelException {
1566: return Flags.isStatic(fTargetMethod.getFlags());
1567: }
1568:
1569: private IMember getEnclosingInitialSelectionMember()
1570: throws JavaModelException {
1571: return (IMember) fSelectionCompilationUnit
1572: .getElementAt(fSelectionStart);
1573: }
1574:
1575: private static ASTNode getSelectedNode(ICompilationUnit unit,
1576: CompilationUnit root, int offset, int length) {
1577: ASTNode node = null;
1578: try {
1579: if (unit != null)
1580: node = checkNode(NodeFinder.perform(root, offset,
1581: length, unit));
1582: else
1583: node = checkNode(NodeFinder.perform(root, offset,
1584: length));
1585: } catch (JavaModelException e) {
1586: // Do nothing
1587: }
1588: if (node != null)
1589: return node;
1590: return checkNode(NodeFinder.perform(root, offset, length));
1591: }
1592:
1593: private static ASTNode checkNode(ASTNode node) {
1594: if (node == null)
1595: return null;
1596: if (node.getNodeType() == ASTNode.SIMPLE_NAME) {
1597: node = node.getParent();
1598: } else if (node.getNodeType() == ASTNode.EXPRESSION_STATEMENT) {
1599: node = ((ExpressionStatement) node).getExpression();
1600: }
1601: switch (node.getNodeType()) {
1602: case ASTNode.METHOD_INVOCATION:
1603: case ASTNode.METHOD_DECLARATION:
1604: case ASTNode.SUPER_METHOD_INVOCATION:
1605: return node;
1606: }
1607: return null;
1608: }
1609:
1610: // ***************** VISIBILITY ********************
1611:
1612: private ModifierKeyword getNeededVisibility(IMember whoToAdjust,
1613: IMember fromWhereToLook) throws JavaModelException {
1614: return fAdjustor.getVisibilityThreshold(fromWhereToLook,
1615: whoToAdjust, new NullProgressMonitor());
1616: }
1617:
1618: private RefactoringStatus adjustVisibility(IMember whoToAdjust,
1619: IMember fromWhereToLook, IProgressMonitor monitor)
1620: throws CoreException {
1621: return adjustVisibility(whoToAdjust, getNeededVisibility(
1622: whoToAdjust, fromWhereToLook), true, monitor);
1623: }
1624:
1625: private RefactoringStatus adjustVisibility(IMember whoToAdjust,
1626: ModifierKeyword neededVisibility, IProgressMonitor monitor)
1627: throws CoreException {
1628: return adjustVisibility(whoToAdjust, neededVisibility, false,
1629: monitor);
1630: }
1631:
1632: private RefactoringStatus adjustVisibility(IMember whoToAdjust,
1633: ModifierKeyword neededVisibility,
1634: boolean alsoIncreaseEnclosing, IProgressMonitor monitor)
1635: throws CoreException {
1636:
1637: Map adjustments;
1638: if (isRewriteKept(whoToAdjust.getCompilationUnit()))
1639: adjustments = fIntermediaryAdjustments;
1640: else
1641: adjustments = new HashMap();
1642:
1643: int existingAdjustments = adjustments.size();
1644: addAdjustment(whoToAdjust, neededVisibility, adjustments);
1645:
1646: if (alsoIncreaseEnclosing)
1647: while (whoToAdjust.getDeclaringType() != null) {
1648: whoToAdjust = whoToAdjust.getDeclaringType();
1649: addAdjustment(whoToAdjust, neededVisibility,
1650: adjustments);
1651: }
1652:
1653: boolean hasNewAdjustments = (adjustments.size() - existingAdjustments) > 0;
1654: if (hasNewAdjustments
1655: && ((whoToAdjust.isReadOnly() || whoToAdjust.isBinary())))
1656: return RefactoringStatus
1657: .createErrorStatus(
1658: Messages
1659: .format(
1660: RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_update_binary_target_visibility,
1661: new String[] { JavaElementLabels
1662: .getElementLabel(
1663: whoToAdjust,
1664: JavaElementLabels.ALL_DEFAULT) }),
1665: JavaStatusContext.create(whoToAdjust));
1666:
1667: RefactoringStatus status = new RefactoringStatus();
1668:
1669: // Don't create a rewrite if it is not necessary
1670: if (!hasNewAdjustments)
1671: return status;
1672:
1673: try {
1674: monitor
1675: .beginTask(
1676: RefactoringCoreMessages.MemberVisibilityAdjustor_adjusting,
1677: 2);
1678: Map rewrites;
1679: if (!isRewriteKept(whoToAdjust.getCompilationUnit())) {
1680: CompilationUnitRewrite rewrite = new CompilationUnitRewrite(
1681: whoToAdjust.getCompilationUnit());
1682: rewrite.setResolveBindings(false);
1683: rewrites = new HashMap();
1684: rewrites.put(whoToAdjust.getCompilationUnit(), rewrite);
1685: status
1686: .merge(rewriteVisibility(
1687: adjustments,
1688: rewrites,
1689: new SubProgressMonitor(
1690: monitor,
1691: 1,
1692: SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)));
1693: rewrite
1694: .attachChange(
1695: (CompilationUnitChange) fTextChangeManager
1696: .get(whoToAdjust
1697: .getCompilationUnit()),
1698: true,
1699: new SubProgressMonitor(
1700: monitor,
1701: 1,
1702: SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
1703: }
1704: } finally {
1705: monitor.done();
1706: }
1707: return status;
1708: }
1709:
1710: private RefactoringStatus rewriteVisibility(Map adjustments,
1711: Map rewrites, IProgressMonitor monitor)
1712: throws JavaModelException {
1713: RefactoringStatus status = new RefactoringStatus();
1714: fAdjustor.setRewrites(rewrites);
1715: fAdjustor.setAdjustments(adjustments);
1716: fAdjustor.setStatus(status);
1717: fAdjustor.rewriteVisibility(monitor);
1718: return status;
1719: }
1720:
1721: private void addAdjustment(IMember whoToAdjust,
1722: ModifierKeyword neededVisibility, Map adjustments)
1723: throws JavaModelException {
1724: ModifierKeyword currentVisibility = ModifierKeyword
1725: .fromFlagValue(JdtFlags.getVisibilityCode(whoToAdjust));
1726: if (MemberVisibilityAdjustor.hasLowerVisibility(
1727: currentVisibility, neededVisibility)
1728: && MemberVisibilityAdjustor.needsVisibilityAdjustments(
1729: whoToAdjust, neededVisibility, adjustments))
1730: adjustments
1731: .put(
1732: whoToAdjust,
1733: new MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment(
1734: whoToAdjust,
1735: neededVisibility,
1736: RefactoringStatus
1737: .createWarningStatus(
1738: Messages
1739: .format(
1740: MemberVisibilityAdjustor
1741: .getMessage(whoToAdjust),
1742: new String[] {
1743: MemberVisibilityAdjustor
1744: .getLabel(whoToAdjust),
1745: MemberVisibilityAdjustor
1746: .getLabel(neededVisibility) }),
1747: JavaStatusContext
1748: .create(whoToAdjust))));
1749: }
1750:
1751: public RefactoringStatus initialize(
1752: final RefactoringArguments arguments) {
1753: if (arguments instanceof JavaRefactoringArguments) {
1754: final JavaRefactoringArguments extended = (JavaRefactoringArguments) arguments;
1755: String handle = extended
1756: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
1757: if (handle != null) {
1758: final IJavaElement element = JavaRefactoringDescriptorUtil
1759: .handleToElement(extended.getProject(), handle,
1760: false);
1761: if (element == null
1762: || !element.exists()
1763: || element.getElementType() != IJavaElement.METHOD)
1764: return createInputFatalStatus(element,
1765: IJavaRefactorings.INTRODUCE_INDIRECTION);
1766: else
1767: fTargetMethod = (IMethod) element;
1768: } else
1769: return RefactoringStatus
1770: .createFatalErrorStatus(Messages
1771: .format(
1772: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1773: JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
1774: handle = extended
1775: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + 1);
1776: if (handle != null) {
1777: final IJavaElement element = JavaRefactoringDescriptorUtil
1778: .handleToElement(extended.getProject(), handle,
1779: false);
1780: if (element == null
1781: || !element.exists()
1782: || element.getElementType() != IJavaElement.TYPE)
1783: return createInputFatalStatus(element,
1784: IJavaRefactorings.INTRODUCE_INDIRECTION);
1785: else
1786: fIntermediaryClass = (IType) element;
1787: } else
1788: return RefactoringStatus
1789: .createFatalErrorStatus(Messages
1790: .format(
1791: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1792: JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + 1));
1793: final String references = extended
1794: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_REFERENCES);
1795: if (references != null) {
1796: fUpdateReferences = Boolean.valueOf(references)
1797: .booleanValue();
1798: } else
1799: return RefactoringStatus
1800: .createFatalErrorStatus(Messages
1801: .format(
1802: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1803: JavaRefactoringDescriptorUtil.ATTRIBUTE_REFERENCES));
1804: final String name = extended
1805: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);
1806: if (name != null && !"".equals(name)) //$NON-NLS-1$
1807: return setIntermediaryMethodName(name);
1808: else
1809: return RefactoringStatus
1810: .createFatalErrorStatus(Messages
1811: .format(
1812: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1813: JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME));
1814: } else
1815: return RefactoringStatus
1816: .createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
1817: }
1818: }
|