0001: /*******************************************************************************
0002: * Copyright (c) 2006, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.jdt.internal.corext.refactoring.structure;
0011:
0012: import java.util.ArrayList;
0013: import java.util.Arrays;
0014: import java.util.HashMap;
0015: import java.util.Iterator;
0016: import java.util.List;
0017: import java.util.Map;
0018:
0019: import org.eclipse.text.edits.MalformedTreeException;
0020: import org.eclipse.text.edits.TextEdit;
0021:
0022: import org.eclipse.core.runtime.Assert;
0023: import org.eclipse.core.runtime.CoreException;
0024: import org.eclipse.core.runtime.IProgressMonitor;
0025: import org.eclipse.core.runtime.NullProgressMonitor;
0026: import org.eclipse.core.runtime.SubProgressMonitor;
0027:
0028: import org.eclipse.jface.text.BadLocationException;
0029: import org.eclipse.jface.text.Document;
0030: import org.eclipse.jface.text.IDocument;
0031:
0032: import org.eclipse.ltk.core.refactoring.GroupCategorySet;
0033: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
0034: import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
0035: import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
0036: import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
0037:
0038: import org.eclipse.jdt.core.Flags;
0039: import org.eclipse.jdt.core.ICompilationUnit;
0040: import org.eclipse.jdt.core.IField;
0041: import org.eclipse.jdt.core.IInitializer;
0042: import org.eclipse.jdt.core.IJavaElement;
0043: import org.eclipse.jdt.core.IMember;
0044: import org.eclipse.jdt.core.IMethod;
0045: import org.eclipse.jdt.core.ISourceRange;
0046: import org.eclipse.jdt.core.IType;
0047: import org.eclipse.jdt.core.ITypeHierarchy;
0048: import org.eclipse.jdt.core.JavaModelException;
0049: import org.eclipse.jdt.core.dom.AST;
0050: import org.eclipse.jdt.core.dom.ASTNode;
0051: import org.eclipse.jdt.core.dom.ASTVisitor;
0052: import org.eclipse.jdt.core.dom.Annotation;
0053: import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
0054: import org.eclipse.jdt.core.dom.BodyDeclaration;
0055: import org.eclipse.jdt.core.dom.ClassInstanceCreation;
0056: import org.eclipse.jdt.core.dom.CompilationUnit;
0057: import org.eclipse.jdt.core.dom.EnumDeclaration;
0058: import org.eclipse.jdt.core.dom.Expression;
0059: import org.eclipse.jdt.core.dom.FieldDeclaration;
0060: import org.eclipse.jdt.core.dom.IExtendedModifier;
0061: import org.eclipse.jdt.core.dom.IMethodBinding;
0062: import org.eclipse.jdt.core.dom.ITypeBinding;
0063: import org.eclipse.jdt.core.dom.Javadoc;
0064: import org.eclipse.jdt.core.dom.MethodDeclaration;
0065: import org.eclipse.jdt.core.dom.Modifier;
0066: import org.eclipse.jdt.core.dom.Name;
0067: import org.eclipse.jdt.core.dom.SimpleName;
0068: import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
0069: import org.eclipse.jdt.core.dom.Type;
0070: import org.eclipse.jdt.core.dom.TypeDeclaration;
0071: import org.eclipse.jdt.core.dom.TypeParameter;
0072: import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
0073: import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
0074: import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition;
0075: import org.eclipse.jdt.core.search.IJavaSearchConstants;
0076: import org.eclipse.jdt.core.search.SearchMatch;
0077: import org.eclipse.jdt.core.search.SearchPattern;
0078:
0079: import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
0080: import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
0081: import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
0082: import org.eclipse.jdt.internal.corext.dom.ASTNodes;
0083: import org.eclipse.jdt.internal.corext.dom.ModifierRewrite;
0084: import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
0085: import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
0086: import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
0087: import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2;
0088: import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
0089: import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
0090: import org.eclipse.jdt.internal.corext.refactoring.reorg.SourceReferenceUtil;
0091: import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsModel;
0092: import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsSolver;
0093: import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor;
0094: import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
0095: import org.eclipse.jdt.internal.corext.refactoring.util.TextEditBasedChangeManager;
0096: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
0097: import org.eclipse.jdt.internal.corext.util.JdtFlags;
0098: import org.eclipse.jdt.internal.corext.util.Messages;
0099: import org.eclipse.jdt.internal.corext.util.SearchUtils;
0100: import org.eclipse.jdt.internal.corext.util.Strings;
0101:
0102: import org.eclipse.jdt.ui.JavaElementLabels;
0103:
0104: import org.eclipse.jdt.internal.ui.JavaPlugin;
0105:
0106: /**
0107: * Partial implementation of a hierarchy refactoring processor used in pull up,
0108: * push down and extract supertype refactorings.
0109: * <p>
0110: * This processor provides common functionality to move members in a type
0111: * hierarchy, and to perform a "Use Supertype" refactoring afterwards.
0112: * </p>
0113: *
0114: * @since 3.2
0115: */
0116: public abstract class HierarchyProcessor extends
0117: SuperTypeRefactoringProcessor {
0118:
0119: /**
0120: * AST node visitor which performs the actual mapping.
0121: */
0122: public static class TypeVariableMapper extends ASTVisitor {
0123:
0124: /** The type variable mapping to use */
0125: protected final TypeVariableMaplet[] fMapping;
0126:
0127: /** The AST rewrite to use */
0128: protected final ASTRewrite fRewrite;
0129:
0130: /**
0131: * Creates a new type variable mapper.
0132: *
0133: * @param rewrite
0134: * The AST rewrite to use
0135: * @param mapping
0136: * The type variable mapping to use
0137: */
0138: public TypeVariableMapper(final ASTRewrite rewrite,
0139: final TypeVariableMaplet[] mapping) {
0140: Assert.isNotNull(rewrite);
0141: Assert.isNotNull(mapping);
0142: fRewrite = rewrite;
0143: fMapping = mapping;
0144: }
0145:
0146: public final boolean visit(final SimpleName node) {
0147: final ITypeBinding binding = node.resolveTypeBinding();
0148: if (binding != null && binding.isTypeVariable()) {
0149: String name = null;
0150: for (int index = 0; index < fMapping.length; index++) {
0151: name = binding.getName();
0152: if (fMapping[index].getSourceName().equals(name)
0153: && node.getIdentifier().equals(name)) {
0154: final MethodDeclaration declaration = (MethodDeclaration) ASTNodes
0155: .getParent(node,
0156: MethodDeclaration.class);
0157: if (declaration != null) {
0158: final IMethodBinding method = declaration
0159: .resolveBinding();
0160: if (method != null) {
0161: final ITypeBinding[] bindings = method
0162: .getTypeParameters();
0163: for (int offset = 0; offset < bindings.length; offset++) {
0164: if (bindings[offset]
0165: .isEqualTo(binding))
0166: return true;
0167: }
0168: }
0169: }
0170: fRewrite.set(node,
0171: SimpleName.IDENTIFIER_PROPERTY,
0172: fMapping[index].getTargetName(), null);
0173: }
0174: }
0175: }
0176: return true;
0177: }
0178: }
0179:
0180: protected static boolean areAllFragmentsDeleted(
0181: final FieldDeclaration declaration,
0182: final List declarationNodes) {
0183: for (final Iterator iterator = declaration.fragments()
0184: .iterator(); iterator.hasNext();) {
0185: if (!declarationNodes.contains(iterator.next()))
0186: return false;
0187: }
0188: return true;
0189: }
0190:
0191: protected static RefactoringStatus checkProjectCompliance(
0192: CompilationUnitRewrite sourceRewriter, IType destination,
0193: IMember[] members) {
0194: RefactoringStatus status = new RefactoringStatus();
0195: if (!JavaModelUtil.is50OrHigher(destination.getJavaProject())) {
0196: for (int index = 0; index < members.length; index++) {
0197: try {
0198: BodyDeclaration decl = ASTNodeSearchUtil
0199: .getBodyDeclarationNode(members[index],
0200: sourceRewriter.getRoot());
0201: if (decl != null) {
0202: for (final Iterator iterator = decl.modifiers()
0203: .iterator(); iterator.hasNext();) {
0204: boolean reported = false;
0205: final IExtendedModifier modifier = (IExtendedModifier) iterator
0206: .next();
0207: if (!reported && modifier.isAnnotation()) {
0208: status
0209: .merge(RefactoringStatus
0210: .createErrorStatus(
0211: Messages
0212: .format(
0213: RefactoringCoreMessages.PullUpRefactoring_incompatible_langauge_constructs,
0214: new String[] {
0215: JavaElementLabels
0216: .getTextLabel(
0217: members[index],
0218: JavaElementLabels.ALL_FULLY_QUALIFIED),
0219: JavaElementLabels
0220: .getTextLabel(
0221: destination,
0222: JavaElementLabels.ALL_DEFAULT) }),
0223: JavaStatusContext
0224: .create(members[index])));
0225: reported = true;
0226: }
0227: }
0228: }
0229: } catch (JavaModelException exception) {
0230: JavaPlugin.log(exception);
0231: }
0232: if (members[index] instanceof IMethod) {
0233: final IMethod method = (IMethod) members[index];
0234: try {
0235: if (Flags.isVarargs(method.getFlags()))
0236: status
0237: .merge(RefactoringStatus
0238: .createErrorStatus(
0239: Messages
0240: .format(
0241: RefactoringCoreMessages.PullUpRefactoring_incompatible_language_constructs1,
0242: new String[] {
0243: JavaElementLabels
0244: .getTextLabel(
0245: members[index],
0246: JavaElementLabels.ALL_FULLY_QUALIFIED),
0247: JavaElementLabels
0248: .getTextLabel(
0249: destination,
0250: JavaElementLabels.ALL_DEFAULT) }),
0251: JavaStatusContext
0252: .create(members[index])));
0253: } catch (JavaModelException exception) {
0254: JavaPlugin.log(exception);
0255: }
0256: }
0257: }
0258: }
0259: return status;
0260: }
0261:
0262: protected static void copyAnnotations(
0263: final FieldDeclaration oldField,
0264: final FieldDeclaration newField) {
0265: final AST ast = newField.getAST();
0266: for (int index = 0, n = oldField.modifiers().size(); index < n; index++) {
0267: final IExtendedModifier modifier = (IExtendedModifier) oldField
0268: .modifiers().get(index);
0269: final List modifiers = newField.modifiers();
0270: if (modifier.isAnnotation()
0271: && !modifiers.contains(modifier))
0272: modifiers.add(index, ASTNode.copySubtree(ast,
0273: (Annotation) modifier));
0274: }
0275: }
0276:
0277: protected static void copyAnnotations(
0278: final MethodDeclaration oldMethod,
0279: final MethodDeclaration newMethod) {
0280: final AST ast = newMethod.getAST();
0281: for (int index = 0, n = oldMethod.modifiers().size(); index < n; index++) {
0282: final IExtendedModifier modifier = (IExtendedModifier) oldMethod
0283: .modifiers().get(index);
0284: final List modifiers = newMethod.modifiers();
0285: if (modifier.isAnnotation()
0286: && !modifiers.contains(modifier))
0287: modifiers.add(index, ASTNode.copySubtree(ast,
0288: (Annotation) modifier));
0289: }
0290: }
0291:
0292: protected static void copyJavadocNode(final ASTRewrite rewrite,
0293: final BodyDeclaration oldDeclaration,
0294: final BodyDeclaration newDeclaration)
0295: throws JavaModelException {
0296: final Javadoc predecessor = oldDeclaration.getJavadoc();
0297: if (predecessor != null) {
0298: String newString = ASTNodes.getNodeSource(predecessor,
0299: false, true);
0300: if (newString != null) {
0301: newDeclaration.setJavadoc((Javadoc) rewrite
0302: .createStringPlaceholder(newString,
0303: ASTNode.JAVADOC));
0304: }
0305: }
0306: }
0307:
0308: protected static void copyThrownExceptions(
0309: final MethodDeclaration oldMethod,
0310: final MethodDeclaration newMethod) {
0311: final AST ast = newMethod.getAST();
0312: for (int index = 0, n = oldMethod.thrownExceptions().size(); index < n; index++)
0313: newMethod.thrownExceptions().add(
0314: index,
0315: ASTNode.copySubtree(ast, (Name) oldMethod
0316: .thrownExceptions().get(index)));
0317: }
0318:
0319: protected static void copyTypeParameters(
0320: final MethodDeclaration oldMethod,
0321: final MethodDeclaration newMethod) {
0322: final AST ast = newMethod.getAST();
0323: for (int index = 0, n = oldMethod.typeParameters().size(); index < n; index++)
0324: newMethod.typeParameters().add(
0325: index,
0326: ASTNode.copySubtree(ast, (TypeParameter) oldMethod
0327: .typeParameters().get(index)));
0328: }
0329:
0330: protected static String createLabel(final IMember member) {
0331: if (member instanceof IType)
0332: return JavaElementLabels.getTextLabel(member,
0333: JavaElementLabels.ALL_FULLY_QUALIFIED);
0334: else if (member instanceof IMethod)
0335: return JavaElementLabels.getTextLabel(member,
0336: JavaElementLabels.ALL_FULLY_QUALIFIED);
0337: else if (member instanceof IField)
0338: return JavaElementLabels.getTextLabel(member,
0339: JavaElementLabels.ALL_FULLY_QUALIFIED);
0340: else if (member instanceof IInitializer)
0341: return RefactoringCoreMessages.HierarchyRefactoring_initializer;
0342: Assert.isTrue(false);
0343: return null;
0344: }
0345:
0346: protected static FieldDeclaration createNewFieldDeclarationNode(
0347: final ASTRewrite rewrite, final CompilationUnit unit,
0348: final IField field,
0349: final VariableDeclarationFragment oldFieldFragment,
0350: final TypeVariableMaplet[] mapping,
0351: final IProgressMonitor monitor,
0352: final RefactoringStatus status, final int modifiers)
0353: throws JavaModelException {
0354: final VariableDeclarationFragment newFragment = rewrite
0355: .getAST().newVariableDeclarationFragment();
0356: newFragment.setExtraDimensions(oldFieldFragment
0357: .getExtraDimensions());
0358: if (oldFieldFragment.getInitializer() != null) {
0359: Expression newInitializer = null;
0360: if (mapping.length > 0)
0361: newInitializer = createPlaceholderForExpression(
0362: oldFieldFragment.getInitializer(), field
0363: .getCompilationUnit(), mapping, rewrite);
0364: else
0365: newInitializer = createPlaceholderForExpression(
0366: oldFieldFragment.getInitializer(), field
0367: .getCompilationUnit(), rewrite);
0368: newFragment.setInitializer(newInitializer);
0369: }
0370: newFragment.setName(((SimpleName) ASTNode.copySubtree(rewrite
0371: .getAST(), oldFieldFragment.getName())));
0372: final FieldDeclaration newField = rewrite.getAST()
0373: .newFieldDeclaration(newFragment);
0374: final FieldDeclaration oldField = ASTNodeSearchUtil
0375: .getFieldDeclarationNode(field, unit);
0376: copyJavadocNode(rewrite, oldField, newField);
0377: copyAnnotations(oldField, newField);
0378: newField.modifiers().addAll(
0379: ASTNodeFactory
0380: .newModifiers(rewrite.getAST(), modifiers));
0381: final Type oldType = oldField.getType();
0382: Type newType = null;
0383: if (mapping.length > 0) {
0384: newType = createPlaceholderForType(oldType, field
0385: .getCompilationUnit(), mapping, rewrite);
0386: } else
0387: newType = createPlaceholderForType(oldType, field
0388: .getCompilationUnit(), rewrite);
0389: newField.setType(newType);
0390: return newField;
0391: }
0392:
0393: protected static Expression createPlaceholderForExpression(
0394: final Expression expression,
0395: final ICompilationUnit declaringCu, final ASTRewrite rewrite)
0396: throws JavaModelException {
0397: return (Expression) rewrite.createStringPlaceholder(declaringCu
0398: .getBuffer().getText(expression.getStartPosition(),
0399: expression.getLength()),
0400: ASTNode.METHOD_INVOCATION);
0401: }
0402:
0403: protected static Expression createPlaceholderForExpression(
0404: final Expression expression,
0405: final ICompilationUnit declaringCu,
0406: final TypeVariableMaplet[] mapping, final ASTRewrite rewrite)
0407: throws JavaModelException {
0408: Expression result = null;
0409: try {
0410: final IDocument document = new Document(declaringCu
0411: .getBuffer().getContents());
0412: final ASTRewrite rewriter = ASTRewrite.create(expression
0413: .getAST());
0414: final ITrackedNodePosition position = rewriter
0415: .track(expression);
0416: expression
0417: .accept(new TypeVariableMapper(rewriter, mapping));
0418: rewriter.rewriteAST(document,
0419: declaringCu.getJavaProject().getOptions(true))
0420: .apply(document, TextEdit.NONE);
0421: result = (Expression) rewrite.createStringPlaceholder(
0422: document.get(position.getStartPosition(), position
0423: .getLength()), ASTNode.METHOD_INVOCATION);
0424: } catch (MalformedTreeException exception) {
0425: JavaPlugin.log(exception);
0426: } catch (BadLocationException exception) {
0427: JavaPlugin.log(exception);
0428: }
0429: return result;
0430: }
0431:
0432: protected static BodyDeclaration createPlaceholderForProtectedTypeDeclaration(
0433: final BodyDeclaration bodyDeclaration,
0434: final CompilationUnit declaringCuNode,
0435: final ICompilationUnit declaringCu,
0436: final ASTRewrite rewrite, final boolean removeIndentation)
0437: throws JavaModelException {
0438: String text = null;
0439: try {
0440: final ASTRewrite rewriter = ASTRewrite
0441: .create(bodyDeclaration.getAST());
0442: ModifierRewrite.create(rewriter, bodyDeclaration)
0443: .setVisibility(Modifier.PROTECTED, null);
0444: final ITrackedNodePosition position = rewriter
0445: .track(bodyDeclaration);
0446: final IDocument document = new Document(declaringCu
0447: .getBuffer().getText(
0448: declaringCuNode.getStartPosition(),
0449: declaringCuNode.getLength()));
0450: rewriter.rewriteAST(document,
0451: declaringCu.getJavaProject().getOptions(true))
0452: .apply(document, TextEdit.UPDATE_REGIONS);
0453: text = document.get(position.getStartPosition(), position
0454: .getLength());
0455: } catch (BadLocationException exception) {
0456: text = getNewText(bodyDeclaration, declaringCu,
0457: removeIndentation);
0458: }
0459: return (BodyDeclaration) rewrite.createStringPlaceholder(text,
0460: ASTNode.TYPE_DECLARATION);
0461: }
0462:
0463: protected static BodyDeclaration createPlaceholderForProtectedTypeDeclaration(
0464: final BodyDeclaration bodyDeclaration,
0465: final CompilationUnit declaringCuNode,
0466: final ICompilationUnit declaringCu,
0467: final TypeVariableMaplet[] mapping,
0468: final ASTRewrite rewrite, final boolean removeIndentation)
0469: throws JavaModelException {
0470: BodyDeclaration result = null;
0471: try {
0472: final IDocument document = new Document(declaringCu
0473: .getBuffer().getContents());
0474: final ASTRewrite rewriter = ASTRewrite
0475: .create(bodyDeclaration.getAST());
0476: final ITrackedNodePosition position = rewriter
0477: .track(bodyDeclaration);
0478: bodyDeclaration.accept(new TypeVariableMapper(rewriter,
0479: mapping) {
0480:
0481: public final boolean visit(
0482: final AnnotationTypeDeclaration node) {
0483: ModifierRewrite.create(fRewrite, bodyDeclaration)
0484: .setVisibility(Modifier.PROTECTED, null);
0485: return true;
0486: }
0487:
0488: public final boolean visit(final EnumDeclaration node) {
0489: ModifierRewrite.create(fRewrite, bodyDeclaration)
0490: .setVisibility(Modifier.PROTECTED, null);
0491: return true;
0492: }
0493:
0494: public final boolean visit(final TypeDeclaration node) {
0495: ModifierRewrite.create(fRewrite, bodyDeclaration)
0496: .setVisibility(Modifier.PROTECTED, null);
0497: return true;
0498: }
0499: });
0500: rewriter.rewriteAST(document,
0501: declaringCu.getJavaProject().getOptions(true))
0502: .apply(document, TextEdit.NONE);
0503: result = (BodyDeclaration) rewrite.createStringPlaceholder(
0504: document.get(position.getStartPosition(), position
0505: .getLength()), ASTNode.TYPE_DECLARATION);
0506: } catch (MalformedTreeException exception) {
0507: JavaPlugin.log(exception);
0508: } catch (BadLocationException exception) {
0509: JavaPlugin.log(exception);
0510: }
0511: return result;
0512: }
0513:
0514: protected static SingleVariableDeclaration createPlaceholderForSingleVariableDeclaration(
0515: final SingleVariableDeclaration declaration,
0516: final ICompilationUnit declaringCu, final ASTRewrite rewrite)
0517: throws JavaModelException {
0518: return (SingleVariableDeclaration) rewrite
0519: .createStringPlaceholder(declaringCu.getBuffer()
0520: .getText(declaration.getStartPosition(),
0521: declaration.getLength()),
0522: ASTNode.SINGLE_VARIABLE_DECLARATION);
0523: }
0524:
0525: protected static SingleVariableDeclaration createPlaceholderForSingleVariableDeclaration(
0526: final SingleVariableDeclaration declaration,
0527: final ICompilationUnit declaringCu,
0528: final TypeVariableMaplet[] mapping, final ASTRewrite rewrite)
0529: throws JavaModelException {
0530: SingleVariableDeclaration result = null;
0531: try {
0532: final IDocument document = new Document(declaringCu
0533: .getBuffer().getContents());
0534: final ASTRewrite rewriter = ASTRewrite.create(declaration
0535: .getAST());
0536: final ITrackedNodePosition position = rewriter
0537: .track(declaration);
0538: declaration
0539: .accept(new TypeVariableMapper(rewriter, mapping));
0540: rewriter.rewriteAST(document,
0541: declaringCu.getJavaProject().getOptions(true))
0542: .apply(document, TextEdit.NONE);
0543: result = (SingleVariableDeclaration) rewrite
0544: .createStringPlaceholder(document.get(position
0545: .getStartPosition(), position.getLength()),
0546: ASTNode.SINGLE_VARIABLE_DECLARATION);
0547: } catch (MalformedTreeException exception) {
0548: JavaPlugin.log(exception);
0549: } catch (BadLocationException exception) {
0550: JavaPlugin.log(exception);
0551: }
0552: return result;
0553: }
0554:
0555: protected static Type createPlaceholderForType(final Type type,
0556: final ICompilationUnit declaringCu, final ASTRewrite rewrite)
0557: throws JavaModelException {
0558: return (Type) rewrite.createStringPlaceholder(declaringCu
0559: .getBuffer().getText(type.getStartPosition(),
0560: type.getLength()), ASTNode.SIMPLE_TYPE);
0561: }
0562:
0563: protected static Type createPlaceholderForType(final Type type,
0564: final ICompilationUnit declaringCu,
0565: final TypeVariableMaplet[] mapping, final ASTRewrite rewrite)
0566: throws JavaModelException {
0567: Type result = null;
0568: try {
0569: final IDocument document = new Document(declaringCu
0570: .getBuffer().getContents());
0571: final ASTRewrite rewriter = ASTRewrite
0572: .create(type.getAST());
0573: final ITrackedNodePosition position = rewriter.track(type);
0574: type.accept(new TypeVariableMapper(rewriter, mapping));
0575: rewriter.rewriteAST(document,
0576: declaringCu.getJavaProject().getOptions(true))
0577: .apply(document, TextEdit.NONE);
0578: result = (Type) rewrite.createStringPlaceholder(document
0579: .get(position.getStartPosition(), position
0580: .getLength()), ASTNode.SIMPLE_TYPE);
0581: } catch (MalformedTreeException exception) {
0582: JavaPlugin.log(exception);
0583: } catch (BadLocationException exception) {
0584: JavaPlugin.log(exception);
0585: }
0586: return result;
0587: }
0588:
0589: protected static BodyDeclaration createPlaceholderForTypeDeclaration(
0590: final BodyDeclaration bodyDeclaration,
0591: final ICompilationUnit declaringCu,
0592: final ASTRewrite rewrite, final boolean removeIndentation)
0593: throws JavaModelException {
0594: return (BodyDeclaration) rewrite.createStringPlaceholder(
0595: getNewText(bodyDeclaration, declaringCu,
0596: removeIndentation), ASTNode.TYPE_DECLARATION);
0597: }
0598:
0599: protected static BodyDeclaration createPlaceholderForTypeDeclaration(
0600: final BodyDeclaration bodyDeclaration,
0601: final ICompilationUnit declaringCu,
0602: final TypeVariableMaplet[] mapping,
0603: final ASTRewrite rewrite, final boolean removeIndentation)
0604: throws JavaModelException {
0605: BodyDeclaration result = null;
0606: try {
0607: final IDocument document = new Document(declaringCu
0608: .getBuffer().getContents());
0609: final ASTRewrite rewriter = ASTRewrite
0610: .create(bodyDeclaration.getAST());
0611: final ITrackedNodePosition position = rewriter
0612: .track(bodyDeclaration);
0613: bodyDeclaration.accept(new TypeVariableMapper(rewriter,
0614: mapping));
0615: rewriter.rewriteAST(document,
0616: declaringCu.getJavaProject().getOptions(true))
0617: .apply(document, TextEdit.NONE);
0618: result = (BodyDeclaration) rewrite.createStringPlaceholder(
0619: document.get(position.getStartPosition(), position
0620: .getLength()), ASTNode.TYPE_DECLARATION);
0621: } catch (MalformedTreeException exception) {
0622: JavaPlugin.log(exception);
0623: } catch (BadLocationException exception) {
0624: JavaPlugin.log(exception);
0625: }
0626: return result;
0627: }
0628:
0629: protected static void deleteDeclarationNodes(
0630: final CompilationUnitRewrite sourceRewriter,
0631: final boolean sameCu,
0632: final CompilationUnitRewrite unitRewriter,
0633: final List members, final GroupCategorySet set)
0634: throws JavaModelException {
0635: final List declarationNodes = getDeclarationNodes(unitRewriter
0636: .getRoot(), members);
0637: for (final Iterator iterator = declarationNodes.iterator(); iterator
0638: .hasNext();) {
0639: final ASTNode node = (ASTNode) iterator.next();
0640: final ASTRewrite rewriter = unitRewriter.getASTRewrite();
0641: final ImportRemover remover = unitRewriter
0642: .getImportRemover();
0643: if (node instanceof VariableDeclarationFragment) {
0644: if (node.getParent() instanceof FieldDeclaration) {
0645: final FieldDeclaration declaration = (FieldDeclaration) node
0646: .getParent();
0647: if (areAllFragmentsDeleted(declaration,
0648: declarationNodes)) {
0649: rewriter
0650: .remove(
0651: declaration,
0652: unitRewriter
0653: .createCategorizedGroupDescription(
0654: RefactoringCoreMessages.HierarchyRefactoring_remove_member,
0655: set));
0656: if (!sameCu)
0657: remover.registerRemovedNode(declaration);
0658: } else {
0659: rewriter
0660: .remove(
0661: node,
0662: unitRewriter
0663: .createCategorizedGroupDescription(
0664: RefactoringCoreMessages.HierarchyRefactoring_remove_member,
0665: set));
0666: if (!sameCu)
0667: remover.registerRemovedNode(node);
0668: }
0669: }
0670: } else {
0671: rewriter
0672: .remove(
0673: node,
0674: unitRewriter
0675: .createCategorizedGroupDescription(
0676: RefactoringCoreMessages.HierarchyRefactoring_remove_member,
0677: set));
0678: if (!sameCu)
0679: remover.registerRemovedNode(node);
0680: }
0681: }
0682: }
0683:
0684: protected static List getDeclarationNodes(
0685: final CompilationUnit cuNode, final List members)
0686: throws JavaModelException {
0687: final List result = new ArrayList(members.size());
0688: for (final Iterator iterator = members.iterator(); iterator
0689: .hasNext();) {
0690: final IMember member = (IMember) iterator.next();
0691: ASTNode node = null;
0692: if (member instanceof IField) {
0693: if (Flags.isEnum(member.getFlags()))
0694: node = ASTNodeSearchUtil
0695: .getEnumConstantDeclaration(
0696: (IField) member, cuNode);
0697: else
0698: node = ASTNodeSearchUtil
0699: .getFieldDeclarationFragmentNode(
0700: (IField) member, cuNode);
0701: } else if (member instanceof IType)
0702: node = ASTNodeSearchUtil
0703: .getAbstractTypeDeclarationNode((IType) member,
0704: cuNode);
0705: else if (member instanceof IMethod)
0706: node = ASTNodeSearchUtil.getMethodDeclarationNode(
0707: (IMethod) member, cuNode);
0708: if (node != null)
0709: result.add(node);
0710: }
0711: return result;
0712: }
0713:
0714: protected static String getNewText(final ASTNode node,
0715: final ICompilationUnit declaringCu,
0716: final boolean removeIndentation) throws JavaModelException {
0717: final String result = declaringCu.getBuffer().getText(
0718: node.getStartPosition(), node.getLength());
0719: if (removeIndentation)
0720: return getUnindentedText(result, declaringCu);
0721:
0722: return result;
0723: }
0724:
0725: protected static String getUnindentedText(final String text,
0726: final ICompilationUnit declaringCu)
0727: throws JavaModelException {
0728: final String[] lines = Strings.convertIntoLines(text);
0729: Strings.trimIndentation(lines, declaringCu.getJavaProject(),
0730: false);
0731: return Strings.concatenate(lines, StubUtility
0732: .getLineDelimiterUsed(declaringCu));
0733: }
0734:
0735: /** The cached declaring type */
0736: protected IType fCachedDeclaringType;
0737:
0738: /** The cached member references */
0739: protected final Map fCachedMembersReferences = new HashMap(2);
0740:
0741: /** The cached type references */
0742: protected IType[] fCachedReferencedTypes;
0743:
0744: /** The text edit based change manager */
0745: protected TextEditBasedChangeManager fChangeManager;
0746:
0747: /** Does the refactoring use a working copy layer? */
0748: protected final boolean fLayer;
0749:
0750: /** The members to move (may be in working copies) */
0751: protected IMember[] fMembersToMove;
0752:
0753: /**
0754: * Creates a new hierarchy processor.
0755: *
0756: * @param members
0757: * the members, or <code>null</code> if invoked by scripting
0758: * @param settings
0759: * the code generation settings to use
0760: * @param layer
0761: * <code>true</code> to create a working copy layer,
0762: * <code>false</code> otherwise
0763: */
0764: protected HierarchyProcessor(final IMember[] members,
0765: final CodeGenerationSettings settings, boolean layer) {
0766: super (settings);
0767: fLayer = layer;
0768: if (members != null) {
0769: fMembersToMove = (IMember[]) SourceReferenceUtil
0770: .sortByOffset(members);
0771: if (layer && fMembersToMove.length > 0) {
0772: final ICompilationUnit original = fMembersToMove[0]
0773: .getCompilationUnit();
0774: if (original != null) {
0775: try {
0776: final ICompilationUnit copy = getSharedWorkingCopy(
0777: original.getPrimary(),
0778: new NullProgressMonitor());
0779: if (copy != null) {
0780: for (int index = 0; index < fMembersToMove.length; index++) {
0781: final IJavaElement[] elements = copy
0782: .findElements(fMembersToMove[index]);
0783: if (elements != null
0784: && elements.length > 0
0785: && elements[0] instanceof IMember) {
0786: fMembersToMove[index] = (IMember) elements[0];
0787: }
0788: }
0789: }
0790: } catch (JavaModelException exception) {
0791: JavaPlugin.log(exception);
0792: }
0793: }
0794: }
0795: }
0796: }
0797:
0798: protected boolean canBeAccessedFrom(final IMember member,
0799: final IType target, final ITypeHierarchy hierarchy)
0800: throws JavaModelException {
0801: Assert.isTrue(!(member instanceof IInitializer));
0802: return member.exists();
0803: }
0804:
0805: protected RefactoringStatus checkConstructorCalls(final IType type,
0806: final IProgressMonitor monitor) throws JavaModelException {
0807: try {
0808: monitor.beginTask(
0809: RefactoringCoreMessages.PullUpRefactoring_checking,
0810: 2);
0811: final RefactoringStatus result = new RefactoringStatus();
0812: final SearchResultGroup[] groups = ConstructorReferenceFinder
0813: .getConstructorReferences(type, fOwner,
0814: new SubProgressMonitor(monitor, 1), result);
0815: final String message = Messages
0816: .format(
0817: RefactoringCoreMessages.HierarchyRefactoring_gets_instantiated,
0818: new Object[] { JavaElementLabels
0819: .getTextLabel(
0820: type,
0821: JavaElementLabels.ALL_FULLY_QUALIFIED) });
0822:
0823: ICompilationUnit unit = null;
0824: for (int index = 0; index < groups.length; index++) {
0825: unit = groups[index].getCompilationUnit();
0826: if (unit != null) {
0827: final CompilationUnit cuNode = RefactoringASTParser
0828: .parseWithASTProvider(unit, false,
0829: new SubProgressMonitor(monitor, 1));
0830: final ASTNode[] references = ASTNodeSearchUtil
0831: .getAstNodes(groups[index]
0832: .getSearchResults(), cuNode);
0833: ASTNode node = null;
0834: for (int offset = 0; offset < references.length; offset++) {
0835: node = references[offset];
0836: if ((node instanceof ClassInstanceCreation)
0837: || ConstructorReferenceFinder
0838: .isImplicitConstructorReferenceNodeInClassCreations(node)) {
0839: final RefactoringStatusContext context = JavaStatusContext
0840: .create(unit, node);
0841: result.addError(message, context);
0842: }
0843: }
0844: }
0845: }
0846: return result;
0847: } finally {
0848: monitor.done();
0849: }
0850: }
0851:
0852: protected RefactoringStatus checkDeclaringType(
0853: final IProgressMonitor monitor) throws JavaModelException {
0854: try {
0855: final IType type = getDeclaringType();
0856: if (type.isEnum())
0857: return RefactoringStatus
0858: .createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_enum_members);
0859: if (type.isAnnotation())
0860: return RefactoringStatus
0861: .createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_annotation_members);
0862: if (type.isInterface())
0863: return RefactoringStatus
0864: .createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_interface_members);
0865: if (type.isBinary())
0866: return RefactoringStatus
0867: .createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_members_of_binary);
0868: if (type.isReadOnly())
0869: return RefactoringStatus
0870: .createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_members_of_read_only);
0871: return new RefactoringStatus();
0872: } finally {
0873: if (monitor != null)
0874: monitor.done();
0875: }
0876: }
0877:
0878: protected RefactoringStatus checkIfMembersExist() {
0879: final RefactoringStatus result = new RefactoringStatus();
0880: IMember member = null;
0881: for (int index = 0; index < fMembersToMove.length; index++) {
0882: member = fMembersToMove[index];
0883: if (member == null || !member.exists())
0884: result
0885: .addFatalError(RefactoringCoreMessages.HierarchyRefactoring_does_not_exist);
0886: }
0887: return result;
0888: }
0889:
0890: protected void clearCaches() {
0891: fCachedReferencedTypes = null;
0892: }
0893:
0894: protected void copyParameters(final ASTRewrite rewrite,
0895: final ICompilationUnit unit,
0896: final MethodDeclaration oldMethod,
0897: final MethodDeclaration newMethod,
0898: final TypeVariableMaplet[] mapping)
0899: throws JavaModelException {
0900: SingleVariableDeclaration newDeclaration = null;
0901: for (int index = 0, size = oldMethod.parameters().size(); index < size; index++) {
0902: final SingleVariableDeclaration oldDeclaration = (SingleVariableDeclaration) oldMethod
0903: .parameters().get(index);
0904: if (mapping.length > 0)
0905: newDeclaration = createPlaceholderForSingleVariableDeclaration(
0906: oldDeclaration, unit, mapping, rewrite);
0907: else
0908: newDeclaration = createPlaceholderForSingleVariableDeclaration(
0909: oldDeclaration, unit, rewrite);
0910: newMethod.parameters().add(index, newDeclaration);
0911: }
0912: }
0913:
0914: protected void copyReturnType(final ASTRewrite rewrite,
0915: final ICompilationUnit unit,
0916: final MethodDeclaration oldMethod,
0917: final MethodDeclaration newMethod,
0918: final TypeVariableMaplet[] mapping)
0919: throws JavaModelException {
0920: Type newReturnType = null;
0921: if (mapping.length > 0)
0922: newReturnType = createPlaceholderForType(oldMethod
0923: .getReturnType2(), unit, mapping, rewrite);
0924: else
0925: newReturnType = createPlaceholderForType(oldMethod
0926: .getReturnType2(), unit, rewrite);
0927: newMethod.setReturnType2(newReturnType);
0928: }
0929:
0930: protected SuperTypeConstraintsSolver createContraintSolver(
0931: final SuperTypeConstraintsModel model) {
0932: return new SuperTypeConstraintsSolver(model);
0933: }
0934:
0935: public IType getDeclaringType() {
0936: if (fCachedDeclaringType != null)
0937: return fCachedDeclaringType;
0938: fCachedDeclaringType = RefactoringAvailabilityTester
0939: .getTopLevelType(fMembersToMove);
0940: if (fCachedDeclaringType == null)
0941: fCachedDeclaringType = fMembersToMove[0].getDeclaringType();
0942: return fCachedDeclaringType;
0943: }
0944:
0945: public IMember[] getMembersToMove() {
0946: return fMembersToMove;
0947: }
0948:
0949: protected IType[] getTypesReferencedInMovedMembers(
0950: final IProgressMonitor monitor) throws JavaModelException {
0951: if (fCachedReferencedTypes == null) {
0952: final IType[] types = ReferenceFinderUtil
0953: .getTypesReferencedIn(fMembersToMove, fOwner,
0954: monitor);
0955: final List result = new ArrayList(types.length);
0956: final List members = Arrays.asList(fMembersToMove);
0957: for (int index = 0; index < types.length; index++) {
0958: if (!members.contains(types[index])
0959: && !types[index].equals(getDeclaringType()))
0960: result.add(types[index]);
0961: }
0962: fCachedReferencedTypes = new IType[result.size()];
0963: result.toArray(fCachedReferencedTypes);
0964: }
0965: return fCachedReferencedTypes;
0966: }
0967:
0968: protected boolean hasNonMovedReferences(final IMember member,
0969: final IProgressMonitor monitor,
0970: final RefactoringStatus status) throws JavaModelException {
0971: if (!fCachedMembersReferences.containsKey(member)) {
0972: final RefactoringSearchEngine2 engine = new RefactoringSearchEngine2(
0973: SearchPattern.createPattern(member,
0974: IJavaSearchConstants.REFERENCES,
0975: SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE));
0976: engine.setFiltering(true, true);
0977: engine.setStatus(status);
0978: engine.setOwner(fOwner);
0979: engine.setScope(RefactoringScopeFactory.create(member));
0980: engine.searchPattern(new SubProgressMonitor(monitor, 1));
0981: fCachedMembersReferences.put(member, engine.getResults());
0982: }
0983: final SearchResultGroup[] groups = (SearchResultGroup[]) fCachedMembersReferences
0984: .get(member);
0985: if (groups.length == 0)
0986: return false;
0987: else if (groups.length > 1)
0988: return true;
0989: final ICompilationUnit unit = groups[0].getCompilationUnit();
0990: if (!getDeclaringType().getCompilationUnit().equals(unit))
0991: return true;
0992: final SearchMatch[] matches = groups[0].getSearchResults();
0993: for (int index = 0; index < matches.length; index++) {
0994: if (!isMovedReference(matches[index]))
0995: return true;
0996: }
0997: return false;
0998: }
0999:
1000: protected boolean isMovedReference(final SearchMatch match)
1001: throws JavaModelException {
1002: ISourceRange range = null;
1003: for (int index = 0; index < fMembersToMove.length; index++) {
1004: range = fMembersToMove[index].getSourceRange();
1005: if (range.getOffset() <= match.getOffset()
1006: && range.getOffset() + range.getLength() >= match
1007: .getOffset())
1008: return true;
1009: }
1010: return false;
1011: }
1012:
1013: public RefactoringParticipant[] loadParticipants(
1014: final RefactoringStatus status,
1015: final SharableParticipants sharedParticipants)
1016: throws CoreException {
1017: return new RefactoringParticipant[0];
1018: }
1019:
1020: protected boolean needsVisibilityAdjustment(final IMember member,
1021: final boolean references, final IProgressMonitor monitor,
1022: final RefactoringStatus status) throws JavaModelException {
1023: if (JdtFlags.isPublic(member) || JdtFlags.isProtected(member))
1024: return false;
1025: if (!references)
1026: return true;
1027: return hasNonMovedReferences(member, monitor, status);
1028: }
1029: }
|