0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2006 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.Comparator;
0016: import java.util.HashMap;
0017: import java.util.HashSet;
0018: import java.util.Iterator;
0019: import java.util.List;
0020: import java.util.Map;
0021: import java.util.Set;
0022:
0023: import org.eclipse.text.edits.MalformedTreeException;
0024: import org.eclipse.text.edits.TextEdit;
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.core.filebuffers.ITextFileBuffer;
0034:
0035: import org.eclipse.core.resources.IFile;
0036:
0037: import org.eclipse.jface.text.BadLocationException;
0038: import org.eclipse.jface.text.Document;
0039: import org.eclipse.jface.text.IDocument;
0040:
0041: import org.eclipse.ltk.core.refactoring.Change;
0042: import org.eclipse.ltk.core.refactoring.GroupCategory;
0043: import org.eclipse.ltk.core.refactoring.GroupCategorySet;
0044: import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
0045: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
0046: import org.eclipse.ltk.core.refactoring.TextChange;
0047: import org.eclipse.ltk.core.refactoring.TextEditBasedChange;
0048: import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
0049: import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
0050: import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
0051: import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
0052:
0053: import org.eclipse.jdt.core.ICompilationUnit;
0054: import org.eclipse.jdt.core.IField;
0055: import org.eclipse.jdt.core.IJavaElement;
0056: import org.eclipse.jdt.core.IJavaProject;
0057: import org.eclipse.jdt.core.IMember;
0058: import org.eclipse.jdt.core.IMethod;
0059: import org.eclipse.jdt.core.IPackageFragment;
0060: import org.eclipse.jdt.core.ISourceReference;
0061: import org.eclipse.jdt.core.IType;
0062: import org.eclipse.jdt.core.ITypeParameter;
0063: import org.eclipse.jdt.core.JavaCore;
0064: import org.eclipse.jdt.core.JavaModelException;
0065: import org.eclipse.jdt.core.dom.AST;
0066: import org.eclipse.jdt.core.dom.ASTNode;
0067: import org.eclipse.jdt.core.dom.ASTParser;
0068: import org.eclipse.jdt.core.dom.ASTRequestor;
0069: import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
0070: import org.eclipse.jdt.core.dom.Annotation;
0071: import org.eclipse.jdt.core.dom.CompilationUnit;
0072: import org.eclipse.jdt.core.dom.EnumDeclaration;
0073: import org.eclipse.jdt.core.dom.FieldDeclaration;
0074: import org.eclipse.jdt.core.dom.IBinding;
0075: import org.eclipse.jdt.core.dom.IExtendedModifier;
0076: import org.eclipse.jdt.core.dom.IMethodBinding;
0077: import org.eclipse.jdt.core.dom.ITypeBinding;
0078: import org.eclipse.jdt.core.dom.IVariableBinding;
0079: import org.eclipse.jdt.core.dom.MethodDeclaration;
0080: import org.eclipse.jdt.core.dom.Modifier;
0081: import org.eclipse.jdt.core.dom.ParameterizedType;
0082: import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
0083: import org.eclipse.jdt.core.dom.Type;
0084: import org.eclipse.jdt.core.dom.TypeDeclaration;
0085: import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
0086: import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
0087: import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition;
0088: import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
0089: import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
0090: import org.eclipse.jdt.core.refactoring.descriptors.ExtractInterfaceDescriptor;
0091: import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
0092:
0093: import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
0094: import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
0095: import org.eclipse.jdt.internal.corext.dom.Bindings;
0096: import org.eclipse.jdt.internal.corext.dom.ModifierRewrite;
0097: import org.eclipse.jdt.internal.corext.dom.NodeFinder;
0098: import org.eclipse.jdt.internal.corext.refactoring.Checks;
0099: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
0100: import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
0101: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
0102: import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
0103: import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
0104: import org.eclipse.jdt.internal.corext.refactoring.changes.CreateCompilationUnitChange;
0105: import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
0106: import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring;
0107: import org.eclipse.jdt.internal.corext.refactoring.reorg.ASTNodeDeleteUtil;
0108: import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsModel;
0109: import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsSolver;
0110: import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor;
0111: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange;
0112: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
0113: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ISourceConstraintVariable;
0114: import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeConstraintVariable;
0115: import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
0116: import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringFileBuffers;
0117: import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
0118: import org.eclipse.jdt.internal.corext.refactoring.util.TextEditBasedChangeManager;
0119: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
0120: import org.eclipse.jdt.internal.corext.util.JdtFlags;
0121: import org.eclipse.jdt.internal.corext.util.Messages;
0122: import org.eclipse.jdt.internal.corext.util.Strings;
0123:
0124: import org.eclipse.jdt.ui.CodeGeneration;
0125: import org.eclipse.jdt.ui.JavaElementLabels;
0126:
0127: import org.eclipse.jdt.internal.ui.JavaPlugin;
0128: import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
0129:
0130: /**
0131: * Refactoring processor to extract interfaces.
0132: */
0133: public final class ExtractInterfaceProcessor extends
0134: SuperTypeRefactoringProcessor {
0135:
0136: private static final String ATTRIBUTE_ABSTRACT = "abstract"; //$NON-NLS-1$
0137:
0138: private static final String ATTRIBUTE_COMMENTS = "comments"; //$NON-NLS-1$
0139:
0140: private static final String ATTRIBUTE_PUBLIC = "public"; //$NON-NLS-1$
0141:
0142: /** The identifier of this processor */
0143: public static final String IDENTIFIER = "org.eclipse.jdt.ui.extractInterfaceProcessor"; //$NON-NLS-1$
0144:
0145: /** The extract interface group category set */
0146: private static final GroupCategorySet SET_EXTRACT_INTERFACE = new GroupCategorySet(
0147: new GroupCategory(
0148: "org.eclipse.jdt.internal.corext.extractInterface", //$NON-NLS-1$
0149: RefactoringCoreMessages.ExtractInterfaceProcessor_category_name,
0150: RefactoringCoreMessages.ExtractInterfaceProcessor_category_description));
0151:
0152: /**
0153: * Is the specified member extractable from the type?
0154: *
0155: * @param member
0156: * the member to test
0157: * @return <code>true</code> if the member is extractable,
0158: * <code>false</code> otherwise
0159: * @throws JavaModelException
0160: * if an error occurs
0161: */
0162: protected static boolean isExtractableMember(final IMember member)
0163: throws JavaModelException {
0164: Assert.isNotNull(member);
0165: switch (member.getElementType()) {
0166: case IJavaElement.METHOD:
0167: return JdtFlags.isPublic(member)
0168: && !JdtFlags.isStatic(member)
0169: && !((IMethod) member).isConstructor();
0170: case IJavaElement.FIELD:
0171: return JdtFlags.isPublic(member)
0172: && JdtFlags.isStatic(member)
0173: && JdtFlags.isFinal(member)
0174: && !JdtFlags.isEnum(member);
0175: default:
0176: return false;
0177: }
0178: }
0179:
0180: /** Should extracted methods be declared as abstract? */
0181: private boolean fAbstract = true;
0182:
0183: /** The text edit based change manager */
0184: private TextEditBasedChangeManager fChangeManager = null;
0185:
0186: /** Should comments be generated? */
0187: private boolean fComments = true;
0188:
0189: /** The members to extract */
0190: private IMember[] fMembers = null;
0191:
0192: /** Should extracted methods be declared as public? */
0193: private boolean fPublic = true;
0194:
0195: /** The subtype where to extract the supertype */
0196: private IType fSubType;
0197:
0198: /** The supertype name */
0199: private String fSuperName;
0200:
0201: /** The source of the new supertype */
0202: private String fSuperSource = null;
0203:
0204: /**
0205: * Creates a new extract interface processor.
0206: *
0207: * @param type
0208: * the type where to extract the supertype, or <code>null</code>
0209: * if invoked by scripting
0210: * @param settings
0211: * the code generation settings, or <code>null</code> if
0212: * invoked by scripting
0213: */
0214: public ExtractInterfaceProcessor(final IType type,
0215: final CodeGenerationSettings settings) {
0216: super (settings);
0217: fSubType = type;
0218: if (fSubType != null)
0219: fSuperName = fSubType.getElementName();
0220: }
0221:
0222: /*
0223: * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#checkFinalConditions(org.eclipse.core.runtime.IProgressMonitor,org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext)
0224: */
0225: public final RefactoringStatus checkFinalConditions(
0226: final IProgressMonitor monitor,
0227: final CheckConditionsContext context) throws CoreException,
0228: OperationCanceledException {
0229: Assert.isNotNull(monitor);
0230: Assert.isNotNull(context);
0231: final RefactoringStatus status = new RefactoringStatus();
0232: fChangeManager = new TextEditBasedChangeManager();
0233: try {
0234: monitor.beginTask("", 1); //$NON-NLS-1$
0235: monitor
0236: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_checking);
0237: status.merge(Checks.checkIfCuBroken(fSubType));
0238: if (!status.hasError()) {
0239: if (fSubType.isBinary() || fSubType.isReadOnly()
0240: || !fSubType.exists())
0241: status
0242: .merge(RefactoringStatus
0243: .createFatalErrorStatus(
0244: RefactoringCoreMessages.ExtractInterfaceProcessor_no_binary,
0245: JavaStatusContext
0246: .create(fSubType)));
0247: else if (fSubType.isAnonymous())
0248: status
0249: .merge(RefactoringStatus
0250: .createFatalErrorStatus(
0251: RefactoringCoreMessages.ExtractInterfaceProcessor_no_anonymous,
0252: JavaStatusContext
0253: .create(fSubType)));
0254: else if (fSubType.isAnnotation())
0255: status
0256: .merge(RefactoringStatus
0257: .createFatalErrorStatus(
0258: RefactoringCoreMessages.ExtractInterfaceProcessor_no_annotation,
0259: JavaStatusContext
0260: .create(fSubType)));
0261: else {
0262: status.merge(checkSuperType());
0263: if (!status.hasFatalError()) {
0264: if (!status.hasFatalError()) {
0265: fChangeManager = createChangeManager(
0266: new SubProgressMonitor(monitor, 1),
0267: status);
0268: if (!status.hasFatalError()) {
0269: final RefactoringStatus validation = Checks
0270: .validateModifiesFiles(
0271: ResourceUtil
0272: .getFiles(fChangeManager
0273: .getAllCompilationUnits()),
0274: getRefactoring()
0275: .getValidationContext());
0276: if (!validation.isOK())
0277: return validation;
0278: }
0279: }
0280: }
0281: }
0282: }
0283: } finally {
0284: monitor.done();
0285: }
0286: return status;
0287: }
0288:
0289: /*
0290: * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
0291: */
0292: public final RefactoringStatus checkInitialConditions(
0293: final IProgressMonitor monitor) throws CoreException,
0294: OperationCanceledException {
0295: Assert.isNotNull(monitor);
0296: final RefactoringStatus status = new RefactoringStatus();
0297: try {
0298: monitor.beginTask("", 1); //$NON-NLS-1$
0299: monitor
0300: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_checking);
0301: status.merge(Checks.checkIfCuBroken(fSubType));
0302: monitor.worked(1);
0303: } finally {
0304: monitor.done();
0305: }
0306: return status;
0307: }
0308:
0309: /**
0310: * Checks whether the supertype clashes with existing types.
0311: *
0312: * @return the status of the condition checking
0313: * @throws JavaModelException
0314: * if an error occurs
0315: */
0316: protected final RefactoringStatus checkSuperType()
0317: throws JavaModelException {
0318: final IPackageFragment fragment = fSubType.getPackageFragment();
0319: final IType type = Checks.findTypeInPackage(fragment,
0320: fSuperName);
0321: if (type != null && type.exists()) {
0322: if (fragment.isDefaultPackage())
0323: return RefactoringStatus
0324: .createFatalErrorStatus(Messages
0325: .format(
0326: RefactoringCoreMessages.ExtractInterfaceProcessor_existing_default_type,
0327: new String[] { fSuperName }));
0328: else
0329: return RefactoringStatus
0330: .createFatalErrorStatus(Messages
0331: .format(
0332: RefactoringCoreMessages.ExtractInterfaceProcessor_existing_type,
0333: new String[] {
0334: fSuperName,
0335: fragment
0336: .getElementName() }));
0337: }
0338: return new RefactoringStatus();
0339: }
0340:
0341: /**
0342: * Checks whether the type name is valid.
0343: *
0344: * @param name
0345: * the name to check
0346: * @return the status of the condition checking
0347: */
0348: public final RefactoringStatus checkTypeName(final String name) {
0349: Assert.isNotNull(name);
0350: try {
0351: final RefactoringStatus result = Checks.checkTypeName(name,
0352: fSubType);
0353: if (result.hasFatalError())
0354: return result;
0355: final String unitName = JavaModelUtil.getRenamedCUName(
0356: fSubType.getCompilationUnit(), name);
0357: result.merge(Checks.checkCompilationUnitName(unitName,
0358: fSubType));
0359: if (result.hasFatalError())
0360: return result;
0361: final IPackageFragment fragment = fSubType
0362: .getPackageFragment();
0363: if (fragment.getCompilationUnit(unitName).exists()) {
0364: result
0365: .addFatalError(Messages
0366: .format(
0367: RefactoringCoreMessages.ExtractInterfaceProcessor_existing_compilation_unit,
0368: new String[] {
0369: unitName,
0370: fragment
0371: .getElementName() }));
0372: return result;
0373: }
0374: result.merge(checkSuperType());
0375: return result;
0376: } catch (JavaModelException exception) {
0377: return RefactoringStatus
0378: .createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error);
0379: }
0380: }
0381:
0382: /*
0383: * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#createChange(org.eclipse.core.runtime.IProgressMonitor)
0384: */
0385: public final Change createChange(final IProgressMonitor monitor)
0386: throws CoreException, OperationCanceledException {
0387: Assert.isNotNull(monitor);
0388: try {
0389: monitor.beginTask("", 1); //$NON-NLS-1$
0390: monitor
0391: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
0392: final Map arguments = new HashMap();
0393: String project = null;
0394: final IJavaProject javaProject = fSubType.getJavaProject();
0395: if (javaProject != null)
0396: project = javaProject.getElementName();
0397: int flags = JavaRefactoringDescriptor.JAR_MIGRATION
0398: | JavaRefactoringDescriptor.JAR_REFACTORING
0399: | RefactoringDescriptor.STRUCTURAL_CHANGE
0400: | RefactoringDescriptor.MULTI_CHANGE;
0401: try {
0402: if (fSubType.isLocal() || fSubType.isAnonymous())
0403: flags |= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
0404: } catch (JavaModelException exception) {
0405: JavaPlugin.log(exception);
0406: }
0407: final IPackageFragment fragment = fSubType
0408: .getPackageFragment();
0409: final ICompilationUnit cu = fragment
0410: .getCompilationUnit(JavaModelUtil.getRenamedCUName(
0411: fSubType.getCompilationUnit(), fSuperName));
0412: final IType type = cu.getType(fSuperName);
0413: final String description = Messages
0414: .format(
0415: RefactoringCoreMessages.ExtractInterfaceProcessor_description_descriptor_short,
0416: fSuperName);
0417: final String header = Messages
0418: .format(
0419: RefactoringCoreMessages.ExtractInterfaceProcessor_descriptor_description,
0420: new String[] {
0421: JavaElementLabels
0422: .getElementLabel(
0423: type,
0424: JavaElementLabels.ALL_FULLY_QUALIFIED),
0425: JavaElementLabels
0426: .getElementLabel(
0427: fSubType,
0428: JavaElementLabels.ALL_FULLY_QUALIFIED) });
0429: final JDTRefactoringDescriptorComment comment = new JDTRefactoringDescriptorComment(
0430: project, this , header);
0431: comment
0432: .addSetting(Messages
0433: .format(
0434: RefactoringCoreMessages.ExtractInterfaceProcessor_refactored_element_pattern,
0435: JavaElementLabels
0436: .getElementLabel(
0437: type,
0438: JavaElementLabels.ALL_FULLY_QUALIFIED)));
0439: final String[] settings = new String[fMembers.length];
0440: for (int index = 0; index < settings.length; index++)
0441: settings[index] = JavaElementLabels.getElementLabel(
0442: fMembers[index],
0443: JavaElementLabels.ALL_FULLY_QUALIFIED);
0444: comment
0445: .addSetting(JDTRefactoringDescriptorComment
0446: .createCompositeSetting(
0447: RefactoringCoreMessages.ExtractInterfaceProcessor_extracted_members_pattern,
0448: settings));
0449: addSuperTypeSettings(comment, true);
0450: final ExtractInterfaceDescriptor descriptor = new ExtractInterfaceDescriptor(
0451: project, description, comment.asString(),
0452: arguments, flags);
0453: arguments.put(
0454: JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT,
0455: JavaRefactoringDescriptorUtil.elementToHandle(
0456: project, fSubType));
0457: arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME,
0458: fSuperName);
0459: for (int index = 0; index < fMembers.length; index++)
0460: arguments.put(
0461: JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT
0462: + (index + 1),
0463: JavaRefactoringDescriptorUtil.elementToHandle(
0464: project, fMembers[index]));
0465: arguments.put(ATTRIBUTE_ABSTRACT, Boolean
0466: .valueOf(fAbstract).toString());
0467: arguments.put(ATTRIBUTE_COMMENTS, Boolean
0468: .valueOf(fComments).toString());
0469: arguments.put(ATTRIBUTE_PUBLIC, Boolean.valueOf(fPublic)
0470: .toString());
0471: arguments.put(ATTRIBUTE_REPLACE, Boolean.valueOf(fReplace)
0472: .toString());
0473: arguments.put(ATTRIBUTE_INSTANCEOF, Boolean.valueOf(
0474: fInstanceOf).toString());
0475: final DynamicValidationRefactoringChange change = new DynamicValidationRefactoringChange(
0476: descriptor,
0477: RefactoringCoreMessages.ExtractInterfaceRefactoring_name,
0478: fChangeManager.getAllChanges());
0479: final IFile file = ResourceUtil.getFile(fSubType
0480: .getCompilationUnit());
0481: if (fSuperSource != null && fSuperSource.length() > 0)
0482: change.add(new CreateCompilationUnitChange(fSubType
0483: .getPackageFragment().getCompilationUnit(
0484: JavaModelUtil.getRenamedCUName(fSubType
0485: .getCompilationUnit(),
0486: fSuperName)), fSuperSource,
0487: file.getCharset(false)));
0488: monitor.worked(1);
0489: return change;
0490: } finally {
0491: monitor.done();
0492: }
0493: }
0494:
0495: /**
0496: * Creates the text change manager for this processor.
0497: *
0498: * @param monitor
0499: * the progress monitor to display progress
0500: * @param status
0501: * the refactoring status
0502: * @return the created text change manager
0503: * @throws JavaModelException
0504: * if the method declaration could not be found
0505: * @throws CoreException
0506: * if the changes could not be generated
0507: */
0508: protected final TextEditBasedChangeManager createChangeManager(
0509: final IProgressMonitor monitor,
0510: final RefactoringStatus status) throws JavaModelException,
0511: CoreException {
0512: Assert.isNotNull(status);
0513: Assert.isNotNull(monitor);
0514: try {
0515: monitor.beginTask("", 300); //$NON-NLS-1$
0516: monitor
0517: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
0518: resetEnvironment();
0519: final TextEditBasedChangeManager manager = new TextEditBasedChangeManager();
0520: final CompilationUnitRewrite sourceRewrite = new CompilationUnitRewrite(
0521: fSubType.getCompilationUnit());
0522: final AbstractTypeDeclaration declaration = ASTNodeSearchUtil
0523: .getAbstractTypeDeclarationNode(fSubType,
0524: sourceRewrite.getRoot());
0525: if (declaration != null) {
0526: createTypeSignature(sourceRewrite, declaration, status,
0527: new SubProgressMonitor(monitor, 20));
0528: final IField[] fields = getExtractedFields(fSubType
0529: .getCompilationUnit());
0530: if (fields.length > 0)
0531: ASTNodeDeleteUtil
0532: .markAsDeleted(
0533: fields,
0534: sourceRewrite,
0535: sourceRewrite
0536: .createCategorizedGroupDescription(
0537: RefactoringCoreMessages.ExtractInterfaceProcessor_remove_field_label,
0538: SET_EXTRACT_INTERFACE));
0539: if (fSubType.isInterface()) {
0540: final IMethod[] methods = getExtractedMethods(fSubType
0541: .getCompilationUnit());
0542: if (methods.length > 0)
0543: ASTNodeDeleteUtil
0544: .markAsDeleted(
0545: methods,
0546: sourceRewrite,
0547: sourceRewrite
0548: .createCategorizedGroupDescription(
0549: RefactoringCoreMessages.ExtractInterfaceProcessor_remove_method_label,
0550: SET_EXTRACT_INTERFACE));
0551: }
0552: final String name = JavaModelUtil.getRenamedCUName(
0553: fSubType.getCompilationUnit(), fSuperName);
0554: final ICompilationUnit original = fSubType
0555: .getPackageFragment().getCompilationUnit(name);
0556: final ICompilationUnit copy = getSharedWorkingCopy(
0557: original.getPrimary(), new SubProgressMonitor(
0558: monitor, 20));
0559: fSuperSource = createTypeSource(copy, fSubType,
0560: fSuperName, sourceRewrite, declaration, status,
0561: new SubProgressMonitor(monitor, 40));
0562: if (fSuperSource != null) {
0563: copy.getBuffer().setContents(fSuperSource);
0564: JavaModelUtil.reconcile(copy);
0565: }
0566: final Set replacements = new HashSet();
0567: if (fReplace)
0568: rewriteTypeOccurrences(manager, sourceRewrite,
0569: copy, replacements, status,
0570: new SubProgressMonitor(monitor, 220));
0571: createMethodComments(sourceRewrite, replacements);
0572: manager.manage(fSubType.getCompilationUnit(),
0573: sourceRewrite.createChange());
0574: }
0575: return manager;
0576: } finally {
0577: monitor.done();
0578: }
0579: }
0580:
0581: /*
0582: * @see org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor#createContraintSolver(org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsModel)
0583: */
0584: protected final SuperTypeConstraintsSolver createContraintSolver(
0585: final SuperTypeConstraintsModel model) {
0586: return new ExtractInterfaceConstraintsSolver(model, fSuperName);
0587: }
0588:
0589: /**
0590: * Creates a target field declaration.
0591: *
0592: * @param sourceRewrite
0593: * the source compilation unit rewrite
0594: * @param targetRewrite
0595: * the target rewrite
0596: * @param targetDeclaration
0597: * the target type declaration
0598: * @param fragment
0599: * the source variable declaration fragment
0600: * @throws CoreException
0601: * if a buffer could not be retrieved
0602: */
0603: protected final void createFieldDeclaration(
0604: final CompilationUnitRewrite sourceRewrite,
0605: final ASTRewrite targetRewrite,
0606: final AbstractTypeDeclaration targetDeclaration,
0607: final VariableDeclarationFragment fragment)
0608: throws CoreException {
0609: Assert.isNotNull(targetDeclaration);
0610: Assert.isNotNull(sourceRewrite);
0611: Assert.isNotNull(targetRewrite);
0612: Assert.isNotNull(fragment);
0613: final FieldDeclaration field = (FieldDeclaration) fragment
0614: .getParent();
0615: ImportRewriteUtil.collectImports(fSubType.getJavaProject(),
0616: field, fTypeBindings, fStaticBindings, false);
0617: final ASTRewrite rewrite = ASTRewrite.create(field.getAST());
0618: final ITrackedNodePosition position = rewrite.track(field);
0619: final ListRewrite rewriter = rewrite.getListRewrite(field,
0620: FieldDeclaration.FRAGMENTS_PROPERTY);
0621: VariableDeclarationFragment current = null;
0622: for (final Iterator iterator = field.fragments().iterator(); iterator
0623: .hasNext();) {
0624: current = (VariableDeclarationFragment) iterator.next();
0625: if (!current.getName().getIdentifier().equals(
0626: fragment.getName().getIdentifier()))
0627: rewriter.remove(current, null);
0628: }
0629: final ICompilationUnit unit = sourceRewrite.getCu();
0630: final ITextFileBuffer buffer = RefactoringFileBuffers
0631: .acquire(unit);
0632: try {
0633: final IDocument document = new Document(buffer
0634: .getDocument().get());
0635: try {
0636: rewrite.rewriteAST(document,
0637: unit.getJavaProject().getOptions(true)).apply(
0638: document, TextEdit.UPDATE_REGIONS);
0639: targetRewrite
0640: .getListRewrite(
0641: targetDeclaration,
0642: targetDeclaration
0643: .getBodyDeclarationsProperty())
0644: .insertFirst(
0645: targetRewrite
0646: .createStringPlaceholder(
0647: normalizeText(document
0648: .get(
0649: position
0650: .getStartPosition(),
0651: position
0652: .getLength())),
0653: ASTNode.FIELD_DECLARATION),
0654: null);
0655: } catch (MalformedTreeException exception) {
0656: JavaPlugin.log(exception);
0657: } catch (BadLocationException exception) {
0658: JavaPlugin.log(exception);
0659: }
0660: } finally {
0661: RefactoringFileBuffers.release(unit);
0662: }
0663: }
0664:
0665: /**
0666: * {@inheritDoc}
0667: */
0668: protected final void createMemberDeclarations(
0669: final CompilationUnitRewrite sourceRewrite,
0670: final ASTRewrite targetRewrite,
0671: final AbstractTypeDeclaration targetDeclaration)
0672: throws CoreException {
0673: Assert.isNotNull(sourceRewrite);
0674: Assert.isNotNull(targetRewrite);
0675: Assert.isNotNull(targetDeclaration);
0676: Arrays.sort(fMembers, new Comparator() {
0677:
0678: public final int compare(final Object first,
0679: final Object second) {
0680: Assert.isNotNull(first);
0681: Assert.isNotNull(second);
0682: final ISourceReference predecessor = (ISourceReference) first;
0683: final ISourceReference successor = (ISourceReference) second;
0684: try {
0685: return predecessor.getSourceRange().getOffset()
0686: - successor.getSourceRange().getOffset();
0687: } catch (JavaModelException exception) {
0688: return first.hashCode() - second.hashCode();
0689: }
0690: }
0691: });
0692: fTypeBindings.clear();
0693: fStaticBindings.clear();
0694: if (fMembers.length > 0) {
0695: IMember member = null;
0696: for (int index = fMembers.length - 1; index >= 0; index--) {
0697: member = fMembers[index];
0698: if (member instanceof IField) {
0699: createFieldDeclaration(sourceRewrite,
0700: targetRewrite, targetDeclaration,
0701: ASTNodeSearchUtil
0702: .getFieldDeclarationFragmentNode(
0703: (IField) member,
0704: sourceRewrite.getRoot()));
0705: } else if (member instanceof IMethod) {
0706: createMethodDeclaration(sourceRewrite,
0707: targetRewrite, targetDeclaration,
0708: ASTNodeSearchUtil.getMethodDeclarationNode(
0709: (IMethod) member, sourceRewrite
0710: .getRoot()));
0711: }
0712: }
0713: }
0714: }
0715:
0716: /**
0717: * Creates the method comment for the specified declaration.
0718: *
0719: * @param sourceRewrite
0720: * the compilation unit rewrite
0721: * @param declaration
0722: * the method declaration
0723: * @param replacements
0724: * the set of variable binding keys of formal parameters which
0725: * must be replaced
0726: * @param javadoc
0727: * <code>true</code> if javadoc comments are processed,
0728: * <code>false</code> otherwise
0729: * @throws CoreException
0730: * if an error occurs
0731: */
0732: protected final void createMethodComment(
0733: final CompilationUnitRewrite sourceRewrite,
0734: final MethodDeclaration declaration,
0735: final Set replacements, final boolean javadoc)
0736: throws CoreException {
0737: Assert.isNotNull(sourceRewrite);
0738: Assert.isNotNull(declaration);
0739: Assert.isNotNull(replacements);
0740: final IMethodBinding binding = declaration.resolveBinding();
0741: if (binding != null) {
0742: IVariableBinding variable = null;
0743: SingleVariableDeclaration argument = null;
0744: final IPackageFragment fragment = fSubType
0745: .getPackageFragment();
0746: final String string = fragment.isDefaultPackage() ? fSuperName
0747: : fragment.getElementName() + "." + fSuperName; //$NON-NLS-1$
0748: final ITypeBinding[] bindings = binding.getParameterTypes();
0749: final String[] names = new String[bindings.length];
0750: for (int offset = 0; offset < names.length; offset++) {
0751: argument = (SingleVariableDeclaration) declaration
0752: .parameters().get(offset);
0753: variable = argument.resolveBinding();
0754: if (variable != null) {
0755: if (replacements.contains(variable.getKey()))
0756: names[offset] = string;
0757: else {
0758: if (binding.isVarargs()
0759: && bindings[offset].isArray()
0760: && offset == names.length - 1)
0761: names[offset] = Bindings
0762: .getFullyQualifiedName(bindings[offset]
0763: .getElementType());
0764: else
0765: names[offset] = Bindings
0766: .getFullyQualifiedName(bindings[offset]);
0767: }
0768: }
0769: }
0770: final String comment = CodeGeneration.getMethodComment(
0771: fSubType.getCompilationUnit(), fSubType
0772: .getElementName(), declaration, false,
0773: binding.getName(), string, names, StubUtility
0774: .getLineDelimiterUsed(fSubType
0775: .getJavaProject()));
0776: if (comment != null) {
0777: final ASTRewrite rewrite = sourceRewrite
0778: .getASTRewrite();
0779: if (declaration.getJavadoc() != null) {
0780: rewrite
0781: .replace(
0782: declaration.getJavadoc(),
0783: rewrite.createStringPlaceholder(
0784: comment, ASTNode.JAVADOC),
0785: sourceRewrite
0786: .createCategorizedGroupDescription(
0787: RefactoringCoreMessages.ExtractInterfaceProcessor_rewrite_comment,
0788: SET_EXTRACT_INTERFACE));
0789: } else if (javadoc) {
0790: rewrite
0791: .set(
0792: declaration,
0793: MethodDeclaration.JAVADOC_PROPERTY,
0794: rewrite.createStringPlaceholder(
0795: comment, ASTNode.JAVADOC),
0796: sourceRewrite
0797: .createCategorizedGroupDescription(
0798: RefactoringCoreMessages.ExtractInterfaceProcessor_add_comment,
0799: SET_EXTRACT_INTERFACE));
0800: }
0801: }
0802: }
0803: }
0804:
0805: /**
0806: * Creates the method annotations and comments of the extracted methods in
0807: * the source type.
0808: *
0809: * @param sourceRewrite
0810: * the source compilation unit rewrite
0811: * @param replacements
0812: * the set of variable binding keys of formal parameters which
0813: * must be replaced
0814: * @throws CoreException
0815: * if an error occurs
0816: */
0817: protected final void createMethodComments(
0818: final CompilationUnitRewrite sourceRewrite,
0819: final Set replacements) throws CoreException {
0820: Assert.isNotNull(sourceRewrite);
0821: Assert.isNotNull(replacements);
0822: if (fComments && fMembers.length > 0) {
0823: final IJavaProject project = fSubType.getJavaProject();
0824: final boolean javadoc = project.getOption(
0825: JavaCore.COMPILER_DOC_COMMENT_SUPPORT, true)
0826: .equals(JavaCore.ENABLED);
0827: IMember member = null;
0828: for (int index = 0; index < fMembers.length; index++) {
0829: member = fMembers[index];
0830: if (member instanceof IMethod)
0831: createMethodComment(sourceRewrite,
0832: ASTNodeSearchUtil.getMethodDeclarationNode(
0833: (IMethod) member, sourceRewrite
0834: .getRoot()), replacements,
0835: javadoc);
0836: }
0837: }
0838: }
0839:
0840: /**
0841: * Creates a target method declaration.
0842: *
0843: * @param sourceRewrite
0844: * the source compilation unit rewrite
0845: * @param targetRewrite
0846: * the target rewrite
0847: * @param targetDeclaration
0848: * the target type declaration
0849: * @param declaration
0850: * the source method declaration
0851: * @throws CoreException
0852: * if a buffer could not be retrieved
0853: */
0854: protected final void createMethodDeclaration(
0855: final CompilationUnitRewrite sourceRewrite,
0856: final ASTRewrite targetRewrite,
0857: final AbstractTypeDeclaration targetDeclaration,
0858: final MethodDeclaration declaration) throws CoreException {
0859: Assert.isNotNull(targetDeclaration);
0860: Assert.isNotNull(sourceRewrite);
0861: Assert.isNotNull(targetRewrite);
0862: Assert.isNotNull(declaration);
0863: ImportRewriteUtil.collectImports(fSubType.getJavaProject(),
0864: declaration, fTypeBindings, fStaticBindings, true);
0865: final ASTRewrite rewrite = ASTRewrite.create(declaration
0866: .getAST());
0867: final ITrackedNodePosition position = rewrite
0868: .track(declaration);
0869: if (declaration.getBody() != null)
0870: rewrite.remove(declaration.getBody(), null);
0871: final ListRewrite list = rewrite.getListRewrite(declaration,
0872: declaration.getModifiersProperty());
0873: boolean publicFound = false;
0874: boolean abstractFound = false;
0875: ITypeBinding binding = null;
0876: Modifier modifier = null;
0877: Annotation annotation = null;
0878: IExtendedModifier extended = null;
0879: for (final Iterator iterator = declaration.modifiers()
0880: .iterator(); iterator.hasNext();) {
0881: extended = (IExtendedModifier) iterator.next();
0882: if (!extended.isAnnotation()) {
0883: modifier = (Modifier) extended;
0884: if (fPublic
0885: && modifier
0886: .getKeyword()
0887: .equals(
0888: Modifier.ModifierKeyword.PUBLIC_KEYWORD)) {
0889: publicFound = true;
0890: continue;
0891: }
0892: if (fAbstract
0893: && modifier
0894: .getKeyword()
0895: .equals(
0896: Modifier.ModifierKeyword.ABSTRACT_KEYWORD)) {
0897: abstractFound = true;
0898: continue;
0899: }
0900: list.remove(modifier, null);
0901: } else if (extended.isAnnotation()) {
0902: annotation = (Annotation) extended;
0903: binding = annotation.resolveTypeBinding();
0904: if (binding.getQualifiedName().equals(
0905: "java.lang.Override")) //$NON-NLS-1$
0906: list.remove(annotation, null);
0907: }
0908: }
0909: final ModifierRewrite rewriter = ModifierRewrite.create(
0910: rewrite, declaration);
0911: if (fPublic && !publicFound)
0912: rewriter.setVisibility(Modifier.PUBLIC, null);
0913: if (fAbstract && !abstractFound)
0914: rewriter.setModifiers(Modifier.ABSTRACT, 0, null);
0915: final ICompilationUnit unit = sourceRewrite.getCu();
0916: final ITextFileBuffer buffer = RefactoringFileBuffers
0917: .acquire(unit);
0918: try {
0919: final IDocument document = new Document(buffer
0920: .getDocument().get());
0921: try {
0922: rewrite.rewriteAST(document,
0923: unit.getJavaProject().getOptions(true)).apply(
0924: document, TextEdit.UPDATE_REGIONS);
0925: targetRewrite
0926: .getListRewrite(
0927: targetDeclaration,
0928: targetDeclaration
0929: .getBodyDeclarationsProperty())
0930: .insertFirst(
0931: targetRewrite
0932: .createStringPlaceholder(
0933: normalizeText(document
0934: .get(
0935: position
0936: .getStartPosition(),
0937: position
0938: .getLength())),
0939: ASTNode.METHOD_DECLARATION),
0940: null);
0941: } catch (MalformedTreeException exception) {
0942: JavaPlugin.log(exception);
0943: } catch (BadLocationException exception) {
0944: JavaPlugin.log(exception);
0945: }
0946: } finally {
0947: RefactoringFileBuffers.release(unit);
0948: }
0949: }
0950:
0951: /**
0952: * Creates the new signature of the source type.
0953: *
0954: * @param rewrite
0955: * the source compilation unit rewrite
0956: * @param declaration
0957: * the type declaration
0958: * @param status
0959: * the refactoring status
0960: * @param monitor
0961: * the progress monitor to use
0962: * @throws JavaModelException
0963: * if the type parameters cannot be retrieved
0964: */
0965: protected final void createTypeSignature(
0966: final CompilationUnitRewrite rewrite,
0967: final AbstractTypeDeclaration declaration,
0968: final RefactoringStatus status,
0969: final IProgressMonitor monitor) throws JavaModelException {
0970: Assert.isNotNull(rewrite);
0971: Assert.isNotNull(declaration);
0972: Assert.isNotNull(status);
0973: Assert.isNotNull(monitor);
0974: try {
0975: monitor.beginTask("", 1); //$NON-NLS-1$
0976: monitor
0977: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
0978: final AST ast = declaration.getAST();
0979: final ITypeParameter[] parameters = fSubType
0980: .getTypeParameters();
0981: Type type = ast
0982: .newSimpleType(ast.newSimpleName(fSuperName));
0983: if (parameters.length > 0) {
0984: final ParameterizedType parameterized = ast
0985: .newParameterizedType(type);
0986: for (int index = 0; index < parameters.length; index++)
0987: parameterized.typeArguments().add(
0988: ast.newSimpleType(ast
0989: .newSimpleName(parameters[index]
0990: .getElementName())));
0991: type = parameterized;
0992: }
0993: final ASTRewrite rewriter = rewrite.getASTRewrite();
0994: if (declaration instanceof TypeDeclaration)
0995: rewriter
0996: .getListRewrite(
0997: declaration,
0998: TypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY)
0999: .insertLast(
1000: type,
1001: rewrite
1002: .createCategorizedGroupDescription(
1003: RefactoringCoreMessages.ExtractInterfaceProcessor_add_super _interface,
1004: SET_EXTRACT_INTERFACE));
1005: else if (declaration instanceof EnumDeclaration)
1006: rewriter
1007: .getListRewrite(
1008: declaration,
1009: EnumDeclaration.SUPER_INTERFACE_TYPES_PROPERTY)
1010: .insertLast(
1011: type,
1012: rewrite
1013: .createCategorizedGroupDescription(
1014: RefactoringCoreMessages.ExtractInterfaceProcessor_add_super _interface,
1015: SET_EXTRACT_INTERFACE));
1016: monitor.worked(1);
1017: } finally {
1018: monitor.done();
1019: }
1020: }
1021:
1022: /**
1023: * Should extracted methods be declared as abstract?
1024: *
1025: * @return <code>true</code> if the should be declared as abstract,
1026: * <code>false</code> otherwise
1027: */
1028: public final boolean getAbstract() {
1029: return fAbstract;
1030: }
1031:
1032: /*
1033: * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getElements()
1034: */
1035: public final Object[] getElements() {
1036: return new Object[] { fSubType };
1037: }
1038:
1039: /**
1040: * Returns the list of extractable members from the type.
1041: *
1042: * @return the list of extractable members
1043: * @throws JavaModelException
1044: * if an error occurs
1045: */
1046: public final IMember[] getExtractableMembers()
1047: throws JavaModelException {
1048: final List list = new ArrayList();
1049: IJavaElement[] children = fSubType.getChildren();
1050: for (int index = 0; index < children.length; index++) {
1051: if (children[index] instanceof IMember
1052: && isExtractableMember((IMember) children[index]))
1053: list.add(children[index]);
1054: }
1055: final IMember[] members = new IMember[list.size()];
1056: list.toArray(members);
1057: return members;
1058: }
1059:
1060: /**
1061: * Returns the extracted fields from the compilation unit.
1062: *
1063: * @param unit
1064: * the compilation unit
1065: * @return the extracted fields
1066: */
1067: protected final IField[] getExtractedFields(
1068: final ICompilationUnit unit) {
1069: Assert.isNotNull(unit);
1070: final List list = new ArrayList();
1071: for (int index = 0; index < fMembers.length; index++) {
1072: if (fMembers[index] instanceof IField) {
1073: final IJavaElement element = JavaModelUtil
1074: .findInCompilationUnit(unit, fMembers[index]);
1075: if (element instanceof IField)
1076: list.add(element);
1077: }
1078: }
1079: final IField[] fields = new IField[list.size()];
1080: list.toArray(fields);
1081: return fields;
1082: }
1083:
1084: /**
1085: * Returns the extracted methods from the compilation unit.
1086: *
1087: * @param unit
1088: * the compilation unit
1089: * @return the extracted methods
1090: */
1091: protected final IMethod[] getExtractedMethods(
1092: final ICompilationUnit unit) {
1093: Assert.isNotNull(unit);
1094: final List list = new ArrayList();
1095: for (int index = 0; index < fMembers.length; index++) {
1096: if (fMembers[index] instanceof IMethod) {
1097: final IJavaElement element = JavaModelUtil
1098: .findInCompilationUnit(unit, fMembers[index]);
1099: if (element instanceof IMethod)
1100: list.add(element);
1101: }
1102: }
1103: final IMethod[] methods = new IMethod[list.size()];
1104: list.toArray(methods);
1105: return methods;
1106: }
1107:
1108: /*
1109: * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getIdentifier()
1110: */
1111: public final String getIdentifier() {
1112: return IDENTIFIER;
1113: }
1114:
1115: /*
1116: * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getProcessorName()
1117: */
1118: public final String getProcessorName() {
1119: return RefactoringCoreMessages.ExtractInterfaceProcessor_name;
1120: }
1121:
1122: /**
1123: * Should extracted methods be declared as public?
1124: *
1125: * @return <code>true</code> if the should be declared as public,
1126: * <code>false</code> otherwise
1127: */
1128: public final boolean getPublic() {
1129: return fPublic;
1130: }
1131:
1132: /**
1133: * Returns the type where to extract an interface.
1134: *
1135: * @return the type where to extract an interface
1136: */
1137: public final IType getType() {
1138: return fSubType;
1139: }
1140:
1141: /**
1142: * Returns the new interface name.
1143: *
1144: * @return the new interface name
1145: */
1146: public final String getTypeName() {
1147: return fSuperName;
1148: }
1149:
1150: /**
1151: * {@inheritDoc}
1152: */
1153: public final RefactoringStatus initialize(
1154: final RefactoringArguments arguments) {
1155: if (arguments instanceof JavaRefactoringArguments) {
1156: final JavaRefactoringArguments extended = (JavaRefactoringArguments) arguments;
1157: String handle = extended
1158: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
1159: if (handle != null) {
1160: final IJavaElement element = JavaRefactoringDescriptorUtil
1161: .handleToElement(extended.getProject(), handle,
1162: false);
1163: if (element == null
1164: || !element.exists()
1165: || element.getElementType() != IJavaElement.TYPE)
1166: return ScriptableRefactoring
1167: .createInputFatalStatus(element,
1168: getRefactoring().getName(),
1169: IJavaRefactorings.EXTRACT_INTERFACE);
1170: else
1171: fSubType = (IType) element;
1172: } else
1173: return RefactoringStatus
1174: .createFatalErrorStatus(Messages
1175: .format(
1176: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1177: JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
1178: final String name = extended
1179: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);
1180: if (name != null) {
1181: fSuperName = name;
1182: final RefactoringStatus status = checkTypeName(name);
1183: if (status.hasError())
1184: return status;
1185: } else
1186: return RefactoringStatus
1187: .createFatalErrorStatus(Messages
1188: .format(
1189: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1190: JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME));
1191: final String deferred = extended
1192: .getAttribute(ATTRIBUTE_ABSTRACT);
1193: if (deferred != null) {
1194: fAbstract = Boolean.valueOf(deferred).booleanValue();
1195: } else
1196: return RefactoringStatus
1197: .createFatalErrorStatus(Messages
1198: .format(
1199: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1200: ATTRIBUTE_ABSTRACT));
1201: final String comment = extended
1202: .getAttribute(ATTRIBUTE_COMMENTS);
1203: if (comment != null) {
1204: fComments = Boolean.valueOf(comment).booleanValue();
1205: } else
1206: return RefactoringStatus
1207: .createFatalErrorStatus(Messages
1208: .format(
1209: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1210: ATTRIBUTE_COMMENTS));
1211: final String instance = extended
1212: .getAttribute(ATTRIBUTE_INSTANCEOF);
1213: if (instance != null) {
1214: fInstanceOf = Boolean.valueOf(instance).booleanValue();
1215: } else
1216: return RefactoringStatus
1217: .createFatalErrorStatus(Messages
1218: .format(
1219: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1220: ATTRIBUTE_INSTANCEOF));
1221: final String visibility = extended
1222: .getAttribute(ATTRIBUTE_PUBLIC);
1223: if (visibility != null) {
1224: fPublic = Boolean.valueOf(visibility).booleanValue();
1225: } else
1226: return RefactoringStatus
1227: .createFatalErrorStatus(Messages
1228: .format(
1229: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1230: ATTRIBUTE_PUBLIC));
1231: final String replace = extended
1232: .getAttribute(ATTRIBUTE_REPLACE);
1233: if (replace != null) {
1234: fReplace = Boolean.valueOf(replace).booleanValue();
1235: } else
1236: return RefactoringStatus
1237: .createFatalErrorStatus(Messages
1238: .format(
1239: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1240: ATTRIBUTE_REPLACE));
1241: int count = 1;
1242: final List elements = new ArrayList();
1243: String attribute = JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT
1244: + count;
1245: final RefactoringStatus status = new RefactoringStatus();
1246: while ((handle = extended.getAttribute(attribute)) != null) {
1247: final IJavaElement element = JavaRefactoringDescriptorUtil
1248: .handleToElement(extended.getProject(), handle,
1249: false);
1250: if (element == null || !element.exists())
1251: status
1252: .merge(ScriptableRefactoring
1253: .createInputWarningStatus(
1254: element,
1255: getRefactoring().getName(),
1256: IJavaRefactorings.EXTRACT_INTERFACE));
1257: else
1258: elements.add(element);
1259: count++;
1260: attribute = JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT
1261: + count;
1262: }
1263: fMembers = (IMember[]) elements
1264: .toArray(new IMember[elements.size()]);
1265: fSettings = JavaPreferencesSettings
1266: .getCodeGenerationSettings(fSubType
1267: .getJavaProject());
1268: if (!status.isOK())
1269: return status;
1270: } else
1271: return RefactoringStatus
1272: .createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
1273: return new RefactoringStatus();
1274: }
1275:
1276: /*
1277: * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#isApplicable()
1278: */
1279: public final boolean isApplicable() throws CoreException {
1280: return Checks.isAvailable(fSubType) && !fSubType.isBinary()
1281: && !fSubType.isReadOnly() && !fSubType.isAnnotation()
1282: && !fSubType.isAnonymous();
1283: }
1284:
1285: /**
1286: * Should comments be generated?
1287: *
1288: * @return <code>true</code> if comments should be generated,
1289: * <code>false</code> otherwise
1290: */
1291: public final boolean isComments() {
1292: return fComments;
1293: }
1294:
1295: /*
1296: * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#loadParticipants(org.eclipse.ltk.core.refactoring.RefactoringStatus,org.eclipse.ltk.core.refactoring.participants.SharableParticipants)
1297: */
1298: public final RefactoringParticipant[] loadParticipants(
1299: final RefactoringStatus status,
1300: final SharableParticipants sharedParticipants)
1301: throws CoreException {
1302: return new RefactoringParticipant[0];
1303: }
1304:
1305: /**
1306: * Normalizes the indentation of the specified text.
1307: *
1308: * @param code
1309: * the text to normalize
1310: * @return the normalized text
1311: * @throws JavaModelException
1312: * if an error occurs
1313: */
1314: protected final String normalizeText(final String code)
1315: throws JavaModelException {
1316: Assert.isNotNull(code);
1317: final String[] lines = Strings.convertIntoLines(code);
1318: final IJavaProject project = fSubType.getJavaProject();
1319: Strings.trimIndentation(lines, project, false);
1320: return Strings.concatenate(lines, StubUtility
1321: .getLineDelimiterUsed(project));
1322: }
1323:
1324: /**
1325: * Resets the environment.
1326: */
1327: protected void resetEnvironment() {
1328: fSuperSource = null;
1329: resetWorkingCopies();
1330: }
1331:
1332: /**
1333: * {@inheritDoc}
1334: */
1335: protected final void rewriteTypeOccurrences(
1336: final TextEditBasedChangeManager manager,
1337: final ASTRequestor requestor,
1338: final CompilationUnitRewrite rewrite,
1339: final ICompilationUnit unit, final CompilationUnit node,
1340: final Set replacements, final IProgressMonitor monitor)
1341: throws CoreException {
1342: try {
1343: monitor.beginTask("", 100); //$NON-NLS-1$
1344: monitor
1345: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
1346: CompilationUnitRewrite currentRewrite = null;
1347: final boolean isSubUnit = rewrite.getCu().equals(
1348: unit.getPrimary());
1349: if (isSubUnit)
1350: currentRewrite = rewrite;
1351: else
1352: currentRewrite = new CompilationUnitRewrite(unit, node);
1353: final Collection collection = (Collection) fTypeOccurrences
1354: .get(unit);
1355: if (collection != null && !collection.isEmpty()) {
1356: final IProgressMonitor subMonitor = new SubProgressMonitor(
1357: monitor, 100);
1358: try {
1359: subMonitor.beginTask("", collection.size() * 10); //$NON-NLS-1$
1360: subMonitor
1361: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
1362: TType estimate = null;
1363: ISourceConstraintVariable variable = null;
1364: ITypeConstraintVariable constraint = null;
1365: for (final Iterator iterator = collection
1366: .iterator(); iterator.hasNext();) {
1367: variable = (ISourceConstraintVariable) iterator
1368: .next();
1369: if (variable instanceof ITypeConstraintVariable) {
1370: constraint = (ITypeConstraintVariable) variable;
1371: estimate = (TType) constraint
1372: .getData(SuperTypeConstraintsSolver.DATA_TYPE_ESTIMATE);
1373: if (estimate != null) {
1374: final CompilationUnitRange range = constraint
1375: .getRange();
1376: if (isSubUnit)
1377: rewriteTypeOccurrence(
1378: range,
1379: estimate,
1380: requestor,
1381: currentRewrite,
1382: node,
1383: replacements,
1384: currentRewrite
1385: .createCategorizedGroupDescription(
1386: RefactoringCoreMessages.SuperTypeRefactoringProcessor_update_type_occurrence,
1387: SET_SUPER_TYPE));
1388: else {
1389: final ASTNode result = NodeFinder
1390: .perform(node, range
1391: .getSourceRange());
1392: if (result != null)
1393: rewriteTypeOccurrence(
1394: estimate,
1395: currentRewrite,
1396: result,
1397: currentRewrite
1398: .createCategorizedGroupDescription(
1399: RefactoringCoreMessages.SuperTypeRefactoringProcessor_update_type_occurrence,
1400: SET_SUPER_TYPE));
1401: }
1402: subMonitor.worked(10);
1403: }
1404: }
1405: }
1406: } finally {
1407: subMonitor.done();
1408: }
1409: }
1410: if (!isSubUnit) {
1411: final TextChange change = currentRewrite.createChange();
1412: if (change != null)
1413: manager.manage(unit, change);
1414: }
1415: } finally {
1416: monitor.done();
1417: }
1418: }
1419:
1420: /**
1421: * Creates the necessary text edits to replace the subtype occurrences by a
1422: * supertype.
1423: *
1424: * @param manager
1425: * the text change manager
1426: * @param sourceRewrite
1427: * the compilation unit of the subtype (not in working copy mode)
1428: * @param superUnit
1429: * the compilation unit of the supertype (in working copy mode)
1430: * @param replacements
1431: * the set of variable binding keys of formal parameters which
1432: * must be replaced
1433: * @param status
1434: * the refactoring status
1435: * @param monitor
1436: * the progress monitor to display progress
1437: * @throws CoreException
1438: * if an error occurs
1439: */
1440: protected final void rewriteTypeOccurrences(
1441: final TextEditBasedChangeManager manager,
1442: final CompilationUnitRewrite sourceRewrite,
1443: final ICompilationUnit super Unit, final Set replacements,
1444: final RefactoringStatus status,
1445: final IProgressMonitor monitor) throws CoreException {
1446: Assert.isNotNull(manager);
1447: Assert.isNotNull(sourceRewrite);
1448: Assert.isNotNull(super Unit);
1449: Assert.isNotNull(replacements);
1450: Assert.isNotNull(status);
1451: Assert.isNotNull(monitor);
1452: try {
1453: monitor.beginTask("", 300); //$NON-NLS-1$
1454: monitor
1455: .setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
1456: final ICompilationUnit subUnit = getSharedWorkingCopy(
1457: fSubType.getCompilationUnit().getPrimary(),
1458: new SubProgressMonitor(monitor, 20));
1459: final ITextFileBuffer buffer = RefactoringFileBuffers
1460: .acquire(fSubType.getCompilationUnit());
1461: final ASTRewrite rewrite = sourceRewrite.getASTRewrite();
1462: try {
1463: final IDocument document = new Document(buffer
1464: .getDocument().get());
1465: try {
1466: rewrite.rewriteAST(document,
1467: fSubType.getJavaProject().getOptions(true))
1468: .apply(document, TextEdit.UPDATE_REGIONS);
1469: } catch (MalformedTreeException exception) {
1470: JavaPlugin.log(exception);
1471: } catch (BadLocationException exception) {
1472: JavaPlugin.log(exception);
1473: }
1474: subUnit.getBuffer().setContents(document.get());
1475: } finally {
1476: RefactoringFileBuffers.release(fSubType
1477: .getCompilationUnit());
1478: }
1479: JavaModelUtil.reconcile(subUnit);
1480: final IJavaProject project = subUnit.getJavaProject();
1481: final ASTParser parser = ASTParser.newParser(AST.JLS3);
1482: parser.setWorkingCopyOwner(fOwner);
1483: parser.setResolveBindings(true);
1484: parser.setProject(project);
1485: parser.setCompilerOptions(RefactoringASTParser
1486: .getCompilerOptions(project));
1487: parser.createASTs(new ICompilationUnit[] { subUnit },
1488: new String[0], new ASTRequestor() {
1489:
1490: public final void acceptAST(
1491: final ICompilationUnit unit,
1492: final CompilationUnit node) {
1493: try {
1494: final IType subType = (IType) JavaModelUtil
1495: .findInCompilationUnit(unit,
1496: fSubType);
1497: final AbstractTypeDeclaration subDeclaration = ASTNodeSearchUtil
1498: .getAbstractTypeDeclarationNode(
1499: subType, node);
1500: if (subDeclaration != null) {
1501: final ITypeBinding subBinding = subDeclaration
1502: .resolveBinding();
1503: if (subBinding != null) {
1504: String name = null;
1505: ITypeBinding super Binding = null;
1506: final ITypeBinding[] super Bindings = subBinding
1507: .getInterfaces();
1508: for (int index = 0; index < super Bindings.length; index++) {
1509: name = super Bindings[index]
1510: .getName();
1511: if (name
1512: .startsWith(fSuperName)
1513: && super Bindings[index]
1514: .getTypeArguments().length == subBinding
1515: .getTypeParameters().length)
1516: super Binding = super Bindings[index];
1517: }
1518: if (super Binding != null) {
1519: solveSuperTypeConstraints(
1520: unit,
1521: node,
1522: subType,
1523: subBinding,
1524: super Binding,
1525: new SubProgressMonitor(
1526: monitor, 80),
1527: status);
1528: if (!status.hasFatalError()) {
1529: rewriteTypeOccurrences(
1530: manager,
1531: this ,
1532: sourceRewrite,
1533: unit,
1534: node,
1535: replacements,
1536: status,
1537: new SubProgressMonitor(
1538: monitor,
1539: 200));
1540: if (manager
1541: .containsChangesIn(super Unit)) {
1542: final TextEditBasedChange change = manager
1543: .get(super Unit);
1544: if (change instanceof TextChange) {
1545: final TextEdit edit = ((TextChange) change)
1546: .getEdit();
1547: if (edit != null) {
1548: final IDocument document = new Document(
1549: super Unit
1550: .getBuffer()
1551: .getContents());
1552: try {
1553: edit
1554: .apply(
1555: document,
1556: TextEdit.UPDATE_REGIONS);
1557: } catch (MalformedTreeException exception) {
1558: JavaPlugin
1559: .log(exception);
1560: status
1561: .merge(RefactoringStatus
1562: .createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
1563: } catch (BadLocationException exception) {
1564: JavaPlugin
1565: .log(exception);
1566: status
1567: .merge(RefactoringStatus
1568: .createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
1569: }
1570: fSuperSource = document
1571: .get();
1572: manager
1573: .remove(super Unit);
1574: }
1575: }
1576: }
1577: }
1578: }
1579: }
1580: }
1581: } catch (JavaModelException exception) {
1582: JavaPlugin.log(exception);
1583: status
1584: .merge(RefactoringStatus
1585: .createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
1586: }
1587: }
1588:
1589: public final void acceptBinding(
1590: final String key, final IBinding binding) {
1591: // Do nothing
1592: }
1593: }, new NullProgressMonitor());
1594: } finally {
1595: monitor.done();
1596: }
1597: }
1598:
1599: /**
1600: * Determines whether extracted methods should be declared as abstract.
1601: *
1602: * @param declare
1603: * <code>true</code> to declare them public, <code>false</code>
1604: * otherwise
1605: */
1606: public final void setAbstract(final boolean declare) {
1607: fAbstract = declare;
1608: }
1609:
1610: /**
1611: * Determines whether comments should be generated.
1612: *
1613: * @param comments
1614: * <code>true</code> to generate comments, <code>false</code>
1615: * otherwise
1616: */
1617: public final void setComments(final boolean comments) {
1618: fComments = comments;
1619: }
1620:
1621: /**
1622: * Sets the members to be extracted.
1623: *
1624: * @param members
1625: * the members to be extracted
1626: * @throws JavaModelException
1627: * if an error occurs
1628: */
1629: public final void setExtractedMembers(final IMember[] members)
1630: throws JavaModelException {
1631: fMembers = members;
1632: }
1633:
1634: /**
1635: * Determines whether extracted methods should be declared as public.
1636: *
1637: * @param declare
1638: * <code>true</code> to declare them public, <code>false</code>
1639: * otherwise
1640: */
1641: public final void setPublic(final boolean declare) {
1642: fPublic = declare;
1643: }
1644:
1645: /**
1646: * Sets the new interface name.
1647: *
1648: * @param name
1649: * the new interface name
1650: */
1651: public final void setTypeName(final String name) {
1652: Assert.isNotNull(name);
1653: fSuperName = name;
1654: }
1655: }
|