1 /*******************************************************************************
2 * Copyright (c) 2006, 2012 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.corext.refactoring.structure;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.HashMap;
16 import java.util.Iterator;
17 import java.util.List;
20 import org.eclipse.core.runtime.Assert;
21 import org.eclipse.core.runtime.CoreException;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.NullProgressMonitor;
24 import org.eclipse.core.runtime.SubProgressMonitor;
26 import org.eclipse.text.edits.MalformedTreeException;
27 import org.eclipse.text.edits.TextEdit;
29 import org.eclipse.jface.text.BadLocationException;
30 import org.eclipse.jface.text.Document;
31 import org.eclipse.jface.text.IDocument;
33 import org.eclipse.ltk.core.refactoring.GroupCategorySet;
34 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
35 import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
36 import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
37 import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
39 import org.eclipse.jdt.core.Flags;
40 import org.eclipse.jdt.core.ICompilationUnit;
41 import org.eclipse.jdt.core.IField;
42 import org.eclipse.jdt.core.IInitializer;
43 import org.eclipse.jdt.core.IJavaElement;
44 import org.eclipse.jdt.core.IMember;
45 import org.eclipse.jdt.core.IMethod;
46 import org.eclipse.jdt.core.ISourceRange;
47 import org.eclipse.jdt.core.IType;
48 import org.eclipse.jdt.core.ITypeHierarchy;
49 import org.eclipse.jdt.core.JavaModelException;
50 import org.eclipse.jdt.core.dom.AST;
51 import org.eclipse.jdt.core.dom.ASTNode;
52 import org.eclipse.jdt.core.dom.ASTVisitor;
53 import org.eclipse.jdt.core.dom.Annotation;
54 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
55 import org.eclipse.jdt.core.dom.BodyDeclaration;
56 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
57 import org.eclipse.jdt.core.dom.CompilationUnit;
58 import org.eclipse.jdt.core.dom.EnumDeclaration;
59 import org.eclipse.jdt.core.dom.Expression;
60 import org.eclipse.jdt.core.dom.FieldDeclaration;
61 import org.eclipse.jdt.core.dom.IExtendedModifier;
62 import org.eclipse.jdt.core.dom.IMethodBinding;
63 import org.eclipse.jdt.core.dom.ITypeBinding;
64 import org.eclipse.jdt.core.dom.Javadoc;
65 import org.eclipse.jdt.core.dom.MethodDeclaration;
66 import org.eclipse.jdt.core.dom.Modifier;
67 import org.eclipse.jdt.core.dom.Name;
68 import org.eclipse.jdt.core.dom.SimpleName;
69 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
70 import org.eclipse.jdt.core.dom.Type;
71 import org.eclipse.jdt.core.dom.TypeDeclaration;
72 import org.eclipse.jdt.core.dom.TypeParameter;
73 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
74 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
75 import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition;
76 import org.eclipse.jdt.core.search.IJavaSearchConstants;
77 import org.eclipse.jdt.core.search.SearchMatch;
78 import org.eclipse.jdt.core.search.SearchPattern;
80 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
81 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
82 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
83 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
84 import org.eclipse.jdt.internal.corext.dom.ModifierRewrite;
85 import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
86 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
87 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2;
88 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
89 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
90 import org.eclipse.jdt.internal.corext.refactoring.reorg.SourceReferenceUtil;
91 import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsModel;
92 import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsSolver;
93 import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor;
94 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
95 import org.eclipse.jdt.internal.corext.refactoring.util.TextEditBasedChangeManager;
96 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
97 import org.eclipse.jdt.internal.corext.util.JdtFlags;
98 import org.eclipse.jdt.internal.corext.util.Messages;
99 import org.eclipse.jdt.internal.corext.util.SearchUtils;
100 import org.eclipse.jdt.internal.corext.util.Strings;
102 import org.eclipse.jdt.ui.JavaElementLabels;
104 import org.eclipse.jdt.internal.ui.JavaPlugin;
107 * Partial implementation of a hierarchy refactoring processor used in pull up,
108 * push down and extract supertype refactorings.
110 * This processor provides common functionality to move members in a type
111 * hierarchy, and to perform a "Use Supertype" refactoring afterwards.
116 public abstract class HierarchyProcessor extends SuperTypeRefactoringProcessor {
119 * AST node visitor which performs the actual mapping.
121 public static class TypeVariableMapper extends ASTVisitor {
123 /** The type variable mapping to use */
124 protected final TypeVariableMaplet[] fMapping;
126 /** The AST rewrite to use */
127 protected final ASTRewrite fRewrite;
130 * Creates a new type variable mapper.
133 * The AST rewrite to use
135 * The type variable mapping to use
137 public TypeVariableMapper(final ASTRewrite rewrite, final TypeVariableMaplet[] mapping) {
138 Assert.isNotNull(rewrite);
139 Assert.isNotNull(mapping);
145 public final boolean visit(final SimpleName node) {
146 final ITypeBinding binding= node.resolveTypeBinding();
147 if (binding != null && binding.isTypeVariable()) {
149 for (int index= 0; index < fMapping.length; index++) {
150 name= binding.getName();
151 if (fMapping[index].getSourceName().equals(name) && node.getIdentifier().equals(name)) {
152 final MethodDeclaration declaration= (MethodDeclaration) ASTNodes.getParent(node, MethodDeclaration.class);
153 if (declaration != null) {
154 final IMethodBinding method= declaration.resolveBinding();
155 if (method != null) {
156 final ITypeBinding[] bindings= method.getTypeParameters();
157 for (int offset= 0; offset < bindings.length; offset++) {
158 if (bindings[offset].isEqualTo(binding))
163 fRewrite.set(node, SimpleName.IDENTIFIER_PROPERTY, fMapping[index].getTargetName(), null);
171 protected static boolean areAllFragmentsDeleted(final FieldDeclaration declaration, final List<ASTNode> declarationNodes) {
172 for (final Iterator<VariableDeclarationFragment> iterator= declaration.fragments().iterator(); iterator.hasNext();) {
173 if (!declarationNodes.contains(iterator.next()))
179 protected static RefactoringStatus checkProjectCompliance(CompilationUnitRewrite sourceRewriter, IType destination, IMember[] members) {
180 RefactoringStatus status= new RefactoringStatus();
181 if (!JavaModelUtil.is50OrHigher(destination.getJavaProject())) {
182 for (int index= 0; index < members.length; index++) {
184 BodyDeclaration decl= ASTNodeSearchUtil.getBodyDeclarationNode(members[index], sourceRewriter.getRoot());
186 for (final Iterator<IExtendedModifier> iterator= decl.modifiers().iterator(); iterator.hasNext();) {
187 boolean reported= false;
188 final IExtendedModifier modifier= iterator.next();
189 if (!reported && modifier.isAnnotation()) {
190 status.merge(RefactoringStatus.createErrorStatus(Messages.format(RefactoringCoreMessages.PullUpRefactoring_incompatible_langauge_constructs, new String[] { JavaElementLabels.getTextLabel(members[index], JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getTextLabel(destination, JavaElementLabels.ALL_DEFAULT)}), JavaStatusContext.create(members[index])));
195 } catch (JavaModelException exception) {
196 JavaPlugin.log(exception);
198 if (members[index] instanceof IMethod) {
199 final IMethod method= (IMethod) members[index];
201 if (Flags.isVarargs(method.getFlags()))
202 status.merge(RefactoringStatus.createErrorStatus(Messages.format(RefactoringCoreMessages.PullUpRefactoring_incompatible_language_constructs1, new String[] { JavaElementLabels.getTextLabel(members[index], JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getTextLabel(destination, JavaElementLabels.ALL_DEFAULT)}), JavaStatusContext.create(members[index])));
203 } catch (JavaModelException exception) {
204 JavaPlugin.log(exception);
212 protected static void copyAnnotations(final FieldDeclaration oldField, final FieldDeclaration newField) {
213 final AST ast= newField.getAST();
214 for (int index= 0, n= oldField.modifiers().size(); index < n; index++) {
215 final IExtendedModifier modifier= (IExtendedModifier) oldField.modifiers().get(index);
216 final List<IExtendedModifier> modifiers= newField.modifiers();
217 if (modifier.isAnnotation() && !modifiers.contains(modifier))
218 modifiers.add((IExtendedModifier) ASTNode.copySubtree(ast, (Annotation) modifier));
222 protected static void copyAnnotations(final MethodDeclaration oldMethod, final MethodDeclaration newMethod) {
223 final AST ast= newMethod.getAST();
224 for (int index= 0, n= oldMethod.modifiers().size(); index < n; index++) {
225 final IExtendedModifier modifier= (IExtendedModifier) oldMethod.modifiers().get(index);
226 final List<IExtendedModifier> modifiers= newMethod.modifiers();
227 if (modifier.isAnnotation() && !modifiers.contains(modifier))
228 modifiers.add((IExtendedModifier) ASTNode.copySubtree(ast, (Annotation) modifier));
232 protected static void copyJavadocNode(final ASTRewrite rewrite, final BodyDeclaration oldDeclaration, final BodyDeclaration newDeclaration) throws JavaModelException {
233 final Javadoc predecessor= oldDeclaration.getJavadoc();
234 if (predecessor != null) {
235 String newString= ASTNodes.getNodeSource(predecessor, false, true);
236 if (newString != null) {
237 newDeclaration.setJavadoc((Javadoc) rewrite.createStringPlaceholder(newString, ASTNode.JAVADOC));
242 protected static void copyThrownExceptions(final MethodDeclaration oldMethod, final MethodDeclaration newMethod) {
243 final AST ast= newMethod.getAST();
244 for (int index= 0, n= oldMethod.thrownExceptions().size(); index < n; index++)
245 newMethod.thrownExceptions().add(ASTNode.copySubtree(ast, (Name) oldMethod.thrownExceptions().get(index)));
248 protected static void copyTypeParameters(final MethodDeclaration oldMethod, final MethodDeclaration newMethod) {
249 final AST ast= newMethod.getAST();
250 for (int index= 0, n= oldMethod.typeParameters().size(); index < n; index++)
251 newMethod.typeParameters().add(ASTNode.copySubtree(ast, (TypeParameter) oldMethod.typeParameters().get(index)));
254 protected static String createLabel(final IMember member) {
255 if (member instanceof IType)
256 return JavaElementLabels.getTextLabel(member, JavaElementLabels.ALL_FULLY_QUALIFIED);
257 else if (member instanceof IMethod)
258 return JavaElementLabels.getTextLabel(member, JavaElementLabels.ALL_FULLY_QUALIFIED);
259 else if (member instanceof IField)
260 return JavaElementLabels.getTextLabel(member, JavaElementLabels.ALL_FULLY_QUALIFIED);
261 else if (member instanceof IInitializer)
262 return RefactoringCoreMessages.HierarchyRefactoring_initializer;
263 Assert.isTrue(false);
267 protected static FieldDeclaration createNewFieldDeclarationNode(final ASTRewrite rewrite, final CompilationUnit unit, final IField field, final VariableDeclarationFragment oldFieldFragment, final TypeVariableMaplet[] mapping, final IProgressMonitor monitor, final RefactoringStatus status, final int modifiers) throws JavaModelException {
268 final VariableDeclarationFragment newFragment= rewrite.getAST().newVariableDeclarationFragment();
269 newFragment.setExtraDimensions(oldFieldFragment.getExtraDimensions());
270 if (oldFieldFragment.getInitializer() != null) {
271 Expression newInitializer= null;
272 if (mapping.length > 0)
273 newInitializer= createPlaceholderForExpression(oldFieldFragment.getInitializer(), field.getCompilationUnit(), mapping, rewrite);
275 newInitializer= createPlaceholderForExpression(oldFieldFragment.getInitializer(), field.getCompilationUnit(), rewrite);
276 newFragment.setInitializer(newInitializer);
278 newFragment.setName(((SimpleName) ASTNode.copySubtree(rewrite.getAST(), oldFieldFragment.getName())));
279 final FieldDeclaration newField= rewrite.getAST().newFieldDeclaration(newFragment);
280 final FieldDeclaration oldField= ASTNodeSearchUtil.getFieldDeclarationNode(field, unit);
281 copyJavadocNode(rewrite, oldField, newField);
282 copyAnnotations(oldField, newField);
283 newField.modifiers().addAll(ASTNodeFactory.newModifiers(rewrite.getAST(), modifiers));
284 final Type oldType= oldField.getType();
286 if (mapping.length > 0) {
287 newType= createPlaceholderForType(oldType, field.getCompilationUnit(), mapping, rewrite);
289 newType= createPlaceholderForType(oldType, field.getCompilationUnit(), rewrite);
290 newField.setType(newType);
294 protected static Expression createPlaceholderForExpression(final Expression expression, final ICompilationUnit declaringCu, final ASTRewrite rewrite) throws JavaModelException {
295 return (Expression) rewrite.createStringPlaceholder(declaringCu.getBuffer().getText(expression.getStartPosition(), expression.getLength()), ASTNode.METHOD_INVOCATION);
298 protected static Expression createPlaceholderForExpression(final Expression expression, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite) throws JavaModelException {
299 Expression result= null;
301 final IDocument document= new Document(declaringCu.getBuffer().getContents());
302 final ASTRewrite rewriter= ASTRewrite.create(expression.getAST());
303 final ITrackedNodePosition position= rewriter.track(expression);
304 expression.accept(new TypeVariableMapper(rewriter, mapping));
305 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
306 result= (Expression) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.METHOD_INVOCATION);
307 } catch (MalformedTreeException exception) {
308 JavaPlugin.log(exception);
309 } catch (BadLocationException exception) {
310 JavaPlugin.log(exception);
315 protected static BodyDeclaration createPlaceholderForProtectedTypeDeclaration(final BodyDeclaration bodyDeclaration, final CompilationUnit declaringCuNode, final ICompilationUnit declaringCu, final ASTRewrite rewrite, final boolean removeIndentation) throws JavaModelException {
318 final ASTRewrite rewriter= ASTRewrite.create(bodyDeclaration.getAST());
319 ModifierRewrite.create(rewriter, bodyDeclaration).setVisibility(Modifier.PROTECTED, null);
320 final ITrackedNodePosition position= rewriter.track(bodyDeclaration);
321 final IDocument document= new Document(declaringCu.getBuffer().getText(declaringCuNode.getStartPosition(), declaringCuNode.getLength()));
322 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
323 text= document.get(position.getStartPosition(), position.getLength());
324 } catch (BadLocationException exception) {
325 text= getNewText(bodyDeclaration, declaringCu, removeIndentation);
327 return (BodyDeclaration) rewrite.createStringPlaceholder(text, ASTNode.TYPE_DECLARATION);
330 protected static BodyDeclaration createPlaceholderForProtectedTypeDeclaration(final BodyDeclaration bodyDeclaration, final CompilationUnit declaringCuNode, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite, final boolean removeIndentation) throws JavaModelException {
331 BodyDeclaration result= null;
333 final IDocument document= new Document(declaringCu.getBuffer().getContents());
334 final ASTRewrite rewriter= ASTRewrite.create(bodyDeclaration.getAST());
335 final ITrackedNodePosition position= rewriter.track(bodyDeclaration);
336 bodyDeclaration.accept(new TypeVariableMapper(rewriter, mapping) {
339 public final boolean visit(final AnnotationTypeDeclaration node) {
340 ModifierRewrite.create(fRewrite, bodyDeclaration).setVisibility(Modifier.PROTECTED, null);
345 public final boolean visit(final EnumDeclaration node) {
346 ModifierRewrite.create(fRewrite, bodyDeclaration).setVisibility(Modifier.PROTECTED, null);
351 public final boolean visit(final TypeDeclaration node) {
352 ModifierRewrite.create(fRewrite, bodyDeclaration).setVisibility(Modifier.PROTECTED, null);
356 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
357 result= (BodyDeclaration) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.TYPE_DECLARATION);
358 } catch (MalformedTreeException exception) {
359 JavaPlugin.log(exception);
360 } catch (BadLocationException exception) {
361 JavaPlugin.log(exception);
366 protected static SingleVariableDeclaration createPlaceholderForSingleVariableDeclaration(final SingleVariableDeclaration declaration, final ICompilationUnit declaringCu, final ASTRewrite rewrite) throws JavaModelException {
367 return (SingleVariableDeclaration) rewrite.createStringPlaceholder(declaringCu.getBuffer().getText(declaration.getStartPosition(), declaration.getLength()), ASTNode.SINGLE_VARIABLE_DECLARATION);
370 protected static SingleVariableDeclaration createPlaceholderForSingleVariableDeclaration(final SingleVariableDeclaration declaration, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite) throws JavaModelException {
371 SingleVariableDeclaration result= null;
373 final IDocument document= new Document(declaringCu.getBuffer().getContents());
374 final ASTRewrite rewriter= ASTRewrite.create(declaration.getAST());
375 final ITrackedNodePosition position= rewriter.track(declaration);
376 declaration.accept(new TypeVariableMapper(rewriter, mapping));
377 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
378 result= (SingleVariableDeclaration) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.SINGLE_VARIABLE_DECLARATION);
379 } catch (MalformedTreeException exception) {
380 JavaPlugin.log(exception);
381 } catch (BadLocationException exception) {
382 JavaPlugin.log(exception);
387 protected static Type createPlaceholderForType(final Type type, final ICompilationUnit declaringCu, final ASTRewrite rewrite) throws JavaModelException {
388 return (Type) rewrite.createStringPlaceholder(declaringCu.getBuffer().getText(type.getStartPosition(), type.getLength()), ASTNode.SIMPLE_TYPE);
391 protected static Type createPlaceholderForType(final Type type, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite) throws JavaModelException {
394 final IDocument document= new Document(declaringCu.getBuffer().getContents());
395 final ASTRewrite rewriter= ASTRewrite.create(type.getAST());
396 final ITrackedNodePosition position= rewriter.track(type);
397 type.accept(new TypeVariableMapper(rewriter, mapping));
398 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
399 result= (Type) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.SIMPLE_TYPE);
400 } catch (MalformedTreeException exception) {
401 JavaPlugin.log(exception);
402 } catch (BadLocationException exception) {
403 JavaPlugin.log(exception);
408 protected static BodyDeclaration createPlaceholderForTypeDeclaration(final BodyDeclaration bodyDeclaration, final ICompilationUnit declaringCu, final ASTRewrite rewrite, final boolean removeIndentation) throws JavaModelException {
409 return (BodyDeclaration) rewrite.createStringPlaceholder(getNewText(bodyDeclaration, declaringCu, removeIndentation), ASTNode.TYPE_DECLARATION);
412 protected static BodyDeclaration createPlaceholderForTypeDeclaration(final BodyDeclaration bodyDeclaration, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite, final boolean removeIndentation) throws JavaModelException {
413 BodyDeclaration result= null;
415 final IDocument document= new Document(declaringCu.getBuffer().getContents());
416 final ASTRewrite rewriter= ASTRewrite.create(bodyDeclaration.getAST());
417 final ITrackedNodePosition position= rewriter.track(bodyDeclaration);
418 bodyDeclaration.accept(new TypeVariableMapper(rewriter, mapping));
419 rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
420 result= (BodyDeclaration) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.TYPE_DECLARATION);
421 } catch (MalformedTreeException exception) {
422 JavaPlugin.log(exception);
423 } catch (BadLocationException exception) {
424 JavaPlugin.log(exception);
429 protected static void deleteDeclarationNodes(final CompilationUnitRewrite sourceRewriter, final boolean sameCu, final CompilationUnitRewrite unitRewriter, final List<IMember> members, final GroupCategorySet set) throws JavaModelException {
430 final List<ASTNode> declarationNodes= getDeclarationNodes(unitRewriter.getRoot(), members);
431 for (final Iterator<ASTNode> iterator= declarationNodes.iterator(); iterator.hasNext();) {
432 final ASTNode node= iterator.next();
433 final ASTRewrite rewriter= unitRewriter.getASTRewrite();
434 final ImportRemover remover= unitRewriter.getImportRemover();
435 if (node instanceof VariableDeclarationFragment) {
436 if (node.getParent() instanceof FieldDeclaration) {
437 final FieldDeclaration declaration= (FieldDeclaration) node.getParent();
438 if (areAllFragmentsDeleted(declaration, declarationNodes)) {
439 rewriter.remove(declaration, unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_remove_member, set));
441 remover.registerRemovedNode(declaration);
443 rewriter.remove(node, unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_remove_member, set));
445 remover.registerRemovedNode(node);
449 rewriter.remove(node, unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_remove_member, set));
451 remover.registerRemovedNode(node);
456 protected static List<ASTNode> getDeclarationNodes(final CompilationUnit cuNode, final List<IMember> members) throws JavaModelException {
457 final List<ASTNode> result= new ArrayList<ASTNode>(members.size());
458 for (final Iterator<IMember> iterator= members.iterator(); iterator.hasNext();) {
459 final IMember member= iterator.next();
461 if (member instanceof IField) {
462 if (Flags.isEnum(member.getFlags()))
463 node= ASTNodeSearchUtil.getEnumConstantDeclaration((IField) member, cuNode);
465 node= ASTNodeSearchUtil.getFieldDeclarationFragmentNode((IField) member, cuNode);
466 } else if (member instanceof IType)
467 node= ASTNodeSearchUtil.getAbstractTypeDeclarationNode((IType) member, cuNode);
468 else if (member instanceof IMethod)
469 node= ASTNodeSearchUtil.getMethodDeclarationNode((IMethod) member, cuNode);
476 protected static String getNewText(final ASTNode node, final ICompilationUnit declaringCu, final boolean removeIndentation) throws JavaModelException {
477 final String result= declaringCu.getBuffer().getText(node.getStartPosition(), node.getLength());
478 if (removeIndentation)
479 return getUnindentedText(result, declaringCu);
484 protected static String getUnindentedText(final String text, final ICompilationUnit declaringCu) throws JavaModelException {
485 final String[] lines= Strings.convertIntoLines(text);
486 Strings.trimIndentation(lines, declaringCu.getJavaProject(), false);
487 return Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(declaringCu));
490 /** The cached declaring type */
491 protected IType fCachedDeclaringType;
493 /** The cached member references */
494 public final Map<IMember, Object[]> fCachedMembersReferences= new HashMap<IMember, Object[]>(2);
496 /** The cached type references */
497 protected IType[] fCachedReferencedTypes;
499 /** The text edit based change manager */
500 protected TextEditBasedChangeManager fChangeManager;
502 /** Does the refactoring use a working copy layer? */
503 protected final boolean fLayer;
505 /** The members to move (may be in working copies) */
506 protected IMember[] fMembersToMove;
509 * Creates a new hierarchy processor.
512 * the members, or <code>null</code> if invoked by scripting
514 * the code generation settings to use
516 * <code>true</code> to create a working copy layer,
517 * <code>false</code> otherwise
519 protected HierarchyProcessor(final IMember[] members, final CodeGenerationSettings settings, boolean layer) {
522 if (members != null) {
523 fMembersToMove= (IMember[]) SourceReferenceUtil.sortByOffset(members);
524 if (layer && fMembersToMove.length > 0) {
525 final ICompilationUnit original= fMembersToMove[0].getCompilationUnit();
526 if (original != null) {
528 final ICompilationUnit copy= getSharedWorkingCopy(original.getPrimary(), new NullProgressMonitor());
530 for (int index= 0; index < fMembersToMove.length; index++) {
531 final IJavaElement[] elements= copy.findElements(fMembersToMove[index]);
532 if (elements != null && elements.length > 0 && elements[0] instanceof IMember) {
533 fMembersToMove[index]= (IMember) elements[0];
537 } catch (JavaModelException exception) {
538 JavaPlugin.log(exception);
545 protected boolean canBeAccessedFrom(final IMember member, final IType target, final ITypeHierarchy hierarchy) throws JavaModelException {
546 Assert.isTrue(!(member instanceof IInitializer));
547 return member.exists();
550 protected RefactoringStatus checkConstructorCalls(final IType type, final IProgressMonitor monitor) throws JavaModelException {
552 monitor.beginTask(RefactoringCoreMessages.PullUpRefactoring_checking, 2);
553 final RefactoringStatus result= new RefactoringStatus();
554 final SearchResultGroup[] groups= ConstructorReferenceFinder.getConstructorReferences(type, fOwner, new SubProgressMonitor(monitor, 1), result);
555 final String message= Messages.format(RefactoringCoreMessages.HierarchyRefactoring_gets_instantiated, new Object[] { JavaElementLabels.getTextLabel(type, JavaElementLabels.ALL_FULLY_QUALIFIED)});
557 ICompilationUnit unit= null;
558 for (int index= 0; index < groups.length; index++) {
559 unit= groups[index].getCompilationUnit();
561 final CompilationUnit cuNode= RefactoringASTParser.parseWithASTProvider(unit, false, new SubProgressMonitor(monitor, 1));
562 final ASTNode[] references= ASTNodeSearchUtil.getAstNodes(groups[index].getSearchResults(), cuNode);
564 for (int offset= 0; offset < references.length; offset++) {
565 node= references[offset];
566 if ((node instanceof ClassInstanceCreation) || ConstructorReferenceFinder.isImplicitConstructorReferenceNodeInClassCreations(node)) {
567 final RefactoringStatusContext context= JavaStatusContext.create(unit, node);
568 result.addError(message, context);
579 protected RefactoringStatus checkDeclaringType(final IProgressMonitor monitor) throws JavaModelException {
581 final IType type= getDeclaringType();
583 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_enum_members);
584 if (type.isAnnotation())
585 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_annotation_members);
586 if (type.isInterface())
587 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_interface_members);
589 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_members_of_binary);
590 if (type.isReadOnly())
591 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.HierarchyRefactoring_members_of_read_only);
592 return new RefactoringStatus();
599 protected RefactoringStatus checkIfMembersExist() {
600 final RefactoringStatus result= new RefactoringStatus();
601 IMember member= null;
602 for (int index= 0; index < fMembersToMove.length; index++) {
603 member= fMembersToMove[index];
604 if (member == null || !member.exists())
605 result.addFatalError(RefactoringCoreMessages.HierarchyRefactoring_does_not_exist);
610 protected void clearCaches() {
611 fCachedReferencedTypes= null;
614 protected void copyParameters(final ASTRewrite rewrite, final ICompilationUnit unit, final MethodDeclaration oldMethod, final MethodDeclaration newMethod, final TypeVariableMaplet[] mapping) throws JavaModelException {
615 SingleVariableDeclaration newDeclaration= null;
616 for (int index= 0, size= oldMethod.parameters().size(); index < size; index++) {
617 final SingleVariableDeclaration oldDeclaration= (SingleVariableDeclaration) oldMethod.parameters().get(index);
618 if (mapping.length > 0)
619 newDeclaration= createPlaceholderForSingleVariableDeclaration(oldDeclaration, unit, mapping, rewrite);
621 newDeclaration= createPlaceholderForSingleVariableDeclaration(oldDeclaration, unit, rewrite);
622 newMethod.parameters().add(newDeclaration);
626 protected void copyReturnType(final ASTRewrite rewrite, final ICompilationUnit unit, final MethodDeclaration oldMethod, final MethodDeclaration newMethod, final TypeVariableMaplet[] mapping) throws JavaModelException {
627 Type newReturnType= null;
628 if (mapping.length > 0)
629 newReturnType= createPlaceholderForType(oldMethod.getReturnType2(), unit, mapping, rewrite);
631 newReturnType= createPlaceholderForType(oldMethod.getReturnType2(), unit, rewrite);
632 newMethod.setReturnType2(newReturnType);
636 protected SuperTypeConstraintsSolver createContraintSolver(final SuperTypeConstraintsModel model) {
637 return new SuperTypeConstraintsSolver(model);
640 public IType getDeclaringType() {
641 if (fCachedDeclaringType != null)
642 return fCachedDeclaringType;
643 fCachedDeclaringType= RefactoringAvailabilityTester.getTopLevelType(fMembersToMove);
644 if (fCachedDeclaringType == null)
645 fCachedDeclaringType= fMembersToMove[0].getDeclaringType();
646 return fCachedDeclaringType;
649 public IMember[] getMembersToMove() {
650 return fMembersToMove;
653 protected IType[] getTypesReferencedInMovedMembers(final IProgressMonitor monitor) throws JavaModelException {
654 if (fCachedReferencedTypes == null) {
655 final IType[] types= ReferenceFinderUtil.getTypesReferencedIn(fMembersToMove, fOwner, monitor);
656 final List<IType> result= new ArrayList<IType>(types.length);
657 final List<IMember> members= Arrays.asList(fMembersToMove);
658 for (int index= 0; index < types.length; index++) {
659 if (!members.contains(types[index]) && !types[index].equals(getDeclaringType()))
660 result.add(types[index]);
662 fCachedReferencedTypes= new IType[result.size()];
663 result.toArray(fCachedReferencedTypes);
665 return fCachedReferencedTypes;
668 protected boolean hasNonMovedReferences(final IMember member, final IProgressMonitor monitor, final RefactoringStatus status) throws JavaModelException {
669 if (!fCachedMembersReferences.containsKey(member)) {
670 final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(member, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE));
671 engine.generated_5514864496594404436(member, monitor, status, this);
673 final SearchResultGroup[] groups= (SearchResultGroup[]) fCachedMembersReferences.get(member);
674 if (groups.length == 0)
676 else if (groups.length > 1)
678 final ICompilationUnit unit= groups[0].getCompilationUnit();
679 if (!getDeclaringType().getCompilationUnit().equals(unit))
681 final SearchMatch[] matches= groups[0].getSearchResults();
682 for (int index= 0; index < matches.length; index++) {
683 if (!isMovedReference(matches[index]))
689 protected boolean isMovedReference(final SearchMatch match) throws JavaModelException {
690 ISourceRange range= null;
691 for (int index= 0; index < fMembersToMove.length; index++) {
692 range= fMembersToMove[index].getSourceRange();
693 if (range.getOffset() <= match.getOffset() && range.getOffset() + range.getLength() >= match.getOffset())
700 public RefactoringParticipant[] loadParticipants(final RefactoringStatus status, final SharableParticipants sharedParticipants) throws CoreException {
701 return new RefactoringParticipant[0];
704 protected boolean needsVisibilityAdjustment(final IMember member, final boolean references, final IProgressMonitor monitor, final RefactoringStatus status) throws JavaModelException {
705 if (JdtFlags.isPublic(member) || JdtFlags.isProtected(member))
709 return hasNonMovedReferences(member, monitor, status);