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.constraints;
0011:
0012: import java.util.ArrayList;
0013: import java.util.Collection;
0014: import java.util.Collections;
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:
0022: import org.eclipse.text.edits.MalformedTreeException;
0023: import org.eclipse.text.edits.TextEdit;
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.SubProgressMonitor;
0031:
0032: import org.eclipse.jface.text.BadLocationException;
0033: import org.eclipse.jface.text.Document;
0034: import org.eclipse.jface.text.IDocument;
0035:
0036: import org.eclipse.ltk.core.refactoring.GroupCategory;
0037: import org.eclipse.ltk.core.refactoring.GroupCategorySet;
0038: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
0039: import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor;
0040:
0041: import org.eclipse.jdt.core.BindingKey;
0042: import org.eclipse.jdt.core.ICompilationUnit;
0043: import org.eclipse.jdt.core.IField;
0044: import org.eclipse.jdt.core.IJavaElement;
0045: import org.eclipse.jdt.core.IJavaProject;
0046: import org.eclipse.jdt.core.IMember;
0047: import org.eclipse.jdt.core.IMethod;
0048: import org.eclipse.jdt.core.IPackageFragment;
0049: import org.eclipse.jdt.core.IType;
0050: import org.eclipse.jdt.core.ITypeParameter;
0051: import org.eclipse.jdt.core.JavaCore;
0052: import org.eclipse.jdt.core.JavaModelException;
0053: import org.eclipse.jdt.core.WorkingCopyOwner;
0054: import org.eclipse.jdt.core.dom.AST;
0055: import org.eclipse.jdt.core.dom.ASTNode;
0056: import org.eclipse.jdt.core.dom.ASTParser;
0057: import org.eclipse.jdt.core.dom.ASTRequestor;
0058: import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
0059: import org.eclipse.jdt.core.dom.ArrayType;
0060: import org.eclipse.jdt.core.dom.BodyDeclaration;
0061: import org.eclipse.jdt.core.dom.CastExpression;
0062: import org.eclipse.jdt.core.dom.CompilationUnit;
0063: import org.eclipse.jdt.core.dom.FieldDeclaration;
0064: import org.eclipse.jdt.core.dom.IBinding;
0065: import org.eclipse.jdt.core.dom.IMethodBinding;
0066: import org.eclipse.jdt.core.dom.ITypeBinding;
0067: import org.eclipse.jdt.core.dom.IVariableBinding;
0068: import org.eclipse.jdt.core.dom.MethodDeclaration;
0069: import org.eclipse.jdt.core.dom.QualifiedName;
0070: import org.eclipse.jdt.core.dom.SimpleName;
0071: import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
0072: import org.eclipse.jdt.core.dom.Type;
0073: import org.eclipse.jdt.core.dom.TypeDeclaration;
0074: import org.eclipse.jdt.core.dom.TypeParameter;
0075: import org.eclipse.jdt.core.dom.VariableDeclaration;
0076: import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
0077: import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
0078: import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
0079: import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
0080: import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
0081: import org.eclipse.jdt.core.formatter.CodeFormatter;
0082: import org.eclipse.jdt.core.search.IJavaSearchConstants;
0083: import org.eclipse.jdt.core.search.SearchMatch;
0084: import org.eclipse.jdt.core.search.SearchPattern;
0085:
0086: import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
0087: import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
0088: import org.eclipse.jdt.internal.corext.dom.ASTNodes;
0089: import org.eclipse.jdt.internal.corext.dom.NodeFinder;
0090: import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
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.RefactoringSearchEngine2;
0094: import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
0095: import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil;
0096: import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
0097: import org.eclipse.jdt.internal.corext.refactoring.structure.ImportRewriteUtil;
0098: import org.eclipse.jdt.internal.corext.refactoring.tagging.ICommentProvider;
0099: import org.eclipse.jdt.internal.corext.refactoring.tagging.IScriptableRefactoring;
0100: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange;
0101: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
0102: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TypeEnvironment;
0103: import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
0104: import org.eclipse.jdt.internal.corext.refactoring.util.TextEditBasedChangeManager;
0105: import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
0106: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
0107: import org.eclipse.jdt.internal.corext.util.JdtFlags;
0108: import org.eclipse.jdt.internal.corext.util.SearchUtils;
0109:
0110: import org.eclipse.jdt.ui.CodeGeneration;
0111:
0112: import org.eclipse.jdt.internal.ui.JavaPlugin;
0113:
0114: /**
0115: * Partial implementation of a refactoring processor solving supertype
0116: * constraint models.
0117: *
0118: * @since 3.1
0119: */
0120: public abstract class SuperTypeRefactoringProcessor extends
0121: RefactoringProcessor implements IScriptableRefactoring,
0122: ICommentProvider {
0123:
0124: // TODO: remove
0125: protected static final String ATTRIBUTE_INSTANCEOF = "instanceof"; //$NON-NLS-1$
0126:
0127: // TODO: remove
0128: protected static final String ATTRIBUTE_REPLACE = "replace"; //$NON-NLS-1$
0129:
0130: /** The super type group category set */
0131: protected static final GroupCategorySet SET_SUPER_TYPE = new GroupCategorySet(
0132: new GroupCategory(
0133: "org.eclipse.jdt.internal.corext.superType", //$NON-NLS-1$
0134: RefactoringCoreMessages.SuperTypeRefactoringProcessor_category_name,
0135: RefactoringCoreMessages.SuperTypeRefactoringProcessor_category_description));
0136:
0137: /** Number of compilation units to parse at once */
0138: private static final int SIZE_BATCH = 500;
0139:
0140: /**
0141: * Returns a new ast node corresponding to the given type.
0142: *
0143: * @param rewrite
0144: * the compilation unit rewrite to use
0145: * @param type
0146: * the specified type
0147: * @return A corresponding ast node
0148: */
0149: protected static ASTNode createCorrespondingNode(
0150: final CompilationUnitRewrite rewrite, final TType type) {
0151: return rewrite.getImportRewrite().addImportFromSignature(
0152: new BindingKey(type.getBindingKey()).toSignature(),
0153: rewrite.getAST());
0154: }
0155:
0156: /** The comment */
0157: protected String fComment;
0158:
0159: /** Should type occurrences on instanceof's also be rewritten? */
0160: protected boolean fInstanceOf = false;
0161:
0162: /**
0163: * The obsolete casts (element type:
0164: * <code><ICompilationUnit, Collection<CastVariable2>></code>)
0165: */
0166: protected Map fObsoleteCasts = null;
0167:
0168: /** The working copy owner */
0169: protected final WorkingCopyOwner fOwner = new WorkingCopyOwner() {
0170: };
0171:
0172: /** Should occurrences of the type be replaced by the supertype? */
0173: protected boolean fReplace = false;
0174:
0175: /** The code generation settings, or <code>null</code> */
0176: protected CodeGenerationSettings fSettings;
0177:
0178: /** The static bindings to import */
0179: protected final Set fStaticBindings = new HashSet();
0180:
0181: /** The type bindings to import */
0182: protected final Set fTypeBindings = new HashSet();
0183:
0184: /**
0185: * The type occurrences (element type:
0186: * <code><ICompilationUnit, Collection<IDeclaredConstraintVariable>></code>)
0187: */
0188: protected Map fTypeOccurrences = null;
0189:
0190: /**
0191: * Creates a new supertype refactoring processor.
0192: *
0193: * @param settings
0194: * the code generation settings, or <code>null</code>
0195: */
0196: protected SuperTypeRefactoringProcessor(
0197: final CodeGenerationSettings settings) {
0198: fSettings = settings;
0199: }
0200:
0201: /**
0202: * Adds the refactoring settings to the specified comment.
0203: *
0204: * @param comment
0205: * the java refactoring descriptor comment
0206: * @param addUseSupertype
0207: * <code>true</code> to add the use supertype setting,
0208: * <code>false</code> otherwise
0209: */
0210: protected void addSuperTypeSettings(
0211: final JDTRefactoringDescriptorComment comment,
0212: final boolean addUseSupertype) {
0213: Assert.isNotNull(comment);
0214: if (fReplace) {
0215: if (addUseSupertype)
0216: comment
0217: .addSetting(RefactoringCoreMessages.SuperTypeRefactoringProcessor_user_super type_setting);
0218: if (fInstanceOf)
0219: comment
0220: .addSetting(RefactoringCoreMessages.SuperTypeRefactoringProcessor_use_in_instanceof _setting);
0221: }
0222: }
0223:
0224: /**
0225: * {@inheritDoc}
0226: */
0227: public boolean canEnableComment() {
0228: return true;
0229: }
0230:
0231: /**
0232: * Creates the super type constraint solver to solve the model.
0233: *
0234: * @param model
0235: * the model to create a solver for
0236: * @return The created super type constraint solver
0237: */
0238: protected abstract SuperTypeConstraintsSolver createContraintSolver(
0239: SuperTypeConstraintsModel model);
0240:
0241: /**
0242: * Creates the declarations of the new supertype members.
0243: *
0244: * @param sourceRewrite
0245: * the source compilation unit rewrite
0246: * @param targetRewrite
0247: * the target rewrite
0248: * @param targetDeclaration
0249: * the target type declaration
0250: * @throws CoreException
0251: * if a buffer could not be retrieved
0252: */
0253: protected void createMemberDeclarations(
0254: CompilationUnitRewrite sourceRewrite,
0255: ASTRewrite targetRewrite,
0256: AbstractTypeDeclaration targetDeclaration)
0257: throws CoreException {
0258: // Do nothing
0259: }
0260:
0261: /**
0262: * Creates the declaration of the new supertype, excluding any comments or
0263: * package declaration.
0264: *
0265: * @param sourceRewrite
0266: * the source compilation unit rewrite
0267: * @param subType
0268: * the subtype
0269: * @param superName
0270: * the name of the supertype
0271: * @param sourceDeclaration
0272: * the type declaration of the source type
0273: * @param buffer
0274: * the string buffer containing the declaration
0275: * @param isInterface
0276: * <code>true</code> if the type declaration is an interface,
0277: * <code>false</code> otherwise
0278: * @param status
0279: * the refactoring status
0280: * @param monitor
0281: * the progress monitor to use
0282: * @throws CoreException
0283: * if an error occurs
0284: */
0285: protected final void createTypeDeclaration(
0286: final CompilationUnitRewrite sourceRewrite,
0287: final IType subType, final String super Name,
0288: final AbstractTypeDeclaration sourceDeclaration,
0289: final StringBuffer buffer, boolean isInterface,
0290: final RefactoringStatus status,
0291: final IProgressMonitor monitor) throws CoreException {
0292: Assert.isNotNull(sourceRewrite);
0293: Assert.isNotNull(subType);
0294: Assert.isNotNull(super Name);
0295: Assert.isNotNull(sourceDeclaration);
0296: Assert.isNotNull(buffer);
0297: Assert.isNotNull(status);
0298: Assert.isNotNull(monitor);
0299: try {
0300: monitor.beginTask("", 100); //$NON-NLS-1$
0301: monitor
0302: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
0303: final String delimiter = StubUtility
0304: .getLineDelimiterUsed(subType.getJavaProject());
0305: if (JdtFlags.isPublic(subType)) {
0306: buffer.append(JdtFlags.VISIBILITY_STRING_PUBLIC);
0307: buffer.append(" "); //$NON-NLS-1$
0308: }
0309: if (isInterface)
0310: buffer.append("interface "); //$NON-NLS-1$
0311: else
0312: buffer.append("class "); //$NON-NLS-1$
0313: buffer.append(super Name);
0314: buffer.append(" {"); //$NON-NLS-1$
0315: buffer.append(delimiter);
0316: buffer.append(delimiter);
0317: buffer.append('}');
0318: final IDocument document = new Document(buffer.toString());
0319: final ASTParser parser = ASTParser.newParser(AST.JLS3);
0320: parser.setSource(document.get().toCharArray());
0321: final CompilationUnit unit = (CompilationUnit) parser
0322: .createAST(new SubProgressMonitor(monitor, 100));
0323: final ASTRewrite targetRewrite = ASTRewrite.create(unit
0324: .getAST());
0325: final AbstractTypeDeclaration targetDeclaration = (AbstractTypeDeclaration) unit
0326: .types().get(0);
0327: createTypeParameters(targetRewrite, subType,
0328: sourceDeclaration, targetDeclaration);
0329: createMemberDeclarations(sourceRewrite, targetRewrite,
0330: targetDeclaration);
0331: final TextEdit edit = targetRewrite.rewriteAST(document,
0332: subType.getJavaProject().getOptions(true));
0333: try {
0334: edit.apply(document, TextEdit.UPDATE_REGIONS);
0335: } catch (MalformedTreeException exception) {
0336: JavaPlugin.log(exception);
0337: } catch (BadLocationException exception) {
0338: JavaPlugin.log(exception);
0339: }
0340: buffer.setLength(0);
0341: buffer.append(document.get());
0342: } finally {
0343: monitor.done();
0344: }
0345: }
0346:
0347: /**
0348: * Creates the necessary imports for the extracted supertype.
0349: *
0350: * @param unit
0351: * the working copy of the new supertype
0352: * @param monitor
0353: * the progress monitor to use
0354: * @return the generated import declaration
0355: * @throws CoreException
0356: * if the imports could not be generated
0357: */
0358: protected final String createTypeImports(
0359: final ICompilationUnit unit, final IProgressMonitor monitor)
0360: throws CoreException {
0361: Assert.isNotNull(unit);
0362: Assert.isNotNull(monitor);
0363: try {
0364: monitor.beginTask("", 100); //$NON-NLS-1$
0365: monitor
0366: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
0367: final ImportRewrite rewrite = StubUtility
0368: .createImportRewrite(unit, true);
0369: ITypeBinding type = null;
0370: for (final Iterator iterator = fTypeBindings.iterator(); iterator
0371: .hasNext();) {
0372: type = (ITypeBinding) iterator.next();
0373: if (type.isTypeVariable()) {
0374: final ITypeBinding[] bounds = type.getTypeBounds();
0375: for (int index = 0; index < bounds.length; index++)
0376: rewrite.addImport(bounds[index]);
0377: }
0378: rewrite.addImport(type);
0379: }
0380: IBinding binding = null;
0381: for (final Iterator iterator = fStaticBindings.iterator(); iterator
0382: .hasNext();) {
0383: binding = (IBinding) iterator.next();
0384: rewrite.addStaticImport(binding);
0385: }
0386: final IDocument document = new Document();
0387: try {
0388: rewrite.rewriteImports(
0389: new SubProgressMonitor(monitor, 100)).apply(
0390: document);
0391: } catch (MalformedTreeException exception) {
0392: JavaPlugin.log(exception);
0393: } catch (BadLocationException exception) {
0394: JavaPlugin.log(exception);
0395: } catch (CoreException exception) {
0396: JavaPlugin.log(exception);
0397: }
0398: fTypeBindings.clear();
0399: fStaticBindings.clear();
0400: return document.get();
0401: } finally {
0402: monitor.done();
0403: }
0404: }
0405:
0406: /**
0407: * Creates the type parameters of the new supertype.
0408: *
0409: * @param targetRewrite
0410: * the target compilation unit rewrite
0411: * @param subType
0412: * the subtype
0413: * @param sourceDeclaration
0414: * the type declaration of the source type
0415: * @param targetDeclaration
0416: * the type declaration of the target type
0417: */
0418: protected final void createTypeParameters(
0419: final ASTRewrite targetRewrite, final IType subType,
0420: final AbstractTypeDeclaration sourceDeclaration,
0421: final AbstractTypeDeclaration targetDeclaration) {
0422: Assert.isNotNull(targetRewrite);
0423: Assert.isNotNull(sourceDeclaration);
0424: Assert.isNotNull(targetDeclaration);
0425: if (sourceDeclaration instanceof TypeDeclaration) {
0426: TypeParameter parameter = null;
0427: final ListRewrite rewrite = targetRewrite.getListRewrite(
0428: targetDeclaration,
0429: TypeDeclaration.TYPE_PARAMETERS_PROPERTY);
0430: for (final Iterator iterator = ((TypeDeclaration) sourceDeclaration)
0431: .typeParameters().iterator(); iterator.hasNext();) {
0432: parameter = (TypeParameter) iterator.next();
0433: rewrite.insertLast(ASTNode.copySubtree(targetRewrite
0434: .getAST(), parameter), null);
0435: ImportRewriteUtil.collectImports(subType
0436: .getJavaProject(), sourceDeclaration,
0437: fTypeBindings, fStaticBindings, false);
0438: }
0439: }
0440: }
0441:
0442: /**
0443: * Creates the source for the new compilation unit containing the supertype.
0444: *
0445: * @param copy
0446: * the working copy of the new supertype
0447: * @param subType
0448: * the subtype
0449: * @param superName
0450: * the name of the supertype
0451: * @param sourceRewrite
0452: * the source compilation unit rewrite
0453: * @param declaration
0454: * the type declaration
0455: * @param status
0456: * the refactoring status
0457: * @param monitor
0458: * the progress monitor to display progress
0459: * @return the source of the new compilation unit, or <code>null</code>
0460: * @throws CoreException
0461: * if an error occurs
0462: */
0463: protected final String createTypeSource(
0464: final ICompilationUnit copy, final IType subType,
0465: final String super Name,
0466: final CompilationUnitRewrite sourceRewrite,
0467: final AbstractTypeDeclaration declaration,
0468: final RefactoringStatus status,
0469: final IProgressMonitor monitor) throws CoreException {
0470: Assert.isNotNull(copy);
0471: Assert.isNotNull(subType);
0472: Assert.isNotNull(super Name);
0473: Assert.isNotNull(sourceRewrite);
0474: Assert.isNotNull(declaration);
0475: Assert.isNotNull(status);
0476: Assert.isNotNull(monitor);
0477: String source = null;
0478: try {
0479: monitor.beginTask("", 100); //$NON-NLS-1$
0480: monitor
0481: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
0482: final String delimiter = StubUtility
0483: .getLineDelimiterUsed(subType.getJavaProject());
0484: String typeComment = null;
0485: String fileComment = null;
0486: if (fSettings.createComments) {
0487: final ITypeParameter[] parameters = subType
0488: .getTypeParameters();
0489: final String[] names = new String[parameters.length];
0490: for (int index = 0; index < parameters.length; index++)
0491: names[index] = parameters[index].getElementName();
0492: typeComment = CodeGeneration.getTypeComment(copy,
0493: super Name, names, delimiter);
0494: fileComment = CodeGeneration.getFileComment(copy,
0495: delimiter);
0496: }
0497: final StringBuffer buffer = new StringBuffer(64);
0498: createTypeDeclaration(sourceRewrite, subType, super Name,
0499: declaration, buffer, true, status,
0500: new SubProgressMonitor(monitor, 40));
0501: final String imports = createTypeImports(copy,
0502: new SubProgressMonitor(monitor, 60));
0503: source = createTypeTemplate(copy, imports, fileComment,
0504: typeComment, buffer.toString());
0505: if (source == null) {
0506: if (!subType.getPackageFragment().isDefaultPackage()) {
0507: if (imports.length() > 0)
0508: buffer.insert(0, imports);
0509: buffer
0510: .insert(
0511: 0,
0512: "package " + subType.getPackageFragment().getElementName() + ";"); //$NON-NLS-1$//$NON-NLS-2$
0513: }
0514: source = buffer.toString();
0515: }
0516: final IDocument document = new Document(source);
0517: final TextEdit edit = CodeFormatterUtil.format2(
0518: CodeFormatter.K_COMPILATION_UNIT, source, 0,
0519: delimiter, copy.getJavaProject().getOptions(true));
0520: if (edit != null) {
0521: try {
0522: edit.apply(document, TextEdit.UPDATE_REGIONS);
0523: } catch (MalformedTreeException exception) {
0524: JavaPlugin.log(exception);
0525: status
0526: .merge(RefactoringStatus
0527: .createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
0528: } catch (BadLocationException exception) {
0529: JavaPlugin.log(exception);
0530: status
0531: .merge(RefactoringStatus
0532: .createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
0533: }
0534: source = document.get();
0535: }
0536: } finally {
0537: monitor.done();
0538: }
0539: return source;
0540: }
0541:
0542: /**
0543: * Creates the type template based on the code generation settings.
0544: *
0545: * @param unit
0546: * the working copy for the new supertype
0547: * @param imports
0548: * the generated imports declaration
0549: * @param fileComment
0550: * the file comment
0551: * @param comment
0552: * the type comment
0553: * @param content
0554: * the type content
0555: * @return a template for the supertype, or <code>null</code>
0556: * @throws CoreException
0557: * if the template could not be evaluated
0558: */
0559: protected final String createTypeTemplate(
0560: final ICompilationUnit unit, final String imports,
0561: String fileComment, final String comment,
0562: final String content) throws CoreException {
0563: Assert.isNotNull(unit);
0564: Assert.isNotNull(imports);
0565: Assert.isNotNull(content);
0566: final IPackageFragment fragment = (IPackageFragment) unit
0567: .getParent();
0568: final StringBuffer buffer = new StringBuffer();
0569: final String delimiter = StubUtility.getLineDelimiterUsed(unit
0570: .getJavaProject());
0571: if (!fragment.isDefaultPackage()) {
0572: buffer.append("package " + fragment.getElementName() + ";"); //$NON-NLS-1$ //$NON-NLS-2$
0573: buffer.append(delimiter);
0574: buffer.append(delimiter);
0575: }
0576: if (imports.length() > 0)
0577: buffer.append(imports);
0578:
0579: return StubUtility.getCompilationUnitContent(unit, buffer
0580: .toString(), fileComment, comment, content, delimiter);
0581: }
0582:
0583: /**
0584: * {@inheritDoc}
0585: */
0586: protected void finalize() throws Throwable {
0587: resetWorkingCopies();
0588: }
0589:
0590: /**
0591: * {@inheritDoc}
0592: */
0593: public final String getComment() {
0594: return fComment;
0595: }
0596:
0597: /**
0598: * Returns the field which corresponds to the specified variable declaration
0599: * fragment
0600: *
0601: * @param fragment
0602: * the variable declaration fragment
0603: * @return the corresponding field
0604: * @throws JavaModelException
0605: * if an error occurs
0606: */
0607: protected final IField getCorrespondingField(
0608: final VariableDeclarationFragment fragment)
0609: throws JavaModelException {
0610: final IBinding binding = fragment.getName().resolveBinding();
0611: if (binding instanceof IVariableBinding) {
0612: final IVariableBinding variable = (IVariableBinding) binding;
0613: if (variable.isField()) {
0614: final ICompilationUnit unit = RefactoringASTParser
0615: .getCompilationUnit(fragment);
0616: final IJavaElement element = unit.getElementAt(fragment
0617: .getStartPosition());
0618: if (element instanceof IField)
0619: return (IField) element;
0620: }
0621: }
0622: return null;
0623: }
0624:
0625: /**
0626: * Computes the compilation units of fields referencing the specified type
0627: * occurrences.
0628: *
0629: * @param units
0630: * the compilation unit map (element type:
0631: * <code><IJavaProject, Set<ICompilationUnit>></code>)
0632: * @param nodes
0633: * the ast nodes representing the type occurrences
0634: * @throws JavaModelException
0635: * if an error occurs
0636: */
0637: protected final void getFieldReferencingCompilationUnits(
0638: final Map units, final ASTNode[] nodes)
0639: throws JavaModelException {
0640: ASTNode node = null;
0641: IField field = null;
0642: IJavaProject project = null;
0643: for (int index = 0; index < nodes.length; index++) {
0644: node = nodes[index];
0645: project = RefactoringASTParser.getCompilationUnit(node)
0646: .getJavaProject();
0647: if (project != null) {
0648: final List fields = getReferencingFields(node, project);
0649: for (int offset = 0; offset < fields.size(); offset++) {
0650: field = (IField) fields.get(offset);
0651: Set set = (Set) units.get(project);
0652: if (set == null) {
0653: set = new HashSet();
0654: units.put(project, set);
0655: }
0656: final ICompilationUnit unit = field
0657: .getCompilationUnit();
0658: if (unit != null)
0659: set.add(unit);
0660: }
0661: }
0662: }
0663: }
0664:
0665: /**
0666: * Computes the compilation units of methods referencing the specified type
0667: * occurrences.
0668: *
0669: * @param units
0670: * the compilation unit map (element type:
0671: * <code><IJavaProject, Set<ICompilationUnit>></code>)
0672: * @param nodes
0673: * the ast nodes representing the type occurrences
0674: * @throws JavaModelException
0675: * if an error occurs
0676: */
0677: protected final void getMethodReferencingCompilationUnits(
0678: final Map units, final ASTNode[] nodes)
0679: throws JavaModelException {
0680: ASTNode node = null;
0681: IMethod method = null;
0682: IJavaProject project = null;
0683: for (int index = 0; index < nodes.length; index++) {
0684: node = nodes[index];
0685: project = RefactoringASTParser.getCompilationUnit(node)
0686: .getJavaProject();
0687: if (project != null) {
0688: method = getReferencingMethod(node);
0689: if (method != null) {
0690: Set set = (Set) units.get(project);
0691: if (set == null) {
0692: set = new HashSet();
0693: units.put(project, set);
0694: }
0695: final ICompilationUnit unit = method
0696: .getCompilationUnit();
0697: if (unit != null)
0698: set.add(unit);
0699: }
0700: }
0701: }
0702: }
0703:
0704: /**
0705: * Computes the compilation units referencing the subtype to replace.
0706: *
0707: * @param type
0708: * the subtype
0709: * @param monitor
0710: * the progress monitor to use
0711: * @param status
0712: * the refactoring status
0713: * @return the referenced compilation units (element type:
0714: * <code><IJavaProject, Collection<SearchResultGroup>></code>)
0715: * @throws JavaModelException
0716: * if an error occurs
0717: */
0718: protected final Map getReferencingCompilationUnits(
0719: final IType type, final IProgressMonitor monitor,
0720: final RefactoringStatus status) throws JavaModelException {
0721: try {
0722: monitor.beginTask("", 100); //$NON-NLS-1$
0723: monitor
0724: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
0725: final RefactoringSearchEngine2 engine = new RefactoringSearchEngine2();
0726: engine.setOwner(fOwner);
0727: engine.setFiltering(true, true);
0728: engine.setStatus(status);
0729: engine.setScope(RefactoringScopeFactory.create(type));
0730: engine.setPattern(SearchPattern.createPattern(type,
0731: IJavaSearchConstants.REFERENCES,
0732: SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE));
0733: engine.searchPattern(new SubProgressMonitor(monitor, 100));
0734: return engine.getAffectedProjects();
0735: } finally {
0736: monitor.done();
0737: }
0738: }
0739:
0740: /**
0741: * Returns the fields which reference the specified ast node.
0742: *
0743: * @param node
0744: * the ast node
0745: * @param project
0746: * the java project
0747: * @return the referencing fields
0748: * @throws JavaModelException
0749: * if an error occurs
0750: */
0751: protected final List getReferencingFields(final ASTNode node,
0752: final IJavaProject project) throws JavaModelException {
0753: List result = Collections.EMPTY_LIST;
0754: if (node instanceof Type) {
0755: final BodyDeclaration parent = (BodyDeclaration) ASTNodes
0756: .getParent(node, BodyDeclaration.class);
0757: if (parent instanceof FieldDeclaration) {
0758: final List fragments = ((FieldDeclaration) parent)
0759: .fragments();
0760: result = new ArrayList(fragments.size());
0761: VariableDeclarationFragment fragment = null;
0762: for (final Iterator iterator = fragments.iterator(); iterator
0763: .hasNext();) {
0764: fragment = (VariableDeclarationFragment) iterator
0765: .next();
0766: final IField field = getCorrespondingField(fragment);
0767: if (field != null)
0768: result.add(field);
0769: }
0770: }
0771: }
0772: return result;
0773: }
0774:
0775: /**
0776: * Returns the method which references the specified ast node.
0777: *
0778: * @param node
0779: * the ast node
0780: * @return the referencing method
0781: * @throws JavaModelException
0782: * if an error occurs
0783: */
0784: protected final IMethod getReferencingMethod(final ASTNode node)
0785: throws JavaModelException {
0786: if (node instanceof Type) {
0787: final BodyDeclaration parent = (BodyDeclaration) ASTNodes
0788: .getParent(node, BodyDeclaration.class);
0789: if (parent instanceof MethodDeclaration) {
0790: final IMethodBinding binding = ((MethodDeclaration) parent)
0791: .resolveBinding();
0792: if (binding != null) {
0793: final ICompilationUnit unit = RefactoringASTParser
0794: .getCompilationUnit(node);
0795: final IJavaElement element = unit.getElementAt(node
0796: .getStartPosition());
0797: if (element instanceof IMethod)
0798: return (IMethod) element;
0799: }
0800: }
0801: }
0802: return null;
0803: }
0804:
0805: protected ICompilationUnit getSharedWorkingCopy(
0806: final ICompilationUnit unit, final IProgressMonitor monitor)
0807: throws JavaModelException {
0808: try {
0809: ICompilationUnit copy = unit.findWorkingCopy(fOwner);
0810: if (copy == null)
0811: copy = unit.getWorkingCopy(fOwner, monitor);
0812: return copy;
0813: } finally {
0814: monitor.done();
0815: }
0816: }
0817:
0818: /**
0819: * Returns whether type occurrences in instanceof's should be rewritten.
0820: *
0821: * @return <code>true</code> if they are rewritten, <code>false</code>
0822: * otherwise
0823: */
0824: public final boolean isInstanceOf() {
0825: return fInstanceOf;
0826: }
0827:
0828: /**
0829: * Should occurrences of the subtype be replaced by the supertype?
0830: *
0831: * @return <code>true</code> if the subtype should be replaced,
0832: * <code>false</code> otherwise
0833: */
0834: public final boolean isReplace() {
0835: return fReplace;
0836: }
0837:
0838: /**
0839: * Performs the first pass of processing the affected compilation units.
0840: *
0841: * @param creator
0842: * the constraints creator to use
0843: * @param units
0844: * the compilation unit map (element type:
0845: * <code><IJavaProject, Set<ICompilationUnit>></code>)
0846: * @param groups
0847: * the search result group map (element type:
0848: * <code><ICompilationUnit, SearchResultGroup></code>)
0849: * @param unit
0850: * the compilation unit of the subtype
0851: * @param node
0852: * the compilation unit node of the subtype
0853: * @param monitor
0854: * the progress monitor to use
0855: */
0856: protected final void performFirstPass(
0857: final SuperTypeConstraintsCreator creator, final Map units,
0858: final Map groups, final ICompilationUnit unit,
0859: final CompilationUnit node, final IProgressMonitor monitor) {
0860: try {
0861: monitor.beginTask("", 100); //$NON-NLS-1$
0862: monitor
0863: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
0864: node.accept(creator);
0865: monitor.worked(20);
0866: final SearchResultGroup group = (SearchResultGroup) groups
0867: .get(unit);
0868: if (group != null) {
0869: final ASTNode[] nodes = ASTNodeSearchUtil.getAstNodes(
0870: group.getSearchResults(), node);
0871: try {
0872: getMethodReferencingCompilationUnits(units, nodes);
0873: monitor.worked(40);
0874: getFieldReferencingCompilationUnits(units, nodes);
0875: monitor.worked(40);
0876: } catch (JavaModelException exception) {
0877: JavaPlugin.log(exception);
0878: }
0879: }
0880: } finally {
0881: monitor.done();
0882: }
0883: }
0884:
0885: /**
0886: * Performs the second pass of processing the affected compilation units.
0887: *
0888: * @param creator
0889: * the constraints creator to use
0890: * @param unit
0891: * the compilation unit of the subtype
0892: * @param node
0893: * the compilation unit node of the subtype
0894: * @param monitor
0895: * the progress monitor to use
0896: */
0897: protected final void performSecondPass(
0898: final SuperTypeConstraintsCreator creator,
0899: final ICompilationUnit unit, final CompilationUnit node,
0900: final IProgressMonitor monitor) {
0901: try {
0902: monitor.beginTask("", 20); //$NON-NLS-1$
0903: monitor
0904: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
0905: node.accept(creator);
0906: monitor.worked(20);
0907: } finally {
0908: monitor.done();
0909: }
0910: }
0911:
0912: /**
0913: * Resets the working copies.
0914: */
0915: protected void resetWorkingCopies() {
0916: final ICompilationUnit[] units = JavaCore
0917: .getWorkingCopies(fOwner);
0918: for (int index = 0; index < units.length; index++) {
0919: final ICompilationUnit unit = units[index];
0920: try {
0921: unit.discardWorkingCopy();
0922: } catch (Exception exception) {
0923: // Do nothing
0924: }
0925: }
0926: }
0927:
0928: /**
0929: * Resets the working copies.
0930: *
0931: * @param unit
0932: * the compilation unit to discard
0933: */
0934: protected void resetWorkingCopies(final ICompilationUnit unit) {
0935: final ICompilationUnit[] units = JavaCore
0936: .getWorkingCopies(fOwner);
0937: for (int index = 0; index < units.length; index++) {
0938: if (!units[index].equals(unit)) {
0939: try {
0940: units[index].discardWorkingCopy();
0941: } catch (Exception exception) {
0942: // Do nothing
0943: }
0944: } else {
0945: try {
0946: units[index].getBuffer()
0947: .setContents(
0948: unit.getPrimary().getBuffer()
0949: .getContents());
0950: JavaModelUtil.reconcile(units[index]);
0951: } catch (JavaModelException exception) {
0952: JavaPlugin.log(exception);
0953: }
0954: }
0955: }
0956: }
0957:
0958: /**
0959: * Creates the necessary text edits to replace the subtype occurrence by a
0960: * supertype.
0961: *
0962: * @param range
0963: * the compilation unit range
0964: * @param estimate
0965: * the type estimate
0966: * @param requestor
0967: * the ast requestor to use
0968: * @param rewrite
0969: * the compilation unit rewrite to use
0970: * @param copy
0971: * the compilation unit node of the working copy ast
0972: * @param replacements
0973: * the set of variable binding keys of formal parameters which
0974: * must be replaced
0975: * @param group
0976: * the text edit group to use
0977: */
0978: protected final void rewriteTypeOccurrence(
0979: final CompilationUnitRange range, final TType estimate,
0980: final ASTRequestor requestor,
0981: final CompilationUnitRewrite rewrite,
0982: final CompilationUnit copy, final Set replacements,
0983: final TextEditGroup group) {
0984: ASTNode node = null;
0985: IBinding binding = null;
0986: final CompilationUnit target = rewrite.getRoot();
0987: node = NodeFinder.perform(copy, range.getSourceRange());
0988: if (node != null) {
0989: node = ASTNodes.getNormalizedNode(node).getParent();
0990: if (node instanceof VariableDeclaration) {
0991: binding = ((VariableDeclaration) node).resolveBinding();
0992: node = target.findDeclaringNode(binding.getKey());
0993: if (node instanceof SingleVariableDeclaration) {
0994: rewriteTypeOccurrence(estimate, rewrite,
0995: ((SingleVariableDeclaration) node)
0996: .getType(), group);
0997: if (node.getParent() instanceof MethodDeclaration) {
0998: binding = ((VariableDeclaration) node)
0999: .resolveBinding();
1000: if (binding != null)
1001: replacements.add(binding.getKey());
1002: }
1003: }
1004: } else if (node instanceof VariableDeclarationStatement) {
1005: binding = ((VariableDeclaration) ((VariableDeclarationStatement) node)
1006: .fragments().get(0)).resolveBinding();
1007: node = target.findDeclaringNode(binding.getKey());
1008: if (node instanceof VariableDeclarationFragment)
1009: rewriteTypeOccurrence(
1010: estimate,
1011: rewrite,
1012: ((VariableDeclarationStatement) ((VariableDeclarationFragment) node)
1013: .getParent()).getType(), group);
1014: } else if (node instanceof MethodDeclaration) {
1015: binding = ((MethodDeclaration) node).resolveBinding();
1016: node = target.findDeclaringNode(binding.getKey());
1017: if (node instanceof MethodDeclaration)
1018: rewriteTypeOccurrence(
1019: estimate,
1020: rewrite,
1021: ((MethodDeclaration) node).getReturnType2(),
1022: group);
1023: } else if (node instanceof FieldDeclaration) {
1024: binding = ((VariableDeclaration) ((FieldDeclaration) node)
1025: .fragments().get(0)).resolveBinding();
1026: node = target.findDeclaringNode(binding.getKey());
1027: if (node instanceof VariableDeclarationFragment) {
1028: node = node.getParent();
1029: if (node instanceof FieldDeclaration)
1030: rewriteTypeOccurrence(estimate, rewrite,
1031: ((FieldDeclaration) node).getType(),
1032: group);
1033: }
1034: } else if (node instanceof ArrayType) {
1035: final ASTNode type = node;
1036: while (node != null
1037: && !(node instanceof MethodDeclaration)
1038: && !(node instanceof VariableDeclarationFragment))
1039: node = node.getParent();
1040: if (node != null) {
1041: final int delta = node.getStartPosition()
1042: + node.getLength()
1043: - type.getStartPosition();
1044: if (node instanceof MethodDeclaration)
1045: binding = ((MethodDeclaration) node)
1046: .resolveBinding();
1047: else if (node instanceof VariableDeclarationFragment)
1048: binding = ((VariableDeclarationFragment) node)
1049: .resolveBinding();
1050: if (binding != null) {
1051: node = target.findDeclaringNode(binding
1052: .getKey());
1053: if (node instanceof MethodDeclaration
1054: || node instanceof VariableDeclarationFragment) {
1055: node = NodeFinder.perform(target, node
1056: .getStartPosition()
1057: + node.getLength() - delta, 0);
1058: if (node instanceof SimpleName)
1059: rewriteTypeOccurrence(estimate,
1060: rewrite, node, group);
1061: }
1062: }
1063: }
1064: } else if (node instanceof QualifiedName) {
1065: final ASTNode name = node;
1066: while (node != null
1067: && !(node instanceof MethodDeclaration)
1068: && !(node instanceof VariableDeclarationFragment))
1069: node = node.getParent();
1070: if (node != null) {
1071: final int delta = node.getStartPosition()
1072: + node.getLength()
1073: - name.getStartPosition();
1074: if (node instanceof MethodDeclaration)
1075: binding = ((MethodDeclaration) node)
1076: .resolveBinding();
1077: else if (node instanceof VariableDeclarationFragment)
1078: binding = ((VariableDeclarationFragment) node)
1079: .resolveBinding();
1080: if (binding != null) {
1081: node = target.findDeclaringNode(binding
1082: .getKey());
1083: if (node instanceof SimpleName
1084: || node instanceof MethodDeclaration
1085: || node instanceof VariableDeclarationFragment) {
1086: node = NodeFinder.perform(target, node
1087: .getStartPosition()
1088: + node.getLength() - delta, 0);
1089: if (node instanceof SimpleName)
1090: rewriteTypeOccurrence(estimate,
1091: rewrite, node, group);
1092: }
1093: }
1094: }
1095: } else if (node instanceof CastExpression) {
1096: final ASTNode expression = node;
1097: while (node != null
1098: && !(node instanceof MethodDeclaration))
1099: node = node.getParent();
1100: if (node != null) {
1101: final int delta = node.getStartPosition()
1102: + node.getLength()
1103: - expression.getStartPosition();
1104: binding = ((MethodDeclaration) node)
1105: .resolveBinding();
1106: node = target.findDeclaringNode(binding.getKey());
1107: if (node instanceof MethodDeclaration) {
1108: node = NodeFinder.perform(target, node
1109: .getStartPosition()
1110: + node.getLength() - delta, 0);
1111: if (node instanceof CastExpression)
1112: rewriteTypeOccurrence(estimate, rewrite,
1113: ((CastExpression) node).getType(),
1114: group);
1115: }
1116: }
1117: }
1118: }
1119: }
1120:
1121: /**
1122: * Creates the necessary text edits to replace the subtype occurrence by a
1123: * supertype.
1124: *
1125: * @param estimate
1126: * the type estimate
1127: * @param rewrite
1128: * the ast rewrite to use
1129: * @param node
1130: * the ast node to rewrite
1131: * @param group
1132: * the text edit group to use
1133: */
1134: protected final void rewriteTypeOccurrence(final TType estimate,
1135: final CompilationUnitRewrite rewrite, final ASTNode node,
1136: final TextEditGroup group) {
1137: rewrite.getImportRemover().registerRemovedNode(node);
1138: rewrite.getASTRewrite().replace(node,
1139: createCorrespondingNode(rewrite, estimate), group);
1140: }
1141:
1142: /**
1143: * Creates the necessary text edits to replace the subtype occurrence by a
1144: * supertype.
1145: *
1146: * @param manager
1147: * the text change manager to use
1148: * @param requestor
1149: * the ast requestor to use
1150: * @param rewrite
1151: * the compilation unit rewrite of the subtype (not in working
1152: * copy mode)
1153: * @param unit
1154: * the compilation unit
1155: * @param node
1156: * the compilation unit node
1157: * @param replacements
1158: * the set of variable binding keys of formal parameters which
1159: * must be replaced
1160: * @param monitor
1161: * the progress monitor to use
1162: * @throws CoreException
1163: * if the change could not be generated
1164: */
1165: protected abstract void rewriteTypeOccurrences(
1166: TextEditBasedChangeManager manager, ASTRequestor requestor,
1167: CompilationUnitRewrite rewrite, ICompilationUnit unit,
1168: CompilationUnit node, Set replacements,
1169: IProgressMonitor monitor) throws CoreException;
1170:
1171: /**
1172: * Creates the necessary text edits to replace the subtype occurrences by a
1173: * supertype.
1174: *
1175: * @param manager
1176: * the text change manager to use
1177: * @param sourceRewrite
1178: * the compilation unit rewrite of the subtype (not in working
1179: * copy mode)
1180: * @param sourceRequestor
1181: * the ast requestor of the subtype, or <code>null</code>
1182: * @param subUnit
1183: * the compilation unit of the subtype, or <code>null</code>
1184: * @param subNode
1185: * the compilation unit node of the subtype, or <code>null</code>
1186: * @param replacements
1187: * the set of variable binding keys of formal parameters which
1188: * must be replaced
1189: * @param status
1190: * the refactoring status
1191: * @param monitor
1192: * the progress monitor to use
1193: */
1194: protected final void rewriteTypeOccurrences(
1195: final TextEditBasedChangeManager manager,
1196: final ASTRequestor sourceRequestor,
1197: final CompilationUnitRewrite sourceRewrite,
1198: final ICompilationUnit subUnit,
1199: final CompilationUnit subNode, final Set replacements,
1200: final RefactoringStatus status,
1201: final IProgressMonitor monitor) {
1202: try {
1203: monitor.beginTask("", 300); //$NON-NLS-1$
1204: monitor
1205: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
1206: if (fTypeOccurrences != null) {
1207: final Set units = new HashSet(fTypeOccurrences.keySet());
1208: if (subUnit != null)
1209: units.remove(subUnit);
1210: final Map projects = new HashMap();
1211: Collection collection = null;
1212: IJavaProject project = null;
1213: ICompilationUnit current = null;
1214: for (final Iterator iterator = units.iterator(); iterator
1215: .hasNext();) {
1216: current = (ICompilationUnit) iterator.next();
1217: project = current.getJavaProject();
1218: collection = (Collection) projects.get(project);
1219: if (collection == null) {
1220: collection = new ArrayList();
1221: projects.put(project, collection);
1222: }
1223: collection.add(current);
1224: }
1225: final ASTParser parser = ASTParser.newParser(AST.JLS3);
1226: final IProgressMonitor subMonitor = new SubProgressMonitor(
1227: monitor, 320);
1228: try {
1229: final Set keySet = projects.keySet();
1230: subMonitor.beginTask("", keySet.size() * 100); //$NON-NLS-1$
1231: subMonitor
1232: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
1233: for (final Iterator iterator = keySet.iterator(); iterator
1234: .hasNext();) {
1235: project = (IJavaProject) iterator.next();
1236: collection = (Collection) projects.get(project);
1237: parser.setWorkingCopyOwner(fOwner);
1238: parser.setResolveBindings(true);
1239: parser.setProject(project);
1240: parser.setCompilerOptions(RefactoringASTParser
1241: .getCompilerOptions(project));
1242: final IProgressMonitor subsubMonitor = new SubProgressMonitor(
1243: subMonitor, 100);
1244: try {
1245: subsubMonitor.beginTask(
1246: "", collection.size() * 100 + 200); //$NON-NLS-1$
1247: subsubMonitor
1248: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
1249: parser
1250: .createASTs(
1251: (ICompilationUnit[]) collection
1252: .toArray(new ICompilationUnit[collection
1253: .size()]),
1254: new String[0],
1255: new ASTRequestor() {
1256:
1257: public final void acceptAST(
1258: final ICompilationUnit unit,
1259: final CompilationUnit node) {
1260: final IProgressMonitor subsubsubMonitor = new SubProgressMonitor(
1261: subsubMonitor,
1262: 100);
1263: try {
1264: subsubsubMonitor
1265: .beginTask(
1266: "", 100); //$NON-NLS-1$
1267: subsubsubMonitor
1268: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
1269: if (sourceRewrite != null)
1270: rewriteTypeOccurrences(
1271: manager,
1272: this ,
1273: sourceRewrite,
1274: unit,
1275: node,
1276: replacements,
1277: new SubProgressMonitor(
1278: subsubsubMonitor,
1279: 100));
1280: } catch (CoreException exception) {
1281: status
1282: .merge(RefactoringStatus
1283: .createFatalErrorStatus(exception
1284: .getLocalizedMessage()));
1285: } finally {
1286: subsubsubMonitor
1287: .done();
1288: }
1289: }
1290:
1291: public final void acceptBinding(
1292: final String key,
1293: final IBinding binding) {
1294: // Do nothing
1295: }
1296: }, new SubProgressMonitor(
1297: subsubMonitor, 200));
1298: } finally {
1299: subsubMonitor.done();
1300: }
1301: }
1302: try {
1303: if (subUnit != null && subNode != null
1304: && sourceRewrite != null
1305: && sourceRequestor != null)
1306: rewriteTypeOccurrences(manager,
1307: sourceRequestor, sourceRewrite,
1308: subUnit, subNode, replacements,
1309: new SubProgressMonitor(subMonitor,
1310: 20));
1311: } catch (CoreException exception) {
1312: status.merge(RefactoringStatus
1313: .createFatalErrorStatus(exception
1314: .getLocalizedMessage()));
1315: }
1316: } finally {
1317: subMonitor.done();
1318: }
1319: }
1320: } finally {
1321: monitor.done();
1322: }
1323: }
1324:
1325: /**
1326: * {@inheritDoc}
1327: */
1328: public final void setComment(final String comment) {
1329: fComment = comment;
1330: }
1331:
1332: /**
1333: * Determines whether type occurrences in instanceof's should be rewritten.
1334: *
1335: * @param rewrite
1336: * <code>true</code> to rewrite them, <code>false</code>
1337: * otherwise
1338: */
1339: public final void setInstanceOf(final boolean rewrite) {
1340: fInstanceOf = rewrite;
1341: }
1342:
1343: /**
1344: * Determines whether occurrences of the subtype should be replaced by the
1345: * supertype.
1346: *
1347: * @param replace
1348: * <code>true</code> to replace occurrences where possible,
1349: * <code>false</code> otherwise
1350: */
1351: public final void setReplace(final boolean replace) {
1352: fReplace = replace;
1353: }
1354:
1355: /**
1356: * Solves the supertype constraints to replace subtype by a supertype.
1357: *
1358: * @param subUnit
1359: * the compilation unit of the subtype, or <code>null</code>
1360: * @param subNode
1361: * the compilation unit node of the subtype, or <code>null</code>
1362: * @param subType
1363: * the java element of the subtype
1364: * @param subBinding
1365: * the type binding of the subtype to replace
1366: * @param superBinding
1367: * the type binding of the supertype to use as replacement
1368: * @param monitor
1369: * the progress monitor to use
1370: * @param status
1371: * the refactoring status
1372: * @throws JavaModelException
1373: * if an error occurs
1374: */
1375: protected final void solveSuperTypeConstraints(
1376: final ICompilationUnit subUnit,
1377: final CompilationUnit subNode, final IType subType,
1378: final ITypeBinding subBinding,
1379: final ITypeBinding super Binding,
1380: final IProgressMonitor monitor,
1381: final RefactoringStatus status) throws JavaModelException {
1382: Assert.isNotNull(subType);
1383: Assert.isNotNull(subBinding);
1384: Assert.isNotNull(super Binding);
1385: Assert.isNotNull(monitor);
1386: Assert.isNotNull(status);
1387: int level = 3;
1388: TypeEnvironment environment = new TypeEnvironment();
1389: final SuperTypeConstraintsModel model = new SuperTypeConstraintsModel(
1390: environment, environment.create(subBinding),
1391: environment.create(super Binding));
1392: final SuperTypeConstraintsCreator creator = new SuperTypeConstraintsCreator(
1393: model, fInstanceOf);
1394: try {
1395: monitor.beginTask("", 300); //$NON-NLS-1$
1396: monitor
1397: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
1398: final Map firstPass = getReferencingCompilationUnits(
1399: subType, new SubProgressMonitor(monitor, 100),
1400: status);
1401: final Map secondPass = new HashMap();
1402: IJavaProject project = null;
1403: Collection collection = null;
1404: try {
1405: final ASTParser parser = ASTParser.newParser(AST.JLS3);
1406: Object element = null;
1407: ICompilationUnit current = null;
1408: SearchResultGroup group = null;
1409: SearchMatch[] matches = null;
1410: final Map groups = new HashMap();
1411: for (final Iterator outer = firstPass.keySet()
1412: .iterator(); outer.hasNext();) {
1413: project = (IJavaProject) outer.next();
1414: if (level == 3
1415: && !JavaModelUtil.is50OrHigher(project))
1416: level = 2;
1417: collection = (Collection) firstPass.get(project);
1418: if (collection != null) {
1419: for (final Iterator inner = collection
1420: .iterator(); inner.hasNext();) {
1421: group = (SearchResultGroup) inner.next();
1422: matches = group.getSearchResults();
1423: for (int index = 0; index < matches.length; index++) {
1424: element = matches[index].getElement();
1425: if (element instanceof IMember) {
1426: current = ((IMember) element)
1427: .getCompilationUnit();
1428: if (current != null)
1429: groups.put(current, group);
1430: }
1431: }
1432: }
1433: }
1434: }
1435: Set units = null;
1436: final Set processed = new HashSet();
1437: if (subUnit != null)
1438: processed.add(subUnit);
1439: model.beginCreation();
1440: IProgressMonitor subMonitor = new SubProgressMonitor(
1441: monitor, 120);
1442: try {
1443: final Set keySet = firstPass.keySet();
1444: subMonitor.beginTask("", keySet.size() * 100); //$NON-NLS-1$
1445: subMonitor
1446: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
1447: for (final Iterator outer = keySet.iterator(); outer
1448: .hasNext();) {
1449: project = (IJavaProject) outer.next();
1450: collection = (Collection) firstPass
1451: .get(project);
1452: if (collection != null) {
1453: units = new HashSet(collection.size());
1454: for (final Iterator inner = collection
1455: .iterator(); inner.hasNext();) {
1456: group = (SearchResultGroup) inner
1457: .next();
1458: matches = group.getSearchResults();
1459: for (int index = 0; index < matches.length; index++) {
1460: element = matches[index]
1461: .getElement();
1462: if (element instanceof IMember) {
1463: current = ((IMember) element)
1464: .getCompilationUnit();
1465: if (current != null)
1466: units.add(current);
1467: }
1468: }
1469: }
1470: final List batches = new ArrayList(units);
1471: final int size = batches.size();
1472: final int iterations = ((size - 1) / SIZE_BATCH) + 1;
1473: final IProgressMonitor subsubMonitor = new SubProgressMonitor(
1474: subMonitor, 100);
1475: try {
1476: subsubMonitor.beginTask(
1477: "", iterations * 100); //$NON-NLS-1$
1478: subsubMonitor
1479: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
1480: final Map options = RefactoringASTParser
1481: .getCompilerOptions(project);
1482: for (int index = 0; index < iterations; index++) {
1483: final List iteration = batches
1484: .subList(
1485: index * SIZE_BATCH,
1486: Math
1487: .min(
1488: size,
1489: (index + 1)
1490: * SIZE_BATCH));
1491: parser.setWorkingCopyOwner(fOwner);
1492: parser.setResolveBindings(true);
1493: parser.setProject(project);
1494: parser.setCompilerOptions(options);
1495: final IProgressMonitor subsubsubMonitor = new SubProgressMonitor(
1496: subsubMonitor, 100);
1497: try {
1498: final int count = iteration
1499: .size();
1500: subsubsubMonitor.beginTask(
1501: "", count * 100); //$NON-NLS-1$
1502: subsubsubMonitor
1503: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
1504: parser
1505: .createASTs(
1506: (ICompilationUnit[]) iteration
1507: .toArray(new ICompilationUnit[count]),
1508: new String[0],
1509: new ASTRequestor() {
1510:
1511: public final void acceptAST(
1512: final ICompilationUnit unit,
1513: final CompilationUnit node) {
1514: if (!processed
1515: .contains(unit)) {
1516: performFirstPass(
1517: creator,
1518: secondPass,
1519: groups,
1520: unit,
1521: node,
1522: new SubProgressMonitor(
1523: subsubsubMonitor,
1524: 100));
1525: processed
1526: .add(unit);
1527: } else
1528: subsubsubMonitor
1529: .worked(100);
1530: }
1531:
1532: public final void acceptBinding(
1533: final String key,
1534: final IBinding binding) {
1535: // Do nothing
1536: }
1537: },
1538: new NullProgressMonitor());
1539: } finally {
1540: subsubsubMonitor.done();
1541: }
1542: }
1543: } finally {
1544: subsubMonitor.done();
1545: }
1546: }
1547: }
1548: } finally {
1549: firstPass.clear();
1550: subMonitor.done();
1551: }
1552: if (subUnit != null && subNode != null)
1553: performFirstPass(creator, secondPass, groups,
1554: subUnit, subNode, new SubProgressMonitor(
1555: subMonitor, 20));
1556: subMonitor = new SubProgressMonitor(monitor, 100);
1557: try {
1558: final Set keySet = secondPass.keySet();
1559: subMonitor.beginTask("", keySet.size() * 100); //$NON-NLS-1$
1560: subMonitor
1561: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
1562: for (final Iterator iterator = keySet.iterator(); iterator
1563: .hasNext();) {
1564: project = (IJavaProject) iterator.next();
1565: if (level == 3
1566: && !JavaModelUtil.is50OrHigher(project))
1567: level = 2;
1568: collection = (Collection) secondPass
1569: .get(project);
1570: if (collection != null) {
1571: parser.setWorkingCopyOwner(fOwner);
1572: parser.setResolveBindings(true);
1573: parser.setProject(project);
1574: parser
1575: .setCompilerOptions(RefactoringASTParser
1576: .getCompilerOptions(project));
1577: final IProgressMonitor subsubMonitor = new SubProgressMonitor(
1578: subMonitor, 100);
1579: try {
1580: subsubMonitor.beginTask(
1581: "", collection.size() * 100); //$NON-NLS-1$
1582: subsubMonitor
1583: .setTaskName(RefactoringCoreMessages.SuperTypeRefactoringProcessor_creating);
1584: parser
1585: .createASTs(
1586: (ICompilationUnit[]) collection
1587: .toArray(new ICompilationUnit[collection
1588: .size()]),
1589: new String[0],
1590: new ASTRequestor() {
1591:
1592: public final void acceptAST(
1593: final ICompilationUnit unit,
1594: final CompilationUnit node) {
1595: if (!processed
1596: .contains(unit))
1597: performSecondPass(
1598: creator,
1599: unit,
1600: node,
1601: new SubProgressMonitor(
1602: subsubMonitor,
1603: 100));
1604: else
1605: subsubMonitor
1606: .worked(100);
1607: }
1608:
1609: public final void acceptBinding(
1610: final String key,
1611: final IBinding binding) {
1612: // Do nothing
1613: }
1614: },
1615: new NullProgressMonitor());
1616: } finally {
1617: subsubMonitor.done();
1618: }
1619: }
1620: }
1621: } finally {
1622: secondPass.clear();
1623: subMonitor.done();
1624: }
1625: } finally {
1626: model.endCreation();
1627: model.setCompliance(level);
1628: }
1629: final SuperTypeConstraintsSolver solver = createContraintSolver(model);
1630: solver.solveConstraints();
1631: fTypeOccurrences = solver.getTypeOccurrences();
1632: fObsoleteCasts = solver.getObsoleteCasts();
1633: } finally {
1634: monitor.done();
1635: }
1636: }
1637: }
|