]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-after/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/HierarchyProcessor.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / core refactoring / org / eclipse / jdt / internal / corext / refactoring / structure / HierarchyProcessor.java
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
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.corext.refactoring.structure;
12
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;
18 import java.util.Map;
19
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;
25
26 import org.eclipse.text.edits.MalformedTreeException;
27 import org.eclipse.text.edits.TextEdit;
28
29 import org.eclipse.jface.text.BadLocationException;
30 import org.eclipse.jface.text.Document;
31 import org.eclipse.jface.text.IDocument;
32
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;
38
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;
79
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;
101
102 import org.eclipse.jdt.ui.JavaElementLabels;
103
104 import org.eclipse.jdt.internal.ui.JavaPlugin;
105
106 /**
107  * Partial implementation of a hierarchy refactoring processor used in pull up,
108  * push down and extract supertype refactorings.
109  * <p>
110  * This processor provides common functionality to move members in a type
111  * hierarchy, and to perform a "Use Supertype" refactoring afterwards.
112  * </p>
113  *
114  * @since 3.2
115  */
116 public abstract class HierarchyProcessor extends SuperTypeRefactoringProcessor {
117
118         /**
119          * AST node visitor which performs the actual mapping.
120          */
121         public static class TypeVariableMapper extends ASTVisitor {
122
123                 /** The type variable mapping to use */
124                 protected final TypeVariableMaplet[] fMapping;
125
126                 /** The AST rewrite to use */
127                 protected final ASTRewrite fRewrite;
128
129                 /**
130                  * Creates a new type variable mapper.
131                  *
132                  * @param rewrite
133                  *            The AST rewrite to use
134                  * @param mapping
135                  *            The type variable mapping to use
136                  */
137                 public TypeVariableMapper(final ASTRewrite rewrite, final TypeVariableMaplet[] mapping) {
138                         Assert.isNotNull(rewrite);
139                         Assert.isNotNull(mapping);
140                         fRewrite= rewrite;
141                         fMapping= mapping;
142                 }
143
144                 @Override
145                 public final boolean visit(final SimpleName node) {
146                         final ITypeBinding binding= node.resolveTypeBinding();
147                         if (binding != null && binding.isTypeVariable()) {
148                                 String name= null;
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))
159                                                                                 return true;
160                                                                 }
161                                                         }
162                                                 }
163                                                 fRewrite.set(node, SimpleName.IDENTIFIER_PROPERTY, fMapping[index].getTargetName(), null);
164                                         }
165                                 }
166                         }
167                         return true;
168                 }
169         }
170
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()))
174                                 return false;
175                 }
176                 return true;
177         }
178
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++) {
183                                 try {
184                                         BodyDeclaration decl= ASTNodeSearchUtil.getBodyDeclarationNode(members[index], sourceRewriter.getRoot());
185                                         if (decl != null) {
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])));
191                                                                 reported= true;
192                                                         }
193                                                 }
194                                         }
195                                 } catch (JavaModelException exception) {
196                                         JavaPlugin.log(exception);
197                                 }
198                                 if (members[index] instanceof IMethod) {
199                                         final IMethod method= (IMethod) members[index];
200                                         try {
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);
205                                         }
206                                 }
207                         }
208                 }
209                 return status;
210         }
211
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));
219                 }
220         }
221
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));
229                 }
230         }
231
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));
238                         }
239                 }
240         }
241
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)));
246         }
247
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)));
252         }
253
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);
264                 return null;
265         }
266
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);
274                         else
275                                 newInitializer= createPlaceholderForExpression(oldFieldFragment.getInitializer(), field.getCompilationUnit(), rewrite);
276                         newFragment.setInitializer(newInitializer);
277                 }
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();
285                 Type newType= null;
286                 if (mapping.length > 0) {
287                         newType= createPlaceholderForType(oldType, field.getCompilationUnit(), mapping, rewrite);
288                 } else
289                         newType= createPlaceholderForType(oldType, field.getCompilationUnit(), rewrite);
290                 newField.setType(newType);
291                 return newField;
292         }
293
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);
296         }
297
298         protected static Expression createPlaceholderForExpression(final Expression expression, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite) throws JavaModelException {
299                 Expression result= null;
300                 try {
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);
311                 }
312                 return result;
313         }
314
315         protected static BodyDeclaration createPlaceholderForProtectedTypeDeclaration(final BodyDeclaration bodyDeclaration, final CompilationUnit declaringCuNode, final ICompilationUnit declaringCu, final ASTRewrite rewrite, final boolean removeIndentation) throws JavaModelException {
316                 String text= null;
317                 try {
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);
326                 }
327                 return (BodyDeclaration) rewrite.createStringPlaceholder(text, ASTNode.TYPE_DECLARATION);
328         }
329
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;
332                 try {
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) {
337
338                                 @Override
339                                 public final boolean visit(final AnnotationTypeDeclaration node) {
340                                         ModifierRewrite.create(fRewrite, bodyDeclaration).setVisibility(Modifier.PROTECTED, null);
341                                         return true;
342                                 }
343
344                                 @Override
345                                 public final boolean visit(final EnumDeclaration node) {
346                                         ModifierRewrite.create(fRewrite, bodyDeclaration).setVisibility(Modifier.PROTECTED, null);
347                                         return true;
348                                 }
349
350                                 @Override
351                                 public final boolean visit(final TypeDeclaration node) {
352                                         ModifierRewrite.create(fRewrite, bodyDeclaration).setVisibility(Modifier.PROTECTED, null);
353                                         return true;
354                                 }
355                         });
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);
362                 }
363                 return result;
364         }
365
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);
368         }
369
370         protected static SingleVariableDeclaration createPlaceholderForSingleVariableDeclaration(final SingleVariableDeclaration declaration, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite) throws JavaModelException {
371                 SingleVariableDeclaration result= null;
372                 try {
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);
383                 }
384                 return result;
385         }
386
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);
389         }
390
391         protected static Type createPlaceholderForType(final Type type, final ICompilationUnit declaringCu, final TypeVariableMaplet[] mapping, final ASTRewrite rewrite) throws JavaModelException {
392                 Type result= null;
393                 try {
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);
404                 }
405                 return result;
406         }
407
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);
410         }
411
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;
414                 try {
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);
425                 }
426                 return result;
427         }
428
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));
440                                                 if (!sameCu)
441                                                         remover.registerRemovedNode(declaration);
442                                         } else {
443                                                 rewriter.remove(node, unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_remove_member, set));
444                                                 if (!sameCu)
445                                                         remover.registerRemovedNode(node);
446                                         }
447                                 }
448                         } else {
449                                 rewriter.remove(node, unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_remove_member, set));
450                                 if (!sameCu)
451                                         remover.registerRemovedNode(node);
452                         }
453                 }
454         }
455
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();
460                         ASTNode node= null;
461                         if (member instanceof IField) {
462                                 if (Flags.isEnum(member.getFlags()))
463                                         node= ASTNodeSearchUtil.getEnumConstantDeclaration((IField) member, cuNode);
464                                 else
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);
470                         if (node != null)
471                                 result.add(node);
472                 }
473                 return result;
474         }
475
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);
480
481                 return result;
482         }
483
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));
488         }
489
490         /** The cached declaring type */
491         protected IType fCachedDeclaringType;
492
493         /** The cached member references */
494         public final Map<IMember, Object[]> fCachedMembersReferences= new HashMap<IMember, Object[]>(2);
495
496         /** The cached type references */
497         protected IType[] fCachedReferencedTypes;
498
499         /** The text edit based change manager */
500         protected TextEditBasedChangeManager fChangeManager;
501
502         /** Does the refactoring use a working copy layer? */
503         protected final boolean fLayer;
504
505         /** The members to move (may be in working copies) */
506         protected IMember[] fMembersToMove;
507
508         /**
509          * Creates a new hierarchy processor.
510          *
511          * @param members
512          *            the members, or <code>null</code> if invoked by scripting
513          * @param settings
514          *            the code generation settings to use
515          * @param layer
516          *            <code>true</code> to create a working copy layer,
517          *            <code>false</code> otherwise
518          */
519         protected HierarchyProcessor(final IMember[] members, final CodeGenerationSettings settings, boolean layer) {
520                 super(settings);
521                 fLayer= 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) {
527                                         try {
528                                                 final ICompilationUnit copy= getSharedWorkingCopy(original.getPrimary(), new NullProgressMonitor());
529                                                 if (copy != null) {
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];
534                                                                 }
535                                                         }
536                                                 }
537                                         } catch (JavaModelException exception) {
538                                                 JavaPlugin.log(exception);
539                                         }
540                                 }
541                         }
542                 }
543         }
544
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();
548         }
549
550         protected RefactoringStatus checkConstructorCalls(final IType type, final IProgressMonitor monitor) throws JavaModelException {
551                 try {
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)});
556
557                         ICompilationUnit unit= null;
558                         for (int index= 0; index < groups.length; index++) {
559                                 unit= groups[index].getCompilationUnit();
560                                 if (unit != null) {
561                                         final CompilationUnit cuNode= RefactoringASTParser.parseWithASTProvider(unit, false, new SubProgressMonitor(monitor, 1));
562                                         final ASTNode[] references= ASTNodeSearchUtil.getAstNodes(groups[index].getSearchResults(), cuNode);
563                                         ASTNode node= null;
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);
569                                                 }
570                                         }
571                                 }
572                         }
573                         return result;
574                 } finally {
575                         monitor.done();
576                 }
577         }
578
579         protected RefactoringStatus checkDeclaringType(final IProgressMonitor monitor) throws JavaModelException {
580                 try {
581                         final IType type= getDeclaringType();
582                         if (type.isEnum())
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);
588                         if (type.isBinary())
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();
593                 } finally {
594                         if (monitor != null)
595                                 monitor.done();
596                 }
597         }
598
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);
606                 }
607                 return result;
608         }
609
610         protected void clearCaches() {
611                 fCachedReferencedTypes= null;
612         }
613
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);
620                         else
621                                 newDeclaration= createPlaceholderForSingleVariableDeclaration(oldDeclaration, unit, rewrite);
622                         newMethod.parameters().add(newDeclaration);
623                 }
624         }
625
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);
630                 else
631                         newReturnType= createPlaceholderForType(oldMethod.getReturnType2(), unit, rewrite);
632                 newMethod.setReturnType2(newReturnType);
633         }
634
635         @Override
636         protected SuperTypeConstraintsSolver createContraintSolver(final SuperTypeConstraintsModel model) {
637                 return new SuperTypeConstraintsSolver(model);
638         }
639
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;
647         }
648
649         public IMember[] getMembersToMove() {
650                 return fMembersToMove;
651         }
652
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]);
661                         }
662                         fCachedReferencedTypes= new IType[result.size()];
663                         result.toArray(fCachedReferencedTypes);
664                 }
665                 return fCachedReferencedTypes;
666         }
667
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);
672                 }
673                 final SearchResultGroup[] groups= (SearchResultGroup[]) fCachedMembersReferences.get(member);
674                 if (groups.length == 0)
675                         return false;
676                 else if (groups.length > 1)
677                         return true;
678                 final ICompilationUnit unit= groups[0].getCompilationUnit();
679                 if (!getDeclaringType().getCompilationUnit().equals(unit))
680                         return true;
681                 final SearchMatch[] matches= groups[0].getSearchResults();
682                 for (int index= 0; index < matches.length; index++) {
683                         if (!isMovedReference(matches[index]))
684                                 return true;
685                 }
686                 return false;
687         }
688
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())
694                                 return true;
695                 }
696                 return false;
697         }
698
699         @Override
700         public RefactoringParticipant[] loadParticipants(final RefactoringStatus status, final SharableParticipants sharedParticipants) throws CoreException {
701                 return new RefactoringParticipant[0];
702         }
703
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))
706                         return false;
707                 if (!references)
708                         return true;
709                 return hasNonMovedReferences(member, monitor, status);
710         }
711 }