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.structure;
0011:
0012: import java.util.ArrayList;
0013: import java.util.Arrays;
0014: import java.util.Collection;
0015: import java.util.HashMap;
0016: import java.util.HashSet;
0017: import java.util.Iterator;
0018: import java.util.List;
0019: import java.util.Map;
0020: import java.util.Set;
0021: import java.util.StringTokenizer;
0022:
0023: import org.eclipse.text.edits.MultiTextEdit;
0024: import org.eclipse.text.edits.TextEditGroup;
0025:
0026: import org.eclipse.core.runtime.Assert;
0027: import org.eclipse.core.runtime.CoreException;
0028: import org.eclipse.core.runtime.IProgressMonitor;
0029: import org.eclipse.core.runtime.NullProgressMonitor;
0030: import org.eclipse.core.runtime.OperationCanceledException;
0031: import org.eclipse.core.runtime.SubProgressMonitor;
0032:
0033: import org.eclipse.ltk.core.refactoring.Change;
0034: import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
0035: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
0036: import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
0037:
0038: import org.eclipse.jdt.core.ICompilationUnit;
0039: import org.eclipse.jdt.core.IField;
0040: import org.eclipse.jdt.core.IJavaElement;
0041: import org.eclipse.jdt.core.IJavaProject;
0042: import org.eclipse.jdt.core.IMethod;
0043: import org.eclipse.jdt.core.JavaModelException;
0044: import org.eclipse.jdt.core.dom.AST;
0045: import org.eclipse.jdt.core.dom.ASTNode;
0046: import org.eclipse.jdt.core.dom.CompilationUnit;
0047: import org.eclipse.jdt.core.dom.Expression;
0048: import org.eclipse.jdt.core.dom.FieldDeclaration;
0049: import org.eclipse.jdt.core.dom.IBinding;
0050: import org.eclipse.jdt.core.dom.IMethodBinding;
0051: import org.eclipse.jdt.core.dom.ITypeBinding;
0052: import org.eclipse.jdt.core.dom.IVariableBinding;
0053: import org.eclipse.jdt.core.dom.MethodDeclaration;
0054: import org.eclipse.jdt.core.dom.ParameterizedType;
0055: import org.eclipse.jdt.core.dom.QualifiedName;
0056: import org.eclipse.jdt.core.dom.SimpleName;
0057: import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
0058: import org.eclipse.jdt.core.dom.Type;
0059: import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
0060: import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
0061: import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
0062: import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
0063: import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
0064: import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer;
0065: import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
0066: import org.eclipse.jdt.core.refactoring.descriptors.GeneralizeTypeDescriptor;
0067: import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
0068: import org.eclipse.jdt.core.search.IJavaSearchConstants;
0069: import org.eclipse.jdt.core.search.IJavaSearchScope;
0070: import org.eclipse.jdt.core.search.SearchPattern;
0071:
0072: import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
0073: import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
0074: import org.eclipse.jdt.internal.corext.dom.Bindings;
0075: import org.eclipse.jdt.internal.corext.dom.NodeFinder;
0076: import org.eclipse.jdt.internal.corext.refactoring.Checks;
0077: import org.eclipse.jdt.internal.corext.refactoring.CollectingSearchRequestor;
0078: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
0079: import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
0080: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
0081: import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
0082: import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
0083: import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
0084: import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
0085: import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange;
0086: import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
0087: import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring;
0088: import org.eclipse.jdt.internal.corext.refactoring.rename.MethodChecks;
0089: import org.eclipse.jdt.internal.corext.refactoring.rename.RippleMethodFinder2;
0090: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ASTCreator;
0091: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompositeOrTypeConstraint;
0092: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintCollector;
0093: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintOperator;
0094: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintVariable;
0095: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintVariableFactory;
0096: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ExpressionVariable;
0097: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.FullConstraintCreator;
0098: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ITypeConstraint;
0099: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ParameterTypeVariable;
0100: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ReturnTypeVariable;
0101: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.SimpleTypeConstraint;
0102: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.TypeConstraintFactory;
0103: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.TypeVariable;
0104: import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
0105: import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
0106: import org.eclipse.jdt.internal.corext.util.Messages;
0107: import org.eclipse.jdt.internal.corext.util.SearchUtils;
0108:
0109: import org.eclipse.jdt.ui.JavaElementLabels;
0110:
0111: import org.eclipse.jdt.internal.ui.JavaPlugin;
0112: import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
0113:
0114: /**
0115: * @author tip
0116: */
0117: public class ChangeTypeRefactoring extends ScriptableRefactoring {
0118:
0119: private static final String ATTRIBUTE_TYPE = "type"; //$NON-NLS-1$
0120:
0121: private final Map/*<ICompilationUnit, Collection<ITypeConstraint>>*/fConstraintCache;
0122: /**
0123: * Offset of the selected text area.
0124: */
0125: private int fSelectionStart;
0126:
0127: /**
0128: * Length of the selected text area.
0129: */
0130: private int fSelectionLength;
0131:
0132: /**
0133: * Offset of the effective selection
0134: */
0135: private int fEffectiveSelectionStart;
0136:
0137: /**
0138: * Length of the effective selection
0139: */
0140: private int fEffectiveSelectionLength;
0141:
0142: /**
0143: * ICompilationUnit containing the selection.
0144: */
0145: private ICompilationUnit fCu;
0146:
0147: /**
0148: * If the selection corresponds to a method parameter/return type, this field stores
0149: * a reference to its IMethodBinding, otherwise this field remains null. Used during
0150: * search for references in other CUs, and for determining the ConstraintVariable
0151: * that corresponds to the selection
0152: */
0153: private IMethodBinding fMethodBinding;
0154:
0155: /**
0156: * If the selection corresponds to a method parameter, this field stores the parameter
0157: * index (0 = first parameter for static methods, 0 = this for nonstatic methods). The
0158: * value -1 is stored in the field if the selection corresponds to a method return type.
0159: */
0160: private int fParamIndex;
0161:
0162: /**
0163: * The name of the selected parameter, or <code>null</code>.
0164: */
0165: private String fParamName;
0166:
0167: /**
0168: * If the selection corresponds to a field, this field stores a reference to its IVariableBinding,
0169: * otherwise this field remains null. Used during search for references in other CUs.
0170: */
0171: private IVariableBinding fFieldBinding;
0172:
0173: /**
0174: * The compilation units that contain constraint variables related to the selection
0175: */
0176: private ICompilationUnit[] fAffectedUnits;
0177:
0178: /**
0179: * The constraint variables that are of interest to this refactoring. This includes
0180: * the constraint var. corresponding to the text selection, and possibly additional
0181: * elements due to method overriding, method calls, etc.
0182: */
0183: private Collection/*<ConstraintVariable>*/fRelevantVars;
0184:
0185: /**
0186: * The set of types (other than the original type) that can be given to
0187: * the selected ASTNode.
0188: */
0189: private final Collection/*<IType>*/fValidTypes;
0190:
0191: /**
0192: * The type constraints that are related to the selected ASTNode.
0193: */
0194: private Collection/*<ITypeConstraint>*/fRelevantConstraints;
0195:
0196: /**
0197: * All type constraints in affected compilation units.
0198: */
0199: private Collection/*<ITypeConstraint>*/fAllConstraints;
0200:
0201: /**
0202: * The name of the new type of the selected declaration.
0203: */
0204: private String fSelectedTypeName;
0205:
0206: /**
0207: * The new type of the selected declaration.
0208: */
0209: private ITypeBinding fSelectedType;
0210:
0211: /**
0212: * Organizes SearchResults by CompilationUnit
0213: */
0214: private Map/*<ICompilationUnit,SearchResultGroup>*/fCuToSearchResultGroup = new HashMap();
0215:
0216: /**
0217: * ITypeBinding for java.lang.Object
0218: */
0219: private ITypeBinding fObject;
0220:
0221: public ITypeBinding getObject() {
0222: return fObject;
0223: }
0224:
0225: /**
0226: * Control debugging output.
0227: */
0228: private static final boolean DEBUG = false;
0229:
0230: private ConstraintVariable fCv;
0231: private IBinding fSelectionBinding;
0232: private ITypeBinding fSelectionTypeBinding;
0233: private ConstraintCollector fCollector;
0234:
0235: public ChangeTypeRefactoring(ICompilationUnit cu,
0236: int selectionStart, int selectionLength) {
0237: this (cu, selectionStart, selectionLength, null);
0238: }
0239:
0240: /**
0241: * Constructor for ChangeTypeRefactoring (invoked from tests only)
0242: */
0243: public ChangeTypeRefactoring(ICompilationUnit cu,
0244: int selectionStart, int selectionLength, String selectedType) {
0245: Assert.isTrue(selectionStart >= 0);
0246: Assert.isTrue(selectionLength >= 0);
0247:
0248: fSelectionStart = selectionStart;
0249: fSelectionLength = selectionLength;
0250:
0251: fEffectiveSelectionStart = selectionStart;
0252: fEffectiveSelectionLength = selectionLength;
0253:
0254: fCu = cu;
0255:
0256: if (selectedType != null)
0257: fSelectedTypeName = selectedType;
0258:
0259: fConstraintCache = new HashMap();
0260: fValidTypes = new HashSet();
0261: }
0262:
0263: // ------------------------------------------------------------------------------------------------- //
0264:
0265: /*
0266: * @see org.eclipse.jdt.internal.corext.refactoring.base.Refactoring#checkActivation(org.eclipse.core.runtime.IProgressMonitor)
0267: */
0268: public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
0269: throws CoreException {
0270: if (fCu == null || !fCu.isStructureKnown())
0271: return RefactoringStatus
0272: .createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_invalidSelection);
0273: return checkSelection(new SubProgressMonitor(pm, 1));
0274: }
0275:
0276: private void setSelectionRanges(Expression exp) {
0277: fEffectiveSelectionStart = exp.getStartPosition();
0278: fEffectiveSelectionLength = exp.getLength();
0279: fSelectionBinding = ExpressionVariable.resolveBinding(exp);
0280: setOriginalType(exp.resolveTypeBinding());
0281: }
0282:
0283: /**
0284: * Check if the right type of AST Node is selected. Create the TypeHierarchy needed to
0285: * bring up the wizard.
0286: */
0287: private RefactoringStatus checkSelection(IProgressMonitor pm)
0288: throws JavaModelException {
0289: try {
0290: pm.beginTask("", 5); //$NON-NLS-1$
0291:
0292: ASTNode node = getTargetNode(fCu, fSelectionStart,
0293: fSelectionLength);
0294: if (DEBUG) {
0295: System.out.println("selection: [" //$NON-NLS-1$
0296: + fSelectionStart
0297: + "," //$NON-NLS-1$
0298: + (fSelectionStart + fSelectionLength)
0299: + "] in " //$NON-NLS-1$
0300: + fCu.getElementName());
0301: System.out
0302: .println("node= " + node + ", type= " + node.getClass().getName()); //$NON-NLS-1$ //$NON-NLS-2$
0303: }
0304:
0305: TypeConstraintFactory typeConstraintFactory = new TypeConstraintFactory() {
0306: public boolean filter(ConstraintVariable v1,
0307: ConstraintVariable v2, ConstraintOperator o) {
0308: if (o.isStrictSubtypeOperator()) //TODO: explain why these can be excluded
0309: return true;
0310: //Don't create constraint if fSelectionTypeBinding is not involved:
0311: if (v1.getBinding() != null
0312: && v2.getBinding() != null
0313: && !Bindings.equals(v1.getBinding(),
0314: fSelectionTypeBinding)
0315: && !Bindings.equals(v2.getBinding(),
0316: fSelectionTypeBinding)) {
0317: if (PRINT_STATS)
0318: fNrFiltered++;
0319: return true;
0320: }
0321: return super .filter(v1, v2, o);
0322: }
0323: };
0324: fCollector = new ConstraintCollector(
0325: new FullConstraintCreator(
0326: new ConstraintVariableFactory(),
0327: typeConstraintFactory));
0328: String selectionValid = determineSelection(node);
0329: if (selectionValid != null) {
0330: if (DEBUG) {
0331: System.out
0332: .println("invalid selection: " + selectionValid); //$NON-NLS-1$
0333: }
0334: return RefactoringStatus
0335: .createFatalErrorStatus(selectionValid);
0336: }
0337:
0338: if (fMethodBinding != null) {
0339: IMethod selectedMethod = (IMethod) fMethodBinding
0340: .getJavaElement();
0341: if (selectedMethod == null) {
0342: return RefactoringStatus
0343: .createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_insideLocalTypesNotSupported);
0344: }
0345: }
0346:
0347: pm.worked(1);
0348:
0349: RefactoringStatus result = new RefactoringStatus();
0350:
0351: if (DEBUG) {
0352: System.out
0353: .println("fSelectionTypeBinding: " + fSelectionTypeBinding.getName()); //$NON-NLS-1$
0354: }
0355:
0356: // produce error message if array or primitive type is selected
0357: if (fSelectionTypeBinding.isArray()) {
0358: return RefactoringStatus
0359: .createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_arraysNotSupported);
0360: }
0361: if (fSelectionTypeBinding.isPrimitive()) {
0362: return RefactoringStatus
0363: .createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_primitivesNotSupported);
0364: }
0365: if (checkOverriddenBinaryMethods())
0366: return RefactoringStatus
0367: .createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_notSupportedOnBinary);
0368:
0369: if (fSelectionTypeBinding.isLocal()) {
0370: return RefactoringStatus
0371: .createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_localTypesNotSupported);
0372: }
0373:
0374: if (fFieldBinding != null
0375: && fFieldBinding.getDeclaringClass().isLocal()) {
0376: return RefactoringStatus
0377: .createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_insideLocalTypesNotSupported);
0378: }
0379:
0380: if (fSelectionTypeBinding.isTypeVariable()) {
0381: return RefactoringStatus
0382: .createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_typeParametersNotSupported);
0383: }
0384:
0385: if (fSelectionTypeBinding.isEnum()) {
0386: return RefactoringStatus
0387: .createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_enumsNotSupported);
0388: }
0389:
0390: pm.worked(1);
0391:
0392: if (fSelectedType != null) { // if invoked from unit test, compute valid types here
0393: computeValidTypes(new NullProgressMonitor());
0394: }
0395: return result;
0396: } finally {
0397: pm.done();
0398: }
0399: }
0400:
0401: private boolean checkOverriddenBinaryMethods()
0402: throws JavaModelException {
0403: if (fMethodBinding != null) {
0404: Set declaringSupertypes = getDeclaringSuperTypes(fMethodBinding);
0405: for (Iterator iter = declaringSupertypes.iterator(); iter
0406: .hasNext();) {
0407: ITypeBinding super Type = (ITypeBinding) iter.next();
0408: IMethodBinding overriddenMethod = findMethod(
0409: fMethodBinding, super Type);
0410: Assert.isNotNull(overriddenMethod);//because we asked for declaring types
0411: IMethod iMethod = (IMethod) overriddenMethod
0412: .getJavaElement();
0413: if (iMethod.isBinary()) {
0414: return true;
0415: }
0416: }
0417: }
0418: return false;
0419: }
0420:
0421: // copied from FullConstraintCreator
0422: private static IMethodBinding findMethod(
0423: IMethodBinding methodBinding, ITypeBinding type) {
0424: if (methodBinding.getDeclaringClass().equals(type))
0425: return methodBinding;
0426: return Bindings.findOverriddenMethodInType(type, methodBinding);
0427: }
0428:
0429: // copied from FullConstraintCreator
0430: private static Set getDeclaringSuperTypes(
0431: IMethodBinding methodBinding) {
0432: ITypeBinding[] allSuperTypes = Bindings
0433: .getAllSuperTypes(methodBinding.getDeclaringClass());
0434: Set result = new HashSet();
0435: for (int i = 0; i < allSuperTypes.length; i++) {
0436: ITypeBinding type = allSuperTypes[i];
0437: if (findMethod(methodBinding, type) != null)
0438: result.add(type);
0439: }
0440: return result;
0441: }
0442:
0443: /**
0444: * Do the actual work of computing allowable types. Invoked by the wizard when
0445: * "compute" button is pressed
0446: */
0447: public Collection/*<IType>*/computeValidTypes(IProgressMonitor pm) {
0448:
0449: pm
0450: .beginTask(
0451: RefactoringCoreMessages.ChangeTypeRefactoring_checking_preconditions,
0452: 100);
0453:
0454: try {
0455: fCv = findConstraintVariableForSelectedNode(new SubProgressMonitor(
0456: pm, 3));
0457: if (DEBUG)
0458: System.out.println("selected CV: " + fCv + //$NON-NLS-1$
0459: " (" + fCv.getClass().getName() + //$NON-NLS-1$
0460: ")"); //$NON-NLS-1$
0461:
0462: if (pm.isCanceled())
0463: throw new OperationCanceledException();
0464: fRelevantVars = findRelevantConstraintVars(fCv,
0465: new SubProgressMonitor(pm, 50));
0466:
0467: if (DEBUG)
0468: printCollection("relevant vars:", fRelevantVars); //$NON-NLS-1$
0469:
0470: if (pm.isCanceled())
0471: throw new OperationCanceledException();
0472: fRelevantConstraints = findRelevantConstraints(
0473: fRelevantVars, new SubProgressMonitor(pm, 30));
0474:
0475: if (pm.isCanceled())
0476: throw new OperationCanceledException();
0477: fValidTypes.addAll(computeValidTypes(fSelectionTypeBinding,
0478: fRelevantVars, fRelevantConstraints,
0479: new SubProgressMonitor(pm, 20)));
0480:
0481: if (DEBUG)
0482: printCollection("valid types:", getValidTypeNames()); //$NON-NLS-1$
0483: } catch (CoreException e) {
0484: JavaPlugin
0485: .logErrorMessage("Error occurred during computation of valid types: " + e.toString()); //$NON-NLS-1$
0486: fValidTypes.clear(); // error occurred during computation of valid types
0487: }
0488:
0489: pm.done();
0490:
0491: return fValidTypes;
0492: }
0493:
0494: /*
0495: * @see org.eclipse.jdt.internal.corext.refactoring.base.Refactoring#checkInput(org.eclipse.core.runtime.IProgressMonitor)
0496: */
0497: public RefactoringStatus checkFinalConditions(IProgressMonitor pm)
0498: throws CoreException {
0499: pm
0500: .beginTask(
0501: RefactoringCoreMessages.ChangeTypeRefactoring_checking_preconditions,
0502: 1);
0503:
0504: RefactoringStatus result = Checks.validateModifiesFiles(
0505: ResourceUtil.getFiles(fAffectedUnits),
0506: getValidationContext());
0507:
0508: pm.done();
0509: return result;
0510: }
0511:
0512: // TODO: do sanity check somewhere if the refactoring changes any files.
0513: /*
0514: * @see org.eclipse.jdt.internal.corext.refactoring.base.IRefactoring#createChange(org.eclipse.core.runtime.IProgressMonitor)
0515: */
0516: public Change createChange(IProgressMonitor pm)
0517: throws CoreException {
0518: pm
0519: .beginTask(
0520: RefactoringCoreMessages.ChangeTypeMessages_CreateChangesForChangeType,
0521: 1);
0522: try {
0523: Map/* <ICompilationUnit,Set<ConstraintVariable>> */relevantVarsByUnit = new HashMap/* <ICompilationUnit,HashSet<ConstraintVariable>> */();
0524: groupChangesByCompilationUnit(relevantVarsByUnit);
0525: final Map arguments = new HashMap();
0526: String project = null;
0527: IJavaProject javaProject = fCu.getJavaProject();
0528: if (javaProject != null)
0529: project = javaProject.getElementName();
0530: final String description = RefactoringCoreMessages.ChangeTypeRefactoring_descriptor_description_short;
0531: final String header = Messages
0532: .format(
0533: RefactoringCoreMessages.ChangeTypeRefactoring_descriptor_description,
0534: new String[] {
0535: BindingLabelProvider
0536: .getBindingLabel(
0537: fSelectionBinding,
0538: JavaElementLabels.ALL_FULLY_QUALIFIED),
0539: BindingLabelProvider
0540: .getBindingLabel(
0541: fSelectedType,
0542: JavaElementLabels.ALL_FULLY_QUALIFIED) });
0543: final JDTRefactoringDescriptorComment comment = new JDTRefactoringDescriptorComment(
0544: project, this , header);
0545: comment
0546: .addSetting(Messages
0547: .format(
0548: RefactoringCoreMessages.ChangeTypeRefactoring_original_element_pattern,
0549: BindingLabelProvider
0550: .getBindingLabel(
0551: fSelectionBinding,
0552: JavaElementLabels.ALL_FULLY_QUALIFIED)));
0553: comment
0554: .addSetting(Messages
0555: .format(
0556: RefactoringCoreMessages.ChangeTypeRefactoring_original_type_pattern,
0557: BindingLabelProvider
0558: .getBindingLabel(
0559: getOriginalType(),
0560: JavaElementLabels.ALL_FULLY_QUALIFIED)));
0561: comment
0562: .addSetting(Messages
0563: .format(
0564: RefactoringCoreMessages.ChangeTypeRefactoring_refactored_type_pattern,
0565: BindingLabelProvider
0566: .getBindingLabel(
0567: fSelectedType,
0568: JavaElementLabels.ALL_FULLY_QUALIFIED)));
0569: final GeneralizeTypeDescriptor descriptor = new GeneralizeTypeDescriptor(
0570: project,
0571: description,
0572: comment.asString(),
0573: arguments,
0574: (RefactoringDescriptor.STRUCTURAL_CHANGE
0575: | JavaRefactoringDescriptor.JAR_REFACTORING | JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT));
0576: arguments.put(
0577: JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT,
0578: JavaRefactoringDescriptorUtil.elementToHandle(
0579: project, fCu));
0580: arguments
0581: .put(
0582: JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION,
0583: new Integer(fSelectionStart).toString()
0584: + " " + new Integer(fSelectionLength).toString()); //$NON-NLS-1$
0585: arguments.put(ATTRIBUTE_TYPE, fSelectedType
0586: .getQualifiedName());
0587: final DynamicValidationRefactoringChange result = new DynamicValidationRefactoringChange(
0588: descriptor,
0589: RefactoringCoreMessages.ChangeTypeRefactoring_allChanges);
0590: for (Iterator/* <ICompilationUnit> */it = relevantVarsByUnit
0591: .keySet().iterator(); it.hasNext();) {
0592: ICompilationUnit icu = (ICompilationUnit) it.next();
0593: Set/* <ConstraintVariable> */cVars = (Set) relevantVarsByUnit
0594: .get(icu);
0595: CompilationUnitChange cuChange = new CompilationUnitChange(
0596: getName(), icu);
0597: addAllChangesFor(icu, cVars, cuChange);
0598: result.add(cuChange);
0599: pm.worked(1);
0600: if (pm.isCanceled())
0601: throw new OperationCanceledException();
0602: }
0603: return result;
0604: } finally {
0605: pm.done();
0606: }
0607: }
0608:
0609: /**
0610: * Apply all changes related to a single ICompilationUnit
0611: */
0612: private void addAllChangesFor(ICompilationUnit icu, Set vars,
0613: CompilationUnitChange unitChange) throws CoreException {
0614: CompilationUnit unit = new RefactoringASTParser(AST.JLS3)
0615: .parse(icu, false);
0616: ASTRewrite unitRewriter = ASTRewrite.create(unit.getAST());
0617: MultiTextEdit root = new MultiTextEdit();
0618: unitChange.setEdit(root); // Adam sez don't need this, but then unitChange.addGroupDescription() fails an assertion!
0619:
0620: String typeName = updateImports(unit, root);
0621: updateCu(unit, vars, unitChange, unitRewriter, typeName);
0622: root.addChild(unitRewriter.rewriteAST());
0623: }
0624:
0625: private class SourceRangeComputer extends TargetSourceRangeComputer {
0626: public SourceRange computeSourceRange(ASTNode node) {
0627: return new SourceRange(node.getStartPosition(), node
0628: .getLength());
0629: }
0630: }
0631:
0632: private void updateCu(CompilationUnit unit, Set vars,
0633: CompilationUnitChange unitChange, ASTRewrite unitRewriter,
0634: String typeName) throws JavaModelException {
0635:
0636: // use custom SourceRangeComputer to avoid losing comments
0637: unitRewriter
0638: .setTargetSourceRangeComputer(new SourceRangeComputer());
0639:
0640: for (Iterator it = vars.iterator(); it.hasNext();) {
0641: ConstraintVariable cv = (ConstraintVariable) it.next();
0642: ASTNode decl = findDeclaration(unit, cv);
0643: if ((decl instanceof SimpleName || decl instanceof QualifiedName)
0644: && cv instanceof ExpressionVariable) {
0645: ASTNode gp = decl.getParent().getParent();
0646: updateType(unit, getType(gp), unitChange, unitRewriter,
0647: typeName); // local variable or parameter
0648: } else if (decl instanceof MethodDeclaration
0649: || decl instanceof FieldDeclaration) {
0650: updateType(unit, getType(decl), unitChange,
0651: unitRewriter, typeName); // method return or field type
0652: } else if (decl instanceof ParameterizedType) {
0653: updateType(unit, getType(decl), unitChange,
0654: unitRewriter, typeName);
0655: }
0656: }
0657: }
0658:
0659: private void updateType(CompilationUnit cu, Type oldType,
0660: CompilationUnitChange unitChange, ASTRewrite unitRewriter,
0661: String typeName) {
0662:
0663: String oldName = fSelectionTypeBinding.getName();
0664: String description = Messages
0665: .format(
0666: RefactoringCoreMessages.ChangeTypeRefactoring_typeChange,
0667: new String[] { oldName, typeName });
0668: TextEditGroup gd = new TextEditGroup(description);
0669: AST ast = cu.getAST();
0670:
0671: ASTNode nodeToReplace = oldType;
0672: if (fSelectionTypeBinding.isParameterizedType()
0673: && !fSelectionTypeBinding.isRawType()) {
0674: if (oldType.isSimpleType()) {
0675: nodeToReplace = oldType.getParent();
0676: }
0677: }
0678:
0679: //TODO handle types other than simple & parameterized (e.g., arrays)
0680: Assert.isTrue(fSelectedType.isClass()
0681: || fSelectedType.isInterface());
0682:
0683: Type newType = null;
0684: if (!fSelectedType.isParameterizedType()) {
0685: newType = ast.newSimpleType(ASTNodeFactory.newName(ast,
0686: typeName));
0687: } else {
0688: newType = createParameterizedType(ast, fSelectedType);
0689: }
0690:
0691: unitRewriter.replace(nodeToReplace, newType, gd);
0692: unitChange.addTextEditGroup(gd);
0693: }
0694:
0695: /**
0696: * Creates the appropriate ParameterizedType node. Recursion is needed to
0697: * handle the nested case (e.g., Vector<Vector<String>>).
0698: */
0699: private Type createParameterizedType(AST ast,
0700: ITypeBinding typeBinding) {
0701: if (typeBinding.isParameterizedType()
0702: && !typeBinding.isRawType()) {
0703: Type baseType = ast.newSimpleType(ASTNodeFactory.newName(
0704: ast, typeBinding.getErasure().getName()));
0705: ParameterizedType newType = ast
0706: .newParameterizedType(baseType);
0707: for (int i = 0; i < typeBinding.getTypeArguments().length; i++) {
0708: ITypeBinding typeArg = typeBinding.getTypeArguments()[i];
0709: Type argType = createParameterizedType(ast, typeArg); // recursive call
0710: newType.typeArguments().add(argType);
0711: }
0712: return newType;
0713: } else {
0714: if (!typeBinding.isTypeVariable()) {
0715: return ast.newSimpleType(ASTNodeFactory.newName(ast,
0716: typeBinding.getErasure().getName()));
0717: } else {
0718: return ast.newSimpleType(ast.newSimpleName(typeBinding
0719: .getName()));
0720: }
0721: }
0722: }
0723:
0724: private void groupChangesByCompilationUnit(Map relevantVarsByUnit)
0725: throws JavaModelException {
0726: for (Iterator it = fRelevantVars.iterator(); it.hasNext();) {
0727: ConstraintVariable cv = (ConstraintVariable) it.next();
0728: if (!(cv instanceof ExpressionVariable)
0729: && !(cv instanceof ReturnTypeVariable)) {
0730: continue;
0731: }
0732: ICompilationUnit icu = null;
0733: if (cv instanceof ExpressionVariable) {
0734: ExpressionVariable ev = (ExpressionVariable) cv;
0735: icu = ev.getCompilationUnitRange().getCompilationUnit();
0736: } else if (cv instanceof ReturnTypeVariable) {
0737: ReturnTypeVariable rtv = (ReturnTypeVariable) cv;
0738: IMethodBinding mb = rtv.getMethodBinding();
0739: icu = ((IMethod) mb.getJavaElement())
0740: .getCompilationUnit();
0741: }
0742: if (!relevantVarsByUnit.containsKey(icu)) {
0743: relevantVarsByUnit.put(icu,
0744: new HashSet/*<ConstraintVariable>*/());
0745: }
0746: ((Set) relevantVarsByUnit.get(icu)).add(cv);
0747: }
0748: }
0749:
0750: private ASTNode findDeclaration(CompilationUnit root,
0751: ConstraintVariable cv) throws JavaModelException {
0752:
0753: if (fFieldBinding != null) {
0754: IField f = (IField) fFieldBinding.getJavaElement();
0755: return ASTNodeSearchUtil.getFieldDeclarationNode(f, root);
0756: }
0757:
0758: if (cv instanceof ExpressionVariable) {
0759: for (Iterator iter = fAllConstraints.iterator(); iter
0760: .hasNext();) {
0761: ITypeConstraint constraint = (ITypeConstraint) iter
0762: .next();
0763: if (constraint.isSimpleTypeConstraint()) {
0764: SimpleTypeConstraint stc = (SimpleTypeConstraint) constraint;
0765: if (stc.isDefinesConstraint()
0766: && stc.getLeft().equals(cv)) {
0767: ConstraintVariable right = stc.getRight();
0768: if (right instanceof TypeVariable) {
0769: TypeVariable typeVariable = (TypeVariable) right;
0770: return NodeFinder.perform(root,
0771: typeVariable
0772: .getCompilationUnitRange()
0773: .getSourceRange());
0774: }
0775: }
0776: }
0777: }
0778: } else if (cv instanceof ReturnTypeVariable) {
0779: ReturnTypeVariable rtv = (ReturnTypeVariable) cv;
0780: IMethodBinding mb = rtv.getMethodBinding();
0781: IMethod im = (IMethod) mb.getJavaElement();
0782: return ASTNodeSearchUtil.getMethodDeclarationNode(im, root);
0783: }
0784: return null;
0785: }
0786:
0787: private static Type getType(ASTNode node) {
0788: switch (node.getNodeType()) {
0789: case ASTNode.SINGLE_VARIABLE_DECLARATION:
0790: return ((SingleVariableDeclaration) node).getType();
0791: case ASTNode.FIELD_DECLARATION:
0792: return ((FieldDeclaration) node).getType();
0793: case ASTNode.VARIABLE_DECLARATION_STATEMENT:
0794: return ((VariableDeclarationStatement) node).getType();
0795: case ASTNode.METHOD_DECLARATION:
0796: return ((MethodDeclaration) node).getReturnType2();
0797: case ASTNode.PARAMETERIZED_TYPE:
0798: return ((ParameterizedType) node).getType();
0799: default:
0800: Assert.isTrue(false);
0801: return null;
0802: }
0803: }
0804:
0805: /*
0806: * @see org.eclipse.jdt.internal.corext.refactoring.base.IRefactoring#getName()
0807: */
0808: public String getName() {
0809: return RefactoringCoreMessages.ChangeTypeRefactoring_name;
0810: }
0811:
0812: // ------------------------------------------------------------------------------------------------- //
0813: // Method for examining if a suitable kind of ASTNode was selected. Information about this node and
0814: // its parents in the AST are stored in fields fBinding, theMethod, and theField
0815:
0816: /**
0817: * Determines what kind of ASTNode has been selected. A non-null String containing an error message
0818: * is returned if the ChangeTypeRefactoring refactoring cannot be applied to the selected ASTNode.
0819: * A return value of null indicates a valid selection.
0820: */
0821: private String determineSelection(ASTNode node) {
0822: if (node == null) {
0823: return RefactoringCoreMessages.ChangeTypeRefactoring_invalidSelection;
0824: } else {
0825:
0826: if (DEBUG)
0827: System.out
0828: .println("node nodeType= " + node.getClass().getName()); //$NON-NLS-1$
0829: if (DEBUG)
0830: System.out
0831: .println("parent nodeType= " + node.getParent().getClass().getName()); //$NON-NLS-1$
0832: if (DEBUG)
0833: System.out
0834: .println("GrandParent nodeType= " + node.getParent().getParent().getClass().getName()); //$NON-NLS-1$
0835:
0836: ASTNode parent = node.getParent();
0837: ASTNode grandParent = parent.getParent();
0838: if (grandParent == null)
0839: return nodeTypeNotSupported();
0840:
0841: // adjustment needed if part of a parameterized type is selected
0842: if (grandParent.getNodeType() == ASTNode.PARAMETERIZED_TYPE) {
0843: node = grandParent;
0844: }
0845:
0846: // adjustment needed if part of a qualified name is selected
0847: ASTNode current = null;
0848: if (node.getNodeType() == ASTNode.QUALIFIED_NAME) {
0849: current = node;
0850: while (current.getNodeType() == ASTNode.QUALIFIED_NAME) {
0851: current = current.getParent();
0852: }
0853: if (current.getNodeType() != ASTNode.SIMPLE_TYPE) {
0854: return nodeTypeNotSupported();
0855: }
0856: node = current.getParent();
0857: } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) {
0858: current = parent;
0859: while (current.getNodeType() == ASTNode.QUALIFIED_NAME) {
0860: current = current.getParent();
0861: }
0862: if (current.getNodeType() != ASTNode.SIMPLE_TYPE) {
0863: return nodeTypeNotSupported();
0864: }
0865: node = current.getParent();
0866: }
0867:
0868: fObject = node.getAST().resolveWellKnownType(
0869: "java.lang.Object"); //$NON-NLS-1$
0870: switch (node.getNodeType()) {
0871: case ASTNode.SIMPLE_NAME:
0872: return simpleNameSelected((SimpleName) node);
0873: case ASTNode.VARIABLE_DECLARATION_STATEMENT:
0874: return variableDeclarationStatementSelected((VariableDeclarationStatement) node);
0875: case ASTNode.FIELD_DECLARATION:
0876: return fieldDeclarationSelected((FieldDeclaration) node);
0877: case ASTNode.SINGLE_VARIABLE_DECLARATION:
0878: return singleVariableDeclarationSelected((SingleVariableDeclaration) node);
0879: case ASTNode.PARAMETERIZED_TYPE:
0880: return parameterizedTypeSelected((ParameterizedType) node);
0881: default:
0882: return nodeTypeNotSupported();
0883: }
0884: }
0885: }
0886:
0887: /**
0888: * The selection corresponds to an ASTNode on which "ChangeTypeRefactoring" is not defined.
0889: */
0890: private static String nodeTypeNotSupported() {
0891: return RefactoringCoreMessages.ChangeTypeRefactoring_notSupportedOnNodeType;
0892: }
0893:
0894: /**
0895: * The selection corresponds to a SingleVariableDeclaration
0896: */
0897: private String singleVariableDeclarationSelected(
0898: SingleVariableDeclaration svd) {
0899: SimpleName name = svd.getName();
0900: setSelectionRanges(name);
0901: return simpleNameSelected(name);
0902: }
0903:
0904: /**
0905: * The selection corresponds to a ParameterizedType (return type of method)
0906: */
0907: private String parameterizedTypeSelected(ParameterizedType pt) {
0908: ASTNode parent = pt.getParent();
0909: if (parent.getNodeType() == ASTNode.METHOD_DECLARATION) {
0910: fMethodBinding = ((MethodDeclaration) parent)
0911: .resolveBinding();
0912: fParamIndex = -1;
0913: fEffectiveSelectionStart = pt.getStartPosition();
0914: fEffectiveSelectionLength = pt.getLength();
0915: setOriginalType(pt.resolveBinding());
0916: } else if (parent.getNodeType() == ASTNode.SINGLE_VARIABLE_DECLARATION) {
0917: return singleVariableDeclarationSelected((SingleVariableDeclaration) parent);
0918: } else if (parent.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT) {
0919: return variableDeclarationStatementSelected((VariableDeclarationStatement) parent);
0920: } else if (parent.getNodeType() == ASTNode.FIELD_DECLARATION) {
0921: return fieldDeclarationSelected((FieldDeclaration) parent);
0922: } else {
0923: return nodeTypeNotSupported();
0924: }
0925: return null;
0926: }
0927:
0928: /**
0929: * The selection corresponds to a VariableDeclarationStatement
0930: */
0931: private String variableDeclarationStatementSelected(
0932: VariableDeclarationStatement vds) {
0933: if (vds.fragments().size() != 1) {
0934: return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
0935: } else {
0936: VariableDeclarationFragment elem = (VariableDeclarationFragment) vds
0937: .fragments().iterator().next();
0938: SimpleName name = elem.getName();
0939: setSelectionRanges(name);
0940: return simpleNameSelected(name);
0941: }
0942: }
0943:
0944: /**
0945: * The selection corresponds to a FieldDeclaration
0946: */
0947: private String fieldDeclarationSelected(
0948: FieldDeclaration fieldDeclaration) {
0949: if (fieldDeclaration.fragments().size() != 1) {
0950: return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
0951: } else {
0952: VariableDeclarationFragment elem = (VariableDeclarationFragment) fieldDeclaration
0953: .fragments().iterator().next();
0954: fFieldBinding = elem.resolveBinding();
0955: SimpleName name = elem.getName();
0956: setSelectionRanges(name);
0957: return simpleNameSelected(name);
0958: }
0959: }
0960:
0961: /**
0962: * The selection corresponds to a SimpleName
0963: */
0964: private String simpleNameSelected(SimpleName simpleName) {
0965: ASTNode parent = simpleName.getParent();
0966: ASTNode grandParent = parent.getParent();
0967:
0968: if (parent.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT) {
0969: VariableDeclarationStatement vds = (VariableDeclarationStatement) parent;
0970: if (vds.fragments().size() > 1) {
0971: return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
0972: }
0973: } else if (parent.getNodeType() == ASTNode.VARIABLE_DECLARATION_FRAGMENT) {
0974: if (grandParent.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT) {
0975: VariableDeclarationStatement vds = (VariableDeclarationStatement) grandParent;
0976: if (vds.fragments().size() > 1) {
0977: return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
0978: }
0979: setSelectionRanges(simpleName);
0980: } else if (grandParent.getNodeType() == ASTNode.VARIABLE_DECLARATION_EXPRESSION) {
0981: VariableDeclarationExpression vde = (VariableDeclarationExpression) grandParent;
0982: if (vde.fragments().size() > 1) {
0983: return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
0984: }
0985: setSelectionRanges(simpleName);
0986: } else if (grandParent.getNodeType() == ASTNode.FIELD_DECLARATION) {
0987: FieldDeclaration fd = (FieldDeclaration) grandParent;
0988: if (fd.fragments().size() > 1) {
0989: return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
0990: }
0991: VariableDeclarationFragment fragment = (VariableDeclarationFragment) parent;
0992: fFieldBinding = fragment.resolveBinding();
0993: setSelectionRanges(fragment.getName());
0994: } else {
0995: return RefactoringCoreMessages.ChangeTypeRefactoring_notSupportedOnNodeType;
0996: }
0997: } else if (parent.getNodeType() == ASTNode.SINGLE_VARIABLE_DECLARATION) {
0998: SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration) parent;
0999: if ((grandParent.getNodeType() == ASTNode.METHOD_DECLARATION)) {
1000: fMethodBinding = ((MethodDeclaration) grandParent)
1001: .resolveBinding();
1002: setOriginalType(simpleName.resolveTypeBinding());
1003: fParamIndex = ((MethodDeclaration) grandParent)
1004: .parameters().indexOf(parent);
1005: fParamName = singleVariableDeclaration.getName()
1006: .getIdentifier();
1007: } else {
1008: setSelectionRanges(singleVariableDeclaration.getName());
1009: }
1010: } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE
1011: && (grandParent.getNodeType() == ASTNode.SINGLE_VARIABLE_DECLARATION)) {
1012: ASTNode greatGrandParent = grandParent.getParent();
1013: SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration) grandParent;
1014: if (singleVariableDeclaration.getExtraDimensions() > 0) {
1015: return RefactoringCoreMessages.ChangeTypeRefactoring_arraysNotSupported;
1016: }
1017: if (greatGrandParent != null
1018: && greatGrandParent.getNodeType() == ASTNode.METHOD_DECLARATION) {
1019: fMethodBinding = ((MethodDeclaration) greatGrandParent)
1020: .resolveBinding();
1021: fParamIndex = ((MethodDeclaration) greatGrandParent)
1022: .parameters().indexOf(grandParent);
1023: fParamName = singleVariableDeclaration.getName()
1024: .getIdentifier();
1025: setSelectionRanges(simpleName);
1026: } else {
1027: setSelectionRanges(singleVariableDeclaration.getName());
1028: }
1029: } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE
1030: && grandParent.getNodeType() == ASTNode.METHOD_DECLARATION) {
1031: fMethodBinding = ((MethodDeclaration) grandParent)
1032: .resolveBinding();
1033: setOriginalType(fMethodBinding.getReturnType());
1034: fParamIndex = -1;
1035: } else if (parent.getNodeType() == ASTNode.METHOD_DECLARATION
1036: && grandParent.getNodeType() == ASTNode.TYPE_DECLARATION) {
1037: MethodDeclaration methodDeclaration = (MethodDeclaration) parent;
1038: if (methodDeclaration.getName().equals(simpleName)
1039: || methodDeclaration.thrownExceptions().contains(
1040: simpleName)) {
1041: return RefactoringCoreMessages.ChangeTypeRefactoring_notSupportedOnNodeType;
1042: }
1043: fMethodBinding = ((MethodDeclaration) parent)
1044: .resolveBinding();
1045: fParamIndex = -1;
1046: } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE
1047: && (grandParent.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT)) {
1048: return variableDeclarationStatementSelected((VariableDeclarationStatement) grandParent);
1049: } else if (parent.getNodeType() == ASTNode.CAST_EXPRESSION) {
1050: ASTNode decl = findDeclaration(parent.getRoot(),
1051: fSelectionStart, fSelectionLength + 1);
1052: VariableDeclarationFragment fragment = (VariableDeclarationFragment) decl;
1053: SimpleName name = fragment.getName();
1054: setSelectionRanges(name);
1055: } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE
1056: && grandParent.getNodeType() == ASTNode.FIELD_DECLARATION) {
1057: return fieldDeclarationSelected((FieldDeclaration) grandParent);
1058: } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE
1059: && grandParent.getNodeType() == ASTNode.ARRAY_TYPE) {
1060: return RefactoringCoreMessages.ChangeTypeRefactoring_arraysNotSupported;
1061: } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME) {
1062: setSelectionRanges(simpleName);
1063: } else {
1064: return RefactoringCoreMessages.ChangeTypeRefactoring_notSupportedOnNodeType;
1065: }
1066: return null;
1067: }
1068:
1069: // ------------------------------------------------------------------------------------------------- //
1070: // Methods for examining & solving type constraints. This includes:
1071: // (1) locating the ConstraintVariable corresponding to the selected ASTNode
1072: // (2) finding all ConstraintVariables "related" to (1) via overriding, method calls, field access
1073: // (3) find all ITypeConstraints of interest that mention ConstraintVariables in (2)
1074: // (4) determining all ITypes for which the ITypeConstraints in (3) are satisfied
1075:
1076: /**
1077: * Find a ConstraintVariable that corresponds to the selected ASTNode.
1078: */
1079: private ConstraintVariable findConstraintVariableForSelectedNode(
1080: IProgressMonitor pm) {
1081: pm
1082: .beginTask(
1083: RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage,
1084: 100);
1085: ICompilationUnit[] cus = { fCu }; // only search in CU containing selection
1086:
1087: if (DEBUG) {
1088: System.out
1089: .println("Effective selection: " + fEffectiveSelectionStart + "/" + fEffectiveSelectionLength); //$NON-NLS-1$ //$NON-NLS-2$
1090: }
1091:
1092: Collection/*<ITypeConstraint>*/allConstraints = getConstraints(
1093: cus, new SubProgressMonitor(pm, 50));
1094:
1095: IProgressMonitor subMonitor = new SubProgressMonitor(pm, 50);
1096: subMonitor
1097: .beginTask(
1098: RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage,
1099: allConstraints.size());
1100: for (Iterator it = allConstraints.iterator(); it.hasNext();) {
1101: subMonitor.worked(1);
1102: ITypeConstraint tc = (ITypeConstraint) it.next();
1103: if (!(tc instanceof SimpleTypeConstraint))
1104: continue;
1105: SimpleTypeConstraint stc = (SimpleTypeConstraint) tc;
1106: if (matchesSelection(stc.getLeft()))
1107: return stc.getLeft();
1108: if (matchesSelection(stc.getRight()))
1109: return stc.getRight();
1110: }
1111: subMonitor.done();
1112: pm.done();
1113: Assert
1114: .isTrue(
1115: false,
1116: RefactoringCoreMessages.ChangeTypeRefactoring_noMatchingConstraintVariable);
1117: return null;
1118: }
1119:
1120: /**
1121: * Determine if a given ConstraintVariable matches the selected ASTNode.
1122: */
1123: private boolean matchesSelection(ConstraintVariable cv) {
1124: if (cv instanceof ExpressionVariable) {
1125: ExpressionVariable ev = (ExpressionVariable) cv;
1126: return (fSelectionBinding != null && Bindings.equals(
1127: fSelectionBinding, ev.getExpressionBinding()));
1128: } else if (cv instanceof ParameterTypeVariable) {
1129: ParameterTypeVariable ptv = (ParameterTypeVariable) cv;
1130: if (fMethodBinding != null
1131: && Bindings.equals(ptv.getMethodBinding(),
1132: fMethodBinding)
1133: && ptv.getParameterIndex() == fParamIndex) {
1134: return true;
1135: }
1136: } else if (cv instanceof ReturnTypeVariable) {
1137: ReturnTypeVariable rtv = (ReturnTypeVariable) cv;
1138: if (fMethodBinding != null
1139: && Bindings.equals(rtv.getMethodBinding(),
1140: fMethodBinding) && fParamIndex == -1) {
1141: return true;
1142: }
1143: }
1144: return false;
1145: }
1146:
1147: /**
1148: * Determine the set of constraint variables related to the selected
1149: * expression. In addition to the expression itself, this consists of
1150: * any expression that is defines-equal to it, and any expression equal
1151: * to it.
1152: */
1153: private Collection/*<ConstraintVariable>*/findRelevantConstraintVars(
1154: ConstraintVariable cv, IProgressMonitor pm)
1155: throws CoreException {
1156: pm
1157: .beginTask(
1158: RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage,
1159: 150);
1160: Collection/*<ConstraintVariable>*/result = new HashSet();
1161: result.add(cv);
1162: ICompilationUnit[] cus = collectAffectedUnits(new SubProgressMonitor(
1163: pm, 50));
1164: Collection/*<ITypeConstraint>*/allConstraints = getConstraints(
1165: cus, new SubProgressMonitor(pm, 50));
1166:
1167: List/*<ConstraintVariable>*/workList = new ArrayList(result);
1168: while (!workList.isEmpty()) {
1169:
1170: pm.worked(10);
1171:
1172: ConstraintVariable first = (ConstraintVariable) workList
1173: .remove(0);
1174: for (Iterator iter = allConstraints.iterator(); iter
1175: .hasNext();) {
1176: pm.worked(1);
1177: ITypeConstraint typeConstraint = (ITypeConstraint) iter
1178: .next();
1179: if (!typeConstraint.isSimpleTypeConstraint())
1180: continue;
1181: SimpleTypeConstraint stc = (SimpleTypeConstraint) typeConstraint;
1182: if (!stc.isDefinesConstraint()
1183: && !stc.isEqualsConstraint())
1184: continue;
1185: ConstraintVariable match = match(first, stc.getLeft(),
1186: stc.getRight());
1187: if (match instanceof ExpressionVariable
1188: || match instanceof ParameterTypeVariable
1189: || match instanceof ReturnTypeVariable) {
1190: if (!result.contains(match)) {
1191: workList.add(match);
1192: result.add(match);
1193: }
1194: }
1195: }
1196: }
1197:
1198: pm.done();
1199:
1200: return result;
1201: }
1202:
1203: private static ConstraintVariable match(ConstraintVariable matchee,
1204: ConstraintVariable left, ConstraintVariable right) {
1205: if (matchee.equals(left))
1206: return right;
1207: if (matchee.equals(right))
1208: return left;
1209: return null;
1210: }
1211:
1212: /**
1213: * Select the type constraints that involve the selected ASTNode.
1214: */
1215: private Collection/*<ITypeConstraint>*/findRelevantConstraints(
1216: Collection/*<ConstraintVariable>*/relevantConstraintVars,
1217: IProgressMonitor pm) throws CoreException {
1218:
1219: ICompilationUnit[] cus = collectAffectedUnits(new SubProgressMonitor(
1220: pm, 100));
1221:
1222: fAllConstraints = getConstraints(cus, new SubProgressMonitor(
1223: pm, 900));
1224:
1225: pm
1226: .beginTask(
1227: RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage,
1228: 1000 + fAllConstraints.size());
1229:
1230: if (DEBUG)
1231: printCollection("type constraints: ", fAllConstraints); //$NON-NLS-1$
1232: Collection/*<ITypeConstraint>*/result = new ArrayList();
1233: for (Iterator it = fAllConstraints.iterator(); it.hasNext();) {
1234: ITypeConstraint tc = (ITypeConstraint) it.next();
1235: if (tc.isSimpleTypeConstraint()) {
1236: SimpleTypeConstraint stc = (SimpleTypeConstraint) tc;
1237: if (stc.isDefinesConstraint()
1238: || stc.isEqualsConstraint())
1239: continue;
1240: if (stc.getLeft().equals(stc.getRight()))
1241: continue;
1242: if (isNull(stc.getLeft()))
1243: continue;
1244: if (relevantConstraintVars.contains(stc.getLeft())
1245: || relevantConstraintVars.contains(stc
1246: .getRight()))
1247: result.add(tc);
1248: } else {
1249: CompositeOrTypeConstraint cotc = (CompositeOrTypeConstraint) tc;
1250: ITypeConstraint[] components = cotc.getConstraints();
1251: for (int i = 0; i < components.length; i++) {
1252: ITypeConstraint component = components[i];
1253: SimpleTypeConstraint simpleComponent = (SimpleTypeConstraint) component;
1254: if (relevantConstraintVars.contains(simpleComponent
1255: .getLeft()))
1256: result.add(tc);
1257: }
1258: }
1259: pm.worked(1);
1260: }
1261: if (DEBUG)
1262: printCollection("selected constraints: ", result); //$NON-NLS-1$
1263: pm.done();
1264: return result;
1265: }
1266:
1267: /**
1268: * Finds the declaration of the ASTNode in a given AST at a specified offset and with a specified length
1269: */
1270: private static ASTNode findDeclaration(final ASTNode root,
1271: final int start, final int length) {
1272: ASTNode node = NodeFinder.perform(root, start, length);
1273: Assert.isTrue(node instanceof SimpleName, String.valueOf(node
1274: .getNodeType()));
1275: Assert.isTrue(root instanceof CompilationUnit, String
1276: .valueOf(root.getNodeType()));
1277: return ((CompilationUnit) root)
1278: .findDeclaringNode(((SimpleName) node).resolveBinding());
1279: }
1280:
1281: // For debugging
1282: static String print(Collection/*<ITypeBinding>*/types) {
1283: if (types.isEmpty())
1284: return "{ }"; //$NON-NLS-1$
1285: String result = "{ "; //$NON-NLS-1$
1286: for (Iterator it = types.iterator(); it.hasNext();) {
1287: ITypeBinding type = (ITypeBinding) it.next();
1288: result += type.getQualifiedName();
1289: if (it.hasNext()) {
1290: result += ", "; //$NON-NLS-1$
1291: } else {
1292: result += " }"; //$NON-NLS-1$
1293: }
1294: }
1295: return result;
1296: }
1297:
1298: /**
1299: * Determines the set of types for which a set of type constraints is satisfied.
1300: */
1301: private Collection/*<ITypeBinding>*/computeValidTypes(
1302: ITypeBinding originalType,
1303: Collection/*<ConstraintVariable>*/relevantVars,
1304: Collection/*<ITypeConstraint>*/relevantConstraints,
1305: IProgressMonitor pm) throws JavaModelException {
1306:
1307: Collection/*<ITypeBinding>*/result = new HashSet();
1308: IJavaProject project = fCu.getJavaProject();
1309:
1310: Collection/*<ITypeBinding>*/allTypes = new HashSet/*<IType>*/();
1311: allTypes.addAll(getAllSuperTypes(originalType));
1312:
1313: pm
1314: .beginTask(
1315: RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage,
1316: allTypes.size());
1317:
1318: for (Iterator/*<ITypeBinding>*/it = allTypes.iterator(); it
1319: .hasNext();) {
1320: ITypeBinding type = (ITypeBinding) it.next();
1321: if (isValid(project, type, relevantVars,
1322: relevantConstraints, new SubProgressMonitor(pm, 1))) {
1323: result.add(type);
1324: }
1325: }
1326: // "changing" to the original type is a no-op
1327: result.remove(originalType);
1328:
1329: // TODO: remove all types that are not visible --- need to check visibility in the CUs for
1330: // all relevant constraint variables
1331:
1332: pm.done();
1333:
1334: return result;
1335: }
1336:
1337: /**
1338: * Determines if a given type satisfies a set of type constraints.
1339: */
1340: private boolean isValid(IJavaProject project, ITypeBinding type,
1341: Collection/*<ConstraintVariable>*/relevantVars,
1342: Collection/*<ITypeConstraint>*/constraints,
1343: IProgressMonitor pm) throws JavaModelException {
1344: pm
1345: .beginTask(
1346: RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage,
1347: constraints.size());
1348: for (Iterator it = constraints.iterator(); it.hasNext();) {
1349: ITypeConstraint tc = (ITypeConstraint) it.next();
1350: if (tc instanceof SimpleTypeConstraint) {
1351: if (!(isValidSimpleConstraint(project, type,
1352: relevantVars, (SimpleTypeConstraint) tc)))
1353: return false;
1354: } else if (tc instanceof CompositeOrTypeConstraint) {
1355: if (!(isValidOrConstraint(project, type, relevantVars,
1356: (CompositeOrTypeConstraint) tc)))
1357: return false;
1358: }
1359: pm.worked(1);
1360: }
1361: pm.done();
1362: return true;
1363: }
1364:
1365: private boolean isValidSimpleConstraint(IJavaProject project,
1366: ITypeBinding type,
1367: Collection/*<ConstraintVariable>*/relevantVars,
1368: SimpleTypeConstraint stc) throws JavaModelException {
1369: if (relevantVars.contains(stc.getLeft())) { // upper bound
1370: if (!isSubTypeOf(type, findType(stc.getRight()))) {
1371: return false;
1372: }
1373: }
1374: return true;
1375: }
1376:
1377: private boolean isValidOrConstraint(IJavaProject project,
1378: ITypeBinding type,
1379: Collection/*<ConstraintVariable>*/relevantVars,
1380: CompositeOrTypeConstraint cotc) throws JavaModelException {
1381: ITypeConstraint[] components = cotc.getConstraints();
1382: for (int i = 0; i < components.length; i++) {
1383: if (components[i] instanceof SimpleTypeConstraint) {
1384: SimpleTypeConstraint sc = (SimpleTypeConstraint) components[i];
1385: if (relevantVars.contains(sc.getLeft())) { // upper bound
1386: if (isSubTypeOf(type, findType(sc.getRight())))
1387: return true;
1388: } else if (relevantVars.contains(sc.getRight())) { // lower bound
1389: if (isSubTypeOf(findType(sc.getLeft()), type))
1390: return true;
1391: }
1392: }
1393: }
1394: return false;
1395: }
1396:
1397: private ITypeBinding findType(ConstraintVariable cv) {
1398: return cv.getBinding();
1399: }
1400:
1401: /**
1402: * Gather constraints associated with a set of compilation units.
1403: */
1404: private Collection/*<ITypeConstraint>*/getConstraints(
1405: ICompilationUnit[] referringCus, IProgressMonitor pm) {
1406: pm
1407: .beginTask(
1408: RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage,
1409: referringCus.length);
1410: Collection/*<ITypeConstraint>*/result = new ArrayList();
1411: for (int i = 0; i < referringCus.length; i++) {
1412: result.addAll(getConstraints(referringCus[i]));
1413: pm.worked(1);
1414: if (pm.isCanceled())
1415: throw new OperationCanceledException();
1416: }
1417: pm.done();
1418: return result;
1419: }
1420:
1421: private List/*<ITypeConstraint>*/getConstraints(
1422: ICompilationUnit unit) {
1423: if (fConstraintCache.containsKey(unit))
1424: return (List) fConstraintCache.get(unit);
1425:
1426: CompilationUnit cu = ASTCreator.createAST(unit, null);
1427:
1428: // only generate type constraints for relevant MethodDeclaration subtrees
1429: if (fMethodBinding != null
1430: && fCuToSearchResultGroup.containsKey(unit)) {
1431: SearchResultGroup group = (SearchResultGroup) fCuToSearchResultGroup
1432: .get(unit);
1433: ASTNode[] nodes = ASTNodeSearchUtil.getAstNodes(group
1434: .getSearchResults(), cu);
1435: for (int i = 0; i < nodes.length; i++) {
1436: ASTNode node = nodes[i];
1437: if (fMethodBinding != null) {
1438: // find MethodDeclaration above it in the tree
1439: ASTNode n = node;
1440: while (!(n instanceof MethodDeclaration)) {
1441: n = n.getParent();
1442: }
1443: MethodDeclaration md = (MethodDeclaration) n;
1444: md.accept(fCollector);
1445: }
1446: }
1447: } else {
1448: cu.accept(fCollector);
1449: }
1450: List/*<ITypeConstraint>*/constraints = Arrays
1451: .asList(fCollector.getConstraints());
1452: fConstraintCache.put(unit, constraints);
1453: return constraints;
1454: }
1455:
1456: /**
1457: * update a CompilationUnit's imports after changing the type of declarations
1458: */
1459: private String updateImports(CompilationUnit astRoot,
1460: MultiTextEdit rootEdit) throws CoreException {
1461: ImportRewrite rewrite = StubUtility.createImportRewrite(
1462: astRoot, true);
1463: String typeName = rewrite.addImport(fSelectedType
1464: .getQualifiedName());
1465: rootEdit.addChild(rewrite.rewriteImports(null));
1466: return typeName;
1467: }
1468:
1469: // ------------------------------------------------------------------------------------------------- //
1470: // Miscellaneous helper methods
1471:
1472: /**
1473: * Returns the Collection<IType> of types that can be given to the selected declaration.
1474: * @return return the valid types
1475: */
1476: public Collection/*<IType>*/getValidTypes() {
1477: return fValidTypes;
1478: }
1479:
1480: public ITypeBinding getOriginalType() {
1481: return fSelectionTypeBinding;
1482: }
1483:
1484: private void setOriginalType(ITypeBinding originalType) {
1485: fSelectionTypeBinding = originalType;
1486: fSelectedType = findSuperTypeByName(originalType,
1487: fSelectedTypeName);
1488: }
1489:
1490: public String getTarget() {
1491: String typeName = fSelectionTypeBinding == null ? "" : fSelectionTypeBinding.getName() + " "; //$NON-NLS-1$//$NON-NLS-2$
1492: if (fFieldBinding != null) {
1493: return typeName + fFieldBinding.getName();
1494: } else if (fMethodBinding != null) {
1495: if (fParamIndex == -1) {
1496: return typeName + fMethodBinding.getName() + "(...)"; //$NON-NLS-1$
1497: } else {
1498: return typeName + fParamName;
1499: }
1500: } else if (fSelectionBinding != null) {
1501: return typeName + fSelectionBinding.getName();
1502: } else {
1503: return typeName;
1504: }
1505: }
1506:
1507: /**
1508: * Returns the Collection<String> of names of types that can be given to the selected declaration.
1509: * (used in tests only)
1510: */
1511: public Collection/*<String>*/getValidTypeNames() {
1512: Collection/*<String>*/typeNames = new ArrayList();
1513: for (Iterator it = fValidTypes.iterator(); it.hasNext();) {
1514: ITypeBinding type = (ITypeBinding) it.next();
1515: typeNames.add(type.getQualifiedName());
1516: }
1517:
1518: return typeNames;
1519: }
1520:
1521: /**
1522: * Find the ASTNode for the given source text selection, if it is a type
1523: * declaration, or null otherwise.
1524: * @param unit The compilation unit in which the selection was made
1525: * @param offset
1526: * @param length
1527: * @return ASTNode
1528: */
1529: private ASTNode getTargetNode(ICompilationUnit unit, int offset,
1530: int length) {
1531: CompilationUnit root = ASTCreator.createAST(unit, null);
1532: ASTNode node = NodeFinder.perform(root, offset, length);
1533: return node;
1534: }
1535:
1536: /**
1537: * Determines the set of compilation units that may give rise to type constraints that
1538: * we are interested in. This involves searching for overriding/overridden methods,
1539: * method calls, field accesses.
1540: */
1541: private ICompilationUnit[] collectAffectedUnits(IProgressMonitor pm)
1542: throws CoreException {
1543: // BUG: currently, no type constraints are generated for methods that are related
1544: // but that do not override each other. As a result, we may miss certain relevant
1545: // variables
1546:
1547: pm
1548: .beginTask(
1549: RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage,
1550: 100);
1551:
1552: if (fAffectedUnits != null) {
1553: if (DEBUG)
1554: printCollection(
1555: "affected units: ", Arrays.asList(fAffectedUnits)); //$NON-NLS-1$
1556: pm.worked(100);
1557: return fAffectedUnits;
1558: }
1559: if (fMethodBinding != null) {
1560: if (fMethodBinding != null) {
1561:
1562: IMethod selectedMethod = (IMethod) fMethodBinding
1563: .getJavaElement();
1564: if (selectedMethod == null) {
1565: // can't happen since we checked it up front in check initial conditions
1566: Assert
1567: .isTrue(
1568: false,
1569: RefactoringCoreMessages.ChangeTypeRefactoring_no_method);
1570: }
1571:
1572: // the following code fragment appears to be the source of a memory leak, when
1573: // GT is repeatedly applied
1574:
1575: IMethod root = selectedMethod;
1576: if (!root.getDeclaringType().isInterface()
1577: && MethodChecks.isVirtual(root)) {
1578: final SubProgressMonitor subMonitor = new SubProgressMonitor(
1579: pm, 5);
1580: IMethod inInterface = MethodChecks
1581: .isDeclaredInInterface(root, root
1582: .getDeclaringType()
1583: .newTypeHierarchy(
1584: new SubProgressMonitor(
1585: subMonitor, 1)),
1586: subMonitor);
1587: if (inInterface != null
1588: && !inInterface.equals(root))
1589: root = inInterface;
1590: }
1591:
1592: // end code fragment
1593:
1594: IMethod[] rippleMethods = RippleMethodFinder2
1595: .getRelatedMethods(root,
1596: new SubProgressMonitor(pm, 15), null);
1597: SearchPattern pattern = RefactoringSearchEngine
1598: .createOrPattern(rippleMethods,
1599: IJavaSearchConstants.ALL_OCCURRENCES);
1600:
1601: // To compute the scope we have to use the selected method. Otherwise we
1602: // might start from the wrong project.
1603: IJavaSearchScope scope = RefactoringScopeFactory
1604: .create(selectedMethod);
1605: CollectingSearchRequestor csr = new CollectingSearchRequestor();
1606:
1607: SearchResultGroup[] groups = RefactoringSearchEngine
1608: .search(pattern, null, scope, csr,
1609: new SubProgressMonitor(pm, 80),
1610: new RefactoringStatus()); //TODO: deal with errors from non-CU matches
1611:
1612: fAffectedUnits = getCus(groups);
1613: }
1614: } else if (fFieldBinding != null) {
1615: IField iField = (IField) fFieldBinding.getJavaElement();
1616: if (iField == null) {
1617: // can't happen since we checked it up front in check initial conditions
1618: Assert
1619: .isTrue(
1620: false,
1621: RefactoringCoreMessages.ChangeTypeRefactoring_no_filed);
1622: }
1623: SearchPattern pattern = SearchPattern.createPattern(iField,
1624: IJavaSearchConstants.ALL_OCCURRENCES,
1625: SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
1626: IJavaSearchScope scope = RefactoringScopeFactory
1627: .create(iField);
1628: CollectingSearchRequestor csr = new CollectingSearchRequestor();
1629: SearchResultGroup[] groups = RefactoringSearchEngine
1630: .search(pattern, null, scope, csr,
1631: new SubProgressMonitor(pm, 100),
1632: new RefactoringStatus()); //TODO: deal with errors from non-CU matches
1633: fAffectedUnits = getCus(groups);
1634: } else {
1635: // otherwise, selection was a local variable and we only have to search the CU
1636: // containing the selection
1637: fAffectedUnits = new ICompilationUnit[] { fCu };
1638: }
1639: if (DEBUG) {
1640: System.out.println("Determining affected CUs:"); //$NON-NLS-1$
1641: for (int i = 0; i < fAffectedUnits.length; i++) {
1642: System.out
1643: .println(" affected CU: " + fAffectedUnits[i].getElementName()); //$NON-NLS-1$
1644: }
1645: }
1646: pm.done();
1647: return fAffectedUnits;
1648: }
1649:
1650: public void setSelectedType(ITypeBinding type) {
1651: fSelectedType = type;
1652: }
1653:
1654: // -------------------------------------------------------------------------------------------- //
1655: // TODO The following utility methods should probably be moved to another class
1656:
1657: /**
1658: * Determines if a constraint variable corresponds to the constant "null".
1659: */
1660: private static boolean isNull(ConstraintVariable cv) {
1661: return cv instanceof ExpressionVariable
1662: && ((ExpressionVariable) cv).getExpressionType() == ASTNode.NULL_LITERAL;
1663: }
1664:
1665: /**
1666: * For debugging.
1667: */
1668: void printCollection(String title, Collection/*<Object>*/l) {
1669: System.out.println(l.size() + " " + title); //$NON-NLS-1$
1670: for (Iterator it = l.iterator(); it.hasNext();) {
1671: System.out.println(" " + it.next()); //$NON-NLS-1$
1672: }
1673: }
1674:
1675: /**
1676: * Returns the compilation units that contain the search results.
1677: */
1678: private ICompilationUnit[] getCus(SearchResultGroup[] groups) {
1679: List result = new ArrayList(groups.length);
1680: for (int i = 0; i < groups.length; i++) {
1681: SearchResultGroup group = groups[i];
1682: ICompilationUnit cu = group.getCompilationUnit();
1683: if (cu != null) {
1684: result.add(cu);
1685: fCuToSearchResultGroup.put(cu, group);
1686: }
1687: }
1688: return (ICompilationUnit[]) result
1689: .toArray(new ICompilationUnit[result.size()]);
1690: }
1691:
1692: /**
1693: * This always includes the type itself. It will include type
1694: * Object for any type other than Object
1695: */
1696: public Set/*<ITypeBinding>*/getAllSuperTypes(ITypeBinding type) {
1697: Set/*<ITypeBinding>*/result = new HashSet();
1698: result.add(type);
1699: if (type.getSuperclass() != null) {
1700: result.addAll(getAllSuperTypes(type.getSuperclass()));
1701: }
1702: ITypeBinding[] interfaces = type.getInterfaces();
1703: for (int i = 0; i < interfaces.length; i++) {
1704: result.addAll(getAllSuperTypes(interfaces[i]));
1705: }
1706: if ((type != fObject) && !contains(result, fObject)) {
1707: result.add(fObject);
1708: }
1709: return result;
1710: }
1711:
1712: private ITypeBinding findSuperTypeByName(ITypeBinding type,
1713: String super TypeName) {
1714: Set/*<ITypeBinding>*/super Types = getAllSuperTypes(type);
1715: for (Iterator/*<ITypeBinding>*/it = super Types.iterator(); it
1716: .hasNext();) {
1717: ITypeBinding sup = (ITypeBinding) it.next();
1718: if (sup.getQualifiedName().equals(super TypeName)) {
1719: return sup;
1720: }
1721: }
1722: return null;
1723: }
1724:
1725: public boolean isSubTypeOf(ITypeBinding type1, ITypeBinding type2) {
1726:
1727: // to ensure that, e.g., Comparable<String> is considered a subtype of raw Comparable
1728: if (type1.isParameterizedType()
1729: && type1.getTypeDeclaration().isEqualTo(
1730: type2.getTypeDeclaration())) {
1731: return true;
1732: }
1733: Set super Types = getAllSuperTypes(type1);
1734: return contains(super Types, type2);
1735: }
1736:
1737: private static boolean contains(Collection/*<ITypeBinding>*/c,
1738: ITypeBinding binding) {
1739: for (Iterator/*<ITypeBinding>*/it = c.iterator(); it.hasNext();) {
1740: ITypeBinding b = (ITypeBinding) it.next();
1741: if (Bindings.equals(b, binding))
1742: return true;
1743: }
1744: return false;
1745: }
1746:
1747: /**
1748: * {@inheritDoc}
1749: */
1750: public RefactoringStatus initialize(RefactoringArguments arguments) {
1751: if (arguments instanceof JavaRefactoringArguments) {
1752: final JavaRefactoringArguments extended = (JavaRefactoringArguments) arguments;
1753: final String selection = extended
1754: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION);
1755: if (selection != null) {
1756: int offset = -1;
1757: int length = -1;
1758: final StringTokenizer tokenizer = new StringTokenizer(
1759: selection);
1760: if (tokenizer.hasMoreTokens())
1761: offset = Integer.valueOf(tokenizer.nextToken())
1762: .intValue();
1763: if (tokenizer.hasMoreTokens())
1764: length = Integer.valueOf(tokenizer.nextToken())
1765: .intValue();
1766: if (offset >= 0 && length >= 0) {
1767: fSelectionStart = offset;
1768: fSelectionLength = length;
1769: } else
1770: return RefactoringStatus
1771: .createFatalErrorStatus(Messages
1772: .format(
1773: RefactoringCoreMessages.InitializableRefactoring_illegal_argument,
1774: new Object[] {
1775: selection,
1776: JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION }));
1777: } else
1778: return RefactoringStatus
1779: .createFatalErrorStatus(Messages
1780: .format(
1781: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1782: JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION));
1783: final String handle = extended
1784: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
1785: if (handle != null) {
1786: final IJavaElement element = JavaRefactoringDescriptorUtil
1787: .handleToElement(extended.getProject(), handle,
1788: false);
1789: if (element == null
1790: || !element.exists()
1791: || element.getElementType() != IJavaElement.COMPILATION_UNIT)
1792: return createInputFatalStatus(element,
1793: IJavaRefactorings.GENERALIZE_TYPE);
1794: else
1795: fCu = (ICompilationUnit) element;
1796: } else
1797: return RefactoringStatus
1798: .createFatalErrorStatus(Messages
1799: .format(
1800: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1801: JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
1802: final String type = extended.getAttribute(ATTRIBUTE_TYPE);
1803: if (type != null && !"".equals(type)) //$NON-NLS-1$
1804: fSelectedTypeName = type;
1805: else
1806: return RefactoringStatus
1807: .createFatalErrorStatus(Messages
1808: .format(
1809: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1810: ATTRIBUTE_TYPE));
1811: } else
1812: return RefactoringStatus
1813: .createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
1814: return new RefactoringStatus();
1815: }
1816: }
|