KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > structure > PushDownRefactoringProcessor


1 /*******************************************************************************
2  * Copyright (c) 2006 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 JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.util.Set JavaDoc;
22
23 import org.eclipse.text.edits.MalformedTreeException;
24 import org.eclipse.text.edits.TextEdit;
25
26 import org.eclipse.core.runtime.Assert;
27 import org.eclipse.core.runtime.CoreException;
28 import org.eclipse.core.runtime.IProgressMonitor;
29 import org.eclipse.core.runtime.OperationCanceledException;
30 import org.eclipse.core.runtime.SubProgressMonitor;
31
32 import org.eclipse.jface.text.BadLocationException;
33 import org.eclipse.jface.text.Document;
34 import org.eclipse.jface.text.IDocument;
35
36 import org.eclipse.ltk.core.refactoring.Change;
37 import org.eclipse.ltk.core.refactoring.GroupCategory;
38 import org.eclipse.ltk.core.refactoring.GroupCategorySet;
39 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
40 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
41 import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
42 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
43
44 import org.eclipse.jdt.core.Flags;
45 import org.eclipse.jdt.core.ICompilationUnit;
46 import org.eclipse.jdt.core.IField;
47 import org.eclipse.jdt.core.IJavaElement;
48 import org.eclipse.jdt.core.IJavaProject;
49 import org.eclipse.jdt.core.IMember;
50 import org.eclipse.jdt.core.IMethod;
51 import org.eclipse.jdt.core.IType;
52 import org.eclipse.jdt.core.ITypeHierarchy;
53 import org.eclipse.jdt.core.JavaModelException;
54 import org.eclipse.jdt.core.dom.AST;
55 import org.eclipse.jdt.core.dom.ASTNode;
56 import org.eclipse.jdt.core.dom.ASTRequestor;
57 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
58 import org.eclipse.jdt.core.dom.Block;
59 import org.eclipse.jdt.core.dom.CompilationUnit;
60 import org.eclipse.jdt.core.dom.Expression;
61 import org.eclipse.jdt.core.dom.FieldDeclaration;
62 import org.eclipse.jdt.core.dom.MarkerAnnotation;
63 import org.eclipse.jdt.core.dom.MethodDeclaration;
64 import org.eclipse.jdt.core.dom.Modifier;
65 import org.eclipse.jdt.core.dom.Type;
66 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
67 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
68 import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition;
69 import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
70 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
71 import org.eclipse.jdt.core.search.IJavaSearchConstants;
72 import org.eclipse.jdt.core.search.SearchEngine;
73 import org.eclipse.jdt.core.search.SearchMatch;
74 import org.eclipse.jdt.core.search.SearchPattern;
75
76 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
77 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
78 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
79 import org.eclipse.jdt.internal.corext.dom.ModifierRewrite;
80 import org.eclipse.jdt.internal.corext.refactoring.Checks;
81 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
82 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor;
83 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
84 import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
85 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
86 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2;
87 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
88 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
89 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
90 import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring;
91 import org.eclipse.jdt.internal.corext.refactoring.rename.MethodChecks;
92 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
93 import org.eclipse.jdt.internal.corext.refactoring.util.TextEditBasedChangeManager;
94 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
95 import org.eclipse.jdt.internal.corext.util.JdtFlags;
96 import org.eclipse.jdt.internal.corext.util.Messages;
97 import org.eclipse.jdt.internal.corext.util.SearchUtils;
98 import org.eclipse.jdt.internal.corext.util.Strings;
99
100 import org.eclipse.jdt.ui.JavaElementLabels;
101
102 import org.eclipse.jdt.internal.ui.JavaPlugin;
103 import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
104
105 /**
106  * Refactoring processor for the push down refactoring.
107  *
108  * @since 3.2
109  */

110 public final class PushDownRefactoringProcessor extends HierarchyProcessor {
111
112     public static class MemberActionInfo implements IMemberActionInfo {
113
114         public static final int NO_ACTION= 2;
115
116         public static final int PUSH_ABSTRACT_ACTION= 1;
117
118         public static final int PUSH_DOWN_ACTION= 0;
119
120         private static void assertValidAction(IMember member, int action) {
121             if (member instanceof IMethod)
122                 Assert.isTrue(action == PUSH_ABSTRACT_ACTION || action == NO_ACTION || action == PUSH_DOWN_ACTION);
123             else if (member instanceof IField)
124                 Assert.isTrue(action == NO_ACTION || action == PUSH_DOWN_ACTION);
125         }
126
127         public static MemberActionInfo create(IMember member, int action) {
128             return new MemberActionInfo(member, action);
129         }
130
131         static IMember[] getMembers(MemberActionInfo[] infos) {
132             IMember[] result= new IMember[infos.length];
133             for (int i= 0; i < result.length; i++) {
134                 result[i]= infos[i].getMember();
135             }
136             return result;
137         }
138
139         private int fAction;
140
141         private final IMember fMember;
142
143         private MemberActionInfo(IMember member, int action) {
144             assertValidAction(member, action);
145             Assert.isTrue(member instanceof IField || member instanceof IMethod);
146             fMember= member;
147             fAction= action;
148         }
149
150         boolean copyJavadocToCopiesInSubclasses() {
151             return isToBeDeletedFromDeclaringClass();
152         }
153
154         public int getAction() {
155             return fAction;
156         }
157
158         public int[] getAvailableActions() {
159             if (isFieldInfo())
160                 return new int[] { PUSH_DOWN_ACTION, NO_ACTION };
161
162             return new int[] { PUSH_DOWN_ACTION, PUSH_ABSTRACT_ACTION, NO_ACTION };
163         }
164
165         public IMember getMember() {
166             return fMember;
167         }
168
169         int getNewModifiersForCopyInSubclass(int oldModifiers) throws JavaModelException {
170             if (isFieldInfo())
171                 return oldModifiers;
172             if (isToBeDeletedFromDeclaringClass())
173                 return oldModifiers;
174             int modifiers= oldModifiers;
175             if (isNewMethodToBeDeclaredAbstract()) {
176                 if (!JdtFlags.isPublic(fMember))
177                     modifiers= Modifier.PROTECTED | JdtFlags.clearAccessModifiers(modifiers);
178             }
179             return modifiers;
180         }
181
182         int getNewModifiersForOriginal(int oldModifiers) throws JavaModelException {
183             if (isFieldInfo())
184                 return oldModifiers;
185             if (isToBeDeletedFromDeclaringClass())
186                 return oldModifiers;
187             int modifiers= oldModifiers;
188             if (isNewMethodToBeDeclaredAbstract()) {
189                 modifiers= JdtFlags.clearFlag(Modifier.FINAL | Modifier.NATIVE, oldModifiers);
190                 modifiers|= Modifier.ABSTRACT;
191
192                 if (!JdtFlags.isPublic(fMember))
193                     modifiers= Modifier.PROTECTED | JdtFlags.clearAccessModifiers(modifiers);
194             }
195             return modifiers;
196         }
197
198         public boolean isActive() {
199             return getAction() != NO_ACTION;
200         }
201
202         public boolean isEditable() {
203             if (isFieldInfo())
204                 return false;
205             if (getAction() == MemberActionInfo.NO_ACTION)
206                 return false;
207             return true;
208         }
209
210         boolean isFieldInfo() {
211             return fMember instanceof IField;
212         }
213
214         boolean isNewMethodToBeDeclaredAbstract() throws JavaModelException {
215             return !isFieldInfo() && !JdtFlags.isAbstract(fMember) && fAction == PUSH_ABSTRACT_ACTION;
216         }
217
218         boolean isToBeCreatedInSubclassesOfDeclaringClass() {
219             return fAction != NO_ACTION;
220         }
221
222         boolean isToBeDeletedFromDeclaringClass() {
223             return isToBePushedDown();
224         }
225
226         public boolean isToBePushedDown() {
227             return fAction == PUSH_DOWN_ACTION;
228         }
229
230         public void setAction(int action) {
231             assertValidAction(fMember, action);
232             if (isFieldInfo())
233                 Assert.isTrue(action != PUSH_ABSTRACT_ACTION);
234             fAction= action;
235         }
236
237     }
238
239     private static final String JavaDoc ATTRIBUTE_ABSTRACT= "abstract"; //$NON-NLS-1$
240

241     private static final String JavaDoc ATTRIBUTE_PUSH= "push"; //$NON-NLS-1$
242

243     /** The identifier of this processor */
244     public static final String JavaDoc IDENTIFIER= "org.eclipse.jdt.ui.pushDownProcessor"; //$NON-NLS-1$
245

246     /** The push down group category set */
247     private static final GroupCategorySet SET_PUSH_DOWN= new GroupCategorySet(new GroupCategory("org.eclipse.jdt.internal.corext.pushDown", //$NON-NLS-1$
248
RefactoringCoreMessages.PushDownRefactoring_category_name, RefactoringCoreMessages.PushDownRefactoring_category_description));
249
250     private static MemberActionInfo[] createInfosForAllPushableFieldsAndMethods(IType type) throws JavaModelException {
251         List JavaDoc result= new ArrayList JavaDoc();
252         IMember[] pushableMembers= RefactoringAvailabilityTester.getPushDownMembers(type);
253         for (int i= 0; i < pushableMembers.length; i++) {
254             result.add(MemberActionInfo.create(pushableMembers[i], MemberActionInfo.NO_ACTION));
255         }
256         return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]);
257     }
258
259     private static IMember[] getAbstractMembers(IMember[] members) throws JavaModelException {
260         List JavaDoc result= new ArrayList JavaDoc(members.length);
261         for (int i= 0; i < members.length; i++) {
262             IMember member= members[i];
263             if (JdtFlags.isAbstract(member))
264                 result.add(member);
265         }
266         return (IMember[]) result.toArray(new IMember[result.size()]);
267     }
268
269     private static CompilationUnitRewrite getCompilationUnitRewrite(final Map JavaDoc rewrites, final ICompilationUnit unit) {
270         Assert.isNotNull(rewrites);
271         Assert.isNotNull(unit);
272         CompilationUnitRewrite rewrite= (CompilationUnitRewrite) rewrites.get(unit);
273         if (rewrite == null) {
274             rewrite= new CompilationUnitRewrite(unit);
275             rewrites.put(unit, rewrite);
276         }
277         return rewrite;
278     }
279
280     private static IJavaElement[] getReferencingElementsFromSameClass(IMember member, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException {
281         Assert.isNotNull(member);
282         final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(member, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE));
283         engine.setFiltering(true, true);
284         engine.setScope(SearchEngine.createJavaSearchScope(new IJavaElement[] { member.getDeclaringType() }));
285         engine.setStatus(status);
286         engine.searchPattern(new SubProgressMonitor(pm, 1));
287         SearchResultGroup[] groups= (SearchResultGroup[]) engine.getResults();
288         Set JavaDoc result= new HashSet JavaDoc(3);
289         for (int i= 0; i < groups.length; i++) {
290             SearchResultGroup group= groups[i];
291             SearchMatch[] results= group.getSearchResults();
292             for (int j= 0; j < results.length; j++) {
293                 SearchMatch searchResult= results[i];
294                 result.add(SearchUtils.getEnclosingJavaElement(searchResult));
295             }
296         }
297         return (IJavaElement[]) result.toArray(new IJavaElement[result.size()]);
298     }
299
300     private ITypeHierarchy fCachedClassHierarchy;
301
302     private MemberActionInfo[] fMemberInfos;
303
304     /**
305      * Creates a new push down refactoring processor.
306      *
307      * @param members
308      * the members to pull up, or <code>null</code> if invoked by
309      * scripting
310      */

311     public PushDownRefactoringProcessor(IMember[] members) {
312         super(members, null, false);
313         if (members != null) {
314             final IType type= RefactoringAvailabilityTester.getTopLevelType(members);
315             try {
316                 if (type != null && RefactoringAvailabilityTester.getPushDownMembers(type).length != 0) {
317                     fMembersToMove= new IMember[0];
318                     fCachedDeclaringType= type;
319                 }
320             } catch (JavaModelException exception) {
321                 JavaPlugin.log(exception);
322             }
323         }
324     }
325
326     private void addAllRequiredPushableMembers(List JavaDoc queue, IMember member, IProgressMonitor monitor) throws JavaModelException {
327         monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_calculating_required, 2);
328         IProgressMonitor sub= new SubProgressMonitor(monitor, 1);
329         sub.beginTask(RefactoringCoreMessages.PushDownRefactoring_calculating_required, 2);
330         IMethod[] requiredMethods= ReferenceFinderUtil.getMethodsReferencedIn(new IJavaElement[] { member }, new SubProgressMonitor(sub, 1));
331         sub= new SubProgressMonitor(sub, 1);
332         sub.beginTask(RefactoringCoreMessages.PushDownRefactoring_calculating_required, requiredMethods.length);
333         for (int index= 0; index < requiredMethods.length; index++) {
334             IMethod method= requiredMethods[index];
335             if (!MethodChecks.isVirtual(method) && (method.getDeclaringType().equals(getDeclaringType()) && !queue.contains(method) && RefactoringAvailabilityTester.isPushDownAvailable(method)))
336                 queue.add(method);
337         }
338         sub.done();
339         IField[] requiredFields= ReferenceFinderUtil.getFieldsReferencedIn(new IJavaElement[] { member }, new SubProgressMonitor(monitor, 1));
340         for (int index= 0; index < requiredFields.length; index++) {
341             IField field= requiredFields[index];
342             if (field.getDeclaringType().equals(getDeclaringType()) && !queue.contains(field) && RefactoringAvailabilityTester.isPushDownAvailable(field))
343                 queue.add(field);
344         }
345         monitor.done();
346     }
347
348     private RefactoringStatus checkAbstractMembersInDestinationClasses(IMember[] membersToPushDown, IType[] destinationClassesForAbstract) throws JavaModelException {
349         RefactoringStatus result= new RefactoringStatus();
350         IMember[] abstractMembersToPushDown= getAbstractMembers(membersToPushDown);
351         for (int index= 0; index < destinationClassesForAbstract.length; index++) {
352             result.merge(MemberCheckUtil.checkMembersInDestinationType(abstractMembersToPushDown, destinationClassesForAbstract[index]));
353         }
354         return result;
355     }
356
357     private RefactoringStatus checkAccessedFields(IType[] subclasses, IProgressMonitor pm) throws JavaModelException {
358         RefactoringStatus result= new RefactoringStatus();
359         IMember[] membersToPushDown= MemberActionInfo.getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass());
360         List JavaDoc pushedDownList= Arrays.asList(membersToPushDown);
361         IField[] accessedFields= ReferenceFinderUtil.getFieldsReferencedIn(membersToPushDown, pm);
362         for (int i= 0; i < subclasses.length; i++) {
363             IType targetClass= subclasses[i];
364             ITypeHierarchy targetSupertypes= targetClass.newSupertypeHierarchy(null);
365             for (int j= 0; j < accessedFields.length; j++) {
366                 IField field= accessedFields[j];
367                 boolean isAccessible= pushedDownList.contains(field) || canBeAccessedFrom(field, targetClass, targetSupertypes) || Flags.isEnum(field.getFlags());
368                 if (!isAccessible) {
369                     String JavaDoc message= Messages.format(RefactoringCoreMessages.PushDownRefactoring_field_not_accessible, new String JavaDoc[] { JavaElementLabels.getTextLabel(field, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getTextLabel(targetClass, JavaElementLabels.ALL_FULLY_QUALIFIED) });
370                     result.addError(message, JavaStatusContext.create(field));
371                 }
372             }
373         }
374         pm.done();
375         return result;
376     }
377
378     private RefactoringStatus checkAccessedMethods(IType[] subclasses, IProgressMonitor pm) throws JavaModelException {
379         RefactoringStatus result= new RefactoringStatus();
380         IMember[] membersToPushDown= MemberActionInfo.getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass());
381         List JavaDoc pushedDownList= Arrays.asList(membersToPushDown);
382         IMethod[] accessedMethods= ReferenceFinderUtil.getMethodsReferencedIn(membersToPushDown, pm);
383         for (int index= 0; index < subclasses.length; index++) {
384             IType targetClass= subclasses[index];
385             ITypeHierarchy targetSupertypes= targetClass.newSupertypeHierarchy(null);
386             for (int offset= 0; offset < accessedMethods.length; offset++) {
387                 IMethod method= accessedMethods[offset];
388                 boolean isAccessible= pushedDownList.contains(method) || canBeAccessedFrom(method, targetClass, targetSupertypes);
389                 if (!isAccessible) {
390                     String JavaDoc message= Messages.format(RefactoringCoreMessages.PushDownRefactoring_method_not_accessible, new String JavaDoc[] { JavaElementLabels.getTextLabel(method, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getTextLabel(targetClass, JavaElementLabels.ALL_FULLY_QUALIFIED) });
391                     result.addError(message, JavaStatusContext.create(method));
392                 }
393             }
394         }
395         pm.done();
396         return result;
397     }
398
399     private RefactoringStatus checkAccessedTypes(IType[] subclasses, IProgressMonitor pm) throws JavaModelException {
400         RefactoringStatus result= new RefactoringStatus();
401         IType[] accessedTypes= getTypesReferencedInMovedMembers(pm);
402         for (int index= 0; index < subclasses.length; index++) {
403             IType targetClass= subclasses[index];
404             ITypeHierarchy targetSupertypes= targetClass.newSupertypeHierarchy(null);
405             for (int offset= 0; offset < accessedTypes.length; offset++) {
406                 IType type= accessedTypes[offset];
407                 if (!canBeAccessedFrom(type, targetClass, targetSupertypes)) {
408                     String JavaDoc message= Messages.format(RefactoringCoreMessages.PushDownRefactoring_type_not_accessible, new String JavaDoc[] { JavaElementLabels.getTextLabel(type, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getTextLabel(targetClass, JavaElementLabels.ALL_FULLY_QUALIFIED) });
409                     result.addError(message, JavaStatusContext.create(type));
410                 }
411             }
412         }
413         pm.done();
414         return result;
415     }
416
417     private RefactoringStatus checkElementsAccessedByModifiedMembers(IProgressMonitor pm) throws JavaModelException {
418         RefactoringStatus result= new RefactoringStatus();
419         pm.beginTask(RefactoringCoreMessages.PushDownRefactoring_check_references, 3);
420         IType[] subclasses= getAbstractDestinations(new SubProgressMonitor(pm, 1));
421         result.merge(checkAccessedTypes(subclasses, new SubProgressMonitor(pm, 1)));
422         result.merge(checkAccessedFields(subclasses, new SubProgressMonitor(pm, 1)));
423         result.merge(checkAccessedMethods(subclasses, new SubProgressMonitor(pm, 1)));
424         pm.done();
425         return result;
426     }
427
428     /**
429      * {@inheritDoc}
430      */

431     public RefactoringStatus checkFinalConditions(IProgressMonitor monitor, CheckConditionsContext context) throws CoreException, OperationCanceledException {
432         try {
433             monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, 5);
434             clearCaches();
435             ICompilationUnit unit= getDeclaringType().getCompilationUnit();
436             if (fLayer)
437                 unit= unit.findWorkingCopy(fOwner);
438             resetWorkingCopies(unit);
439             final RefactoringStatus result= new RefactoringStatus();
440             result.merge(checkMembersInDestinationClasses(new SubProgressMonitor(monitor, 1)));
441             result.merge(checkElementsAccessedByModifiedMembers(new SubProgressMonitor(monitor, 1)));
442             result.merge(checkReferencesToPushedDownMembers(new SubProgressMonitor(monitor, 1)));
443             if (!JdtFlags.isAbstract(getDeclaringType()) && getAbstractDeclarationInfos().length != 0)
444                 result.merge(checkConstructorCalls(getDeclaringType(), new SubProgressMonitor(monitor, 1)));
445             else
446                 monitor.worked(1);
447             if (result.hasFatalError())
448                 return result;
449             List JavaDoc members= new ArrayList JavaDoc(fMemberInfos.length);
450             for (int index= 0; index < fMemberInfos.length; index++) {
451                 if (fMemberInfos[index].getAction() != MemberActionInfo.NO_ACTION)
452                     members.add(fMemberInfos[index].getMember());
453             }
454             fMembersToMove= (IMember[]) members.toArray(new IMember[members.size()]);
455             fChangeManager= createChangeManager(new SubProgressMonitor(monitor, 1), result);
456             if (result.hasFatalError())
457                 return result;
458             result.merge(Checks.validateModifiesFiles(ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits()), getRefactoring().getValidationContext()));
459             return result;
460         } finally {
461             monitor.done();
462         }
463     }
464
465     /**
466      * {@inheritDoc}
467      */

468     public RefactoringStatus checkInitialConditions(IProgressMonitor monitor) throws CoreException, OperationCanceledException {
469         try {
470             monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, 1);
471             RefactoringStatus status= new RefactoringStatus();
472             status.merge(checkPossibleSubclasses(new SubProgressMonitor(monitor, 1)));
473             if (status.hasFatalError())
474                 return status;
475             status.merge(checkDeclaringType(new SubProgressMonitor(monitor, 1)));
476             if (status.hasFatalError())
477                 return status;
478             status.merge(checkIfMembersExist());
479             if (status.hasFatalError())
480                 return status;
481             fMemberInfos= createInfosForAllPushableFieldsAndMethods(getDeclaringType());
482             List JavaDoc list= Arrays.asList(fMembersToMove);
483             for (int offset= 0; offset < fMemberInfos.length; offset++) {
484                 MemberActionInfo info= fMemberInfos[offset];
485                 if (list.contains(info.getMember()))
486                     info.setAction(MemberActionInfo.PUSH_DOWN_ACTION);
487             }
488             return status;
489         } finally {
490             monitor.done();
491         }
492     }
493
494     private RefactoringStatus checkMembersInDestinationClasses(IProgressMonitor monitor) throws JavaModelException {
495         monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, 2);
496         RefactoringStatus result= new RefactoringStatus();
497         IMember[] membersToPushDown= MemberActionInfo.getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass());
498
499         IType[] destinationClassesForNonAbstract= getAbstractDestinations(new SubProgressMonitor(monitor, 1));
500         result.merge(checkNonAbstractMembersInDestinationClasses(membersToPushDown, destinationClassesForNonAbstract));
501         List JavaDoc list= Arrays.asList(getAbstractMembers(getAbstractDestinations(new SubProgressMonitor(monitor, 1))));
502
503         IType[] destinationClassesForAbstract= (IType[]) list.toArray(new IType[list.size()]);
504         result.merge(checkAbstractMembersInDestinationClasses(membersToPushDown, destinationClassesForAbstract));
505         monitor.done();
506         return result;
507     }
508
509     private RefactoringStatus checkNonAbstractMembersInDestinationClasses(IMember[] membersToPushDown, IType[] destinationClassesForNonAbstract) throws JavaModelException {
510         RefactoringStatus result= new RefactoringStatus();
511         List JavaDoc list= new ArrayList JavaDoc(); // Arrays.asList does not support removing
512
list.addAll(Arrays.asList(membersToPushDown));
513         list.removeAll(Arrays.asList(getAbstractMembers(membersToPushDown)));
514         IMember[] nonAbstractMembersToPushDown= (IMember[]) list.toArray(new IMember[list.size()]);
515         for (int i= 0; i < destinationClassesForNonAbstract.length; i++) {
516             result.merge(MemberCheckUtil.checkMembersInDestinationType(nonAbstractMembersToPushDown, destinationClassesForNonAbstract[i]));
517         }
518         return result;
519     }
520
521     private RefactoringStatus checkPossibleSubclasses(IProgressMonitor pm) throws JavaModelException {
522         IType[] modifiableSubclasses= getAbstractDestinations(pm);
523         if (modifiableSubclasses.length == 0) {
524             String JavaDoc msg= Messages.format(RefactoringCoreMessages.PushDownRefactoring_no_subclasses, new String JavaDoc[] { JavaElementLabels.getTextLabel(getDeclaringType(), JavaElementLabels.ALL_FULLY_QUALIFIED) });
525             return RefactoringStatus.createFatalErrorStatus(msg);
526         }
527         return new RefactoringStatus();
528     }
529
530     private RefactoringStatus checkReferencesToPushedDownMembers(IProgressMonitor monitor) throws JavaModelException {
531         List JavaDoc fields= new ArrayList JavaDoc(fMemberInfos.length);
532         for (int index= 0; index < fMemberInfos.length; index++) {
533             MemberActionInfo info= fMemberInfos[index];
534             if (info.isToBePushedDown())
535                 fields.add(info.getMember());
536         }
537         IMember[] membersToPush= (IMember[]) fields.toArray(new IMember[fields.size()]);
538         RefactoringStatus result= new RefactoringStatus();
539         List JavaDoc movedMembers= Arrays.asList(MemberActionInfo.getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass()));
540         monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_check_references, membersToPush.length);
541         for (int index= 0; index < membersToPush.length; index++) {
542             IMember member= membersToPush[index];
543             String JavaDoc label= createLabel(member);
544             IJavaElement[] referencing= getReferencingElementsFromSameClass(member, new SubProgressMonitor(monitor, 1), result);
545             for (int offset= 0; offset < referencing.length; offset++) {
546                 IJavaElement element= referencing[offset];
547                 if (movedMembers.contains(element))
548                     continue;
549                 if (!(element instanceof IMember))
550                     continue;
551                 IMember referencingMember= (IMember) element;
552                 Object JavaDoc[] keys= { label, createLabel(referencingMember) };
553                 String JavaDoc msg= Messages.format(RefactoringCoreMessages.PushDownRefactoring_referenced, keys);
554                 result.addError(msg, JavaStatusContext.create(referencingMember));
555             }
556         }
557         monitor.done();
558         return result;
559     }
560
561     public void computeAdditionalRequiredMembersToPushDown(IProgressMonitor monitor) throws JavaModelException {
562         List JavaDoc list= Arrays.asList(getAdditionalRequiredMembers(monitor));
563         for (int index= 0; index < fMemberInfos.length; index++) {
564             MemberActionInfo info= fMemberInfos[index];
565             if (list.contains(info.getMember()))
566                 info.setAction(MemberActionInfo.PUSH_DOWN_ACTION);
567         }
568     }
569
570     private void copyBodyOfPushedDownMethod(ASTRewrite targetRewrite, IMethod method, MethodDeclaration oldMethod, MethodDeclaration newMethod, TypeVariableMaplet[] mapping) throws JavaModelException {
571         Block body= oldMethod.getBody();
572         if (body == null) {
573             newMethod.setBody(null);
574             return;
575         }
576         try {
577             final IDocument document= new Document(method.getCompilationUnit().getBuffer().getContents());
578             final ASTRewrite rewriter= ASTRewrite.create(body.getAST());
579             final ITrackedNodePosition position= rewriter.track(body);
580             body.accept(new TypeVariableMapper(rewriter, mapping));
581             rewriter.rewriteAST(document, getDeclaringType().getCompilationUnit().getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
582             String JavaDoc content= document.get(position.getStartPosition(), position.getLength());
583             String JavaDoc[] lines= Strings.convertIntoLines(content);
584             Strings.trimIndentation(lines, method.getJavaProject(), false);
585             content= Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(method));
586             newMethod.setBody((Block) targetRewrite.createStringPlaceholder(content, ASTNode.BLOCK));
587         } catch (MalformedTreeException exception) {
588             JavaPlugin.log(exception);
589         } catch (BadLocationException exception) {
590             JavaPlugin.log(exception);
591         }
592     }
593
594     private void copyMembers(Collection JavaDoc adjustors, Map JavaDoc adjustments, Map JavaDoc rewrites, RefactoringStatus status, MemberActionInfo[] infos, IType[] destinations, CompilationUnitRewrite sourceRewriter, CompilationUnitRewrite unitRewriter, IProgressMonitor monitor) throws JavaModelException {
595         try {
596             monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, 1);
597             IType type= null;
598             TypeVariableMaplet[] mapping= null;
599             for (int index= 0; index < destinations.length; index++) {
600                 type= destinations[index];
601                 mapping= TypeVariableUtil.superTypeToInheritedType(getDeclaringType(), type);
602                 if (unitRewriter.getCu().equals(type.getCompilationUnit())) {
603                     IMember member= null;
604                     MemberVisibilityAdjustor adjustor= null;
605                     AbstractTypeDeclaration declaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(type, unitRewriter.getRoot());
606                     for (int offset= infos.length - 1; offset >= 0; offset--) {
607                         member= infos[offset].getMember();
608                         adjustor= new MemberVisibilityAdjustor(type, member);
609                         if (infos[offset].isNewMethodToBeDeclaredAbstract())
610                             adjustor.setIncoming(false);
611                         adjustor.setRewrite(sourceRewriter.getASTRewrite(), sourceRewriter.getRoot());
612                         adjustor.setRewrites(rewrites);
613
614                         // TW: set to error if bug 78387 is fixed
615
adjustor.setFailureSeverity(RefactoringStatus.WARNING);
616
617                         adjustor.setStatus(status);
618                         adjustor.setAdjustments(adjustments);
619                         adjustor.adjustVisibility(new SubProgressMonitor(monitor, 1));
620                         adjustments.remove(member);
621                         adjustors.add(adjustor);
622                         status.merge(checkProjectCompliance(getCompilationUnitRewrite(rewrites, getDeclaringType().getCompilationUnit()), type, new IMember[] {infos[offset].getMember()}));
623                         if (infos[offset].isFieldInfo()) {
624                             final VariableDeclarationFragment oldField= ASTNodeSearchUtil.getFieldDeclarationFragmentNode((IField) infos[offset].getMember(), sourceRewriter.getRoot());
625                             if (oldField != null) {
626                                 FieldDeclaration newField= createNewFieldDeclarationNode(infos[offset], sourceRewriter.getRoot(), mapping, unitRewriter.getASTRewrite(), oldField);
627                                 unitRewriter.getASTRewrite().getListRewrite(declaration, declaration.getBodyDeclarationsProperty()).insertAt(newField, ASTNodes.getInsertionIndex(newField, declaration.bodyDeclarations()), unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_add_member, SET_PUSH_DOWN));
628                                 ImportRewriteUtil.addImports(unitRewriter, oldField.getParent(), new HashMap JavaDoc(), new HashMap JavaDoc(), false);
629                             }
630                         } else {
631                             final MethodDeclaration oldMethod= ASTNodeSearchUtil.getMethodDeclarationNode((IMethod) infos[offset].getMember(), sourceRewriter.getRoot());
632                             if (oldMethod != null) {
633                                 MethodDeclaration newMethod= createNewMethodDeclarationNode(infos[offset], sourceRewriter.getRoot(), mapping, unitRewriter, oldMethod);
634                                 unitRewriter.getASTRewrite().getListRewrite(declaration, declaration.getBodyDeclarationsProperty()).insertAt(newMethod, ASTNodes.getInsertionIndex(newMethod, declaration.bodyDeclarations()), unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_add_member, SET_PUSH_DOWN));
635                                 ImportRewriteUtil.addImports(unitRewriter, oldMethod, new HashMap JavaDoc(), new HashMap JavaDoc(), false);
636                             }
637                         }
638                     }
639                 }
640             }
641         } finally {
642             monitor.done();
643         }
644     }
645
646     /**
647      * {@inheritDoc}
648      */

649     public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
650         try {
651             final Map JavaDoc arguments= new HashMap JavaDoc();
652             String JavaDoc project= null;
653             final IType declaring= getDeclaringType();
654             final IJavaProject javaProject= declaring.getJavaProject();
655             if (javaProject != null)
656                 project= javaProject.getElementName();
657             int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE;
658             try {
659                 if (declaring.isLocal() || declaring.isAnonymous())
660                     flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
661             } catch (JavaModelException exception) {
662                 JavaPlugin.log(exception);
663             }
664             final String JavaDoc description= fMembersToMove.length == 1 ? Messages.format(RefactoringCoreMessages.PushDownRefactoring_descriptor_description_short_multi, fMembersToMove[0].getElementName()) : RefactoringCoreMessages.PushDownRefactoring_descriptor_description_short;
665             final String JavaDoc header= fMembersToMove.length == 1 ? Messages.format(RefactoringCoreMessages.PushDownRefactoring_descriptor_description_full, new String JavaDoc[] { JavaElementLabels.getElementLabel(fMembersToMove[0], JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getElementLabel(declaring, JavaElementLabels.ALL_FULLY_QUALIFIED) }) : Messages.format(RefactoringCoreMessages.PushDownRefactoring_descriptor_description, new String JavaDoc[] { JavaElementLabels.getElementLabel(declaring, JavaElementLabels.ALL_FULLY_QUALIFIED) });
666             final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
667             final String JavaDoc[] settings= new String JavaDoc[fMembersToMove.length];
668             for (int index= 0; index < settings.length; index++)
669                 settings[index]= JavaElementLabels.getElementLabel(fMembersToMove[index], JavaElementLabels.ALL_FULLY_QUALIFIED);
670             comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.PushDownRefactoring_pushed_members_pattern, settings));
671             addSuperTypeSettings(comment, true);
672             final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.PUSH_DOWN, project, description, comment.asString(), arguments, flags);
673             if (fCachedDeclaringType != null)
674                 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fCachedDeclaringType));
675             for (int index= 0; index < fMembersToMove.length; index++) {
676                 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + (index + 1), descriptor.elementToHandle(fMembersToMove[index]));
677                 for (int offset= 0; offset < fMemberInfos.length; offset++) {
678                     if (fMemberInfos[offset].getMember().equals(fMembersToMove[index])) {
679                         switch (fMemberInfos[offset].getAction()) {
680                             case MemberActionInfo.PUSH_ABSTRACT_ACTION:
681                                 arguments.put(ATTRIBUTE_ABSTRACT + (index + 1), Boolean.valueOf(true).toString());
682                                 break;
683                             case MemberActionInfo.PUSH_DOWN_ACTION:
684                                 arguments.put(ATTRIBUTE_PUSH + (index + 1), Boolean.valueOf(true).toString());
685                                 break;
686                         }
687                     }
688                 }
689             }
690             return new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.PushDownRefactoring_change_name, fChangeManager.getAllChanges());
691         } finally {
692             pm.done();
693             clearCaches();
694         }
695     }
696
697     private TextEditBasedChangeManager createChangeManager(final IProgressMonitor monitor, final RefactoringStatus status) throws CoreException {
698         Assert.isNotNull(monitor);
699         Assert.isNotNull(status);
700         try {
701             monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, 7);
702             final ICompilationUnit source= getDeclaringType().getCompilationUnit();
703             final CompilationUnitRewrite sourceRewriter= new CompilationUnitRewrite(source);
704             final Map JavaDoc rewrites= new HashMap JavaDoc(2);
705             rewrites.put(source, sourceRewriter);
706             IType[] types= getHierarchyOfDeclaringClass(new SubProgressMonitor(monitor, 1)).getSubclasses(getDeclaringType());
707             final Set JavaDoc result= new HashSet JavaDoc(types.length + 1);
708             for (int index= 0; index < types.length; index++)
709                 result.add(types[index].getCompilationUnit());
710             result.add(source);
711             final Map JavaDoc adjustments= new HashMap JavaDoc();
712             final List JavaDoc adjustors= new ArrayList JavaDoc();
713             final ICompilationUnit[] units= (ICompilationUnit[]) result.toArray(new ICompilationUnit[result.size()]);
714             ICompilationUnit unit= null;
715             CompilationUnitRewrite rewrite= null;
716             final IProgressMonitor sub= new SubProgressMonitor(monitor, 4);
717             try {
718                 sub.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, units.length * 4);
719                 for (int index= 0; index < units.length; index++) {
720                     unit= units[index];
721                     rewrite= getCompilationUnitRewrite(rewrites, unit);
722                     if (unit.equals(sourceRewriter.getCu())) {
723                         final AbstractTypeDeclaration declaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(getDeclaringType(), rewrite.getRoot());
724                         if (!JdtFlags.isAbstract(getDeclaringType()) && getAbstractDeclarationInfos().length != 0)
725                             ModifierRewrite.create(rewrite.getASTRewrite(), declaration).setModifiers((Modifier.ABSTRACT | declaration.getModifiers()), rewrite.createCategorizedGroupDescription(RefactoringCoreMessages.PushDownRefactoring_make_abstract, SET_PUSH_DOWN));
726                         deleteDeclarationNodes(sourceRewriter, false, rewrite, Arrays.asList(getDeletableMembers()), SET_PUSH_DOWN);
727                         MemberActionInfo[] methods= getAbstractDeclarationInfos();
728                         for (int offset= 0; offset < methods.length; offset++)
729                             declareMethodAbstract(methods[offset], sourceRewriter, rewrite);
730                     }
731                     final IMember[] members= getAbstractMembers(getAbstractDestinations(new SubProgressMonitor(monitor, 1)));
732                     final IType[] classes= new IType[members.length];
733                     for (int offset= 0; offset < members.length; offset++)
734                         classes[offset]= (IType) members[offset];
735                     copyMembers(adjustors, adjustments, rewrites, status, getAbstractMemberInfos(), classes, sourceRewriter, rewrite, sub);
736                     copyMembers(adjustors, adjustments, rewrites, status, getEffectedMemberInfos(), getAbstractDestinations(new SubProgressMonitor(monitor, 1)), sourceRewriter, rewrite, sub);
737                     if (monitor.isCanceled())
738                         throw new OperationCanceledException();
739                 }
740             } finally {
741                 sub.done();
742             }
743             if (!adjustors.isEmpty() && !adjustments.isEmpty()) {
744                 final MemberVisibilityAdjustor adjustor= (MemberVisibilityAdjustor) adjustors.get(0);
745                 adjustor.rewriteVisibility(new SubProgressMonitor(monitor, 1));
746             }
747             final TextEditBasedChangeManager manager= new TextEditBasedChangeManager();
748             for (final Iterator JavaDoc iterator= rewrites.keySet().iterator(); iterator.hasNext();) {
749                 unit= (ICompilationUnit) iterator.next();
750                 rewrite= (CompilationUnitRewrite) rewrites.get(unit);
751                 if (rewrite != null)
752                     manager.manage(unit, rewrite.createChange());
753             }
754             return manager;
755         } finally {
756             monitor.done();
757         }
758     }
759
760     private FieldDeclaration createNewFieldDeclarationNode(MemberActionInfo info, CompilationUnit declaringCuNode, TypeVariableMaplet[] mapping, ASTRewrite rewrite, VariableDeclarationFragment oldFieldFragment) throws JavaModelException {
761         Assert.isTrue(info.isFieldInfo());
762         IField field= (IField) info.getMember();
763         AST ast= rewrite.getAST();
764         VariableDeclarationFragment newFragment= ast.newVariableDeclarationFragment();
765         newFragment.setExtraDimensions(oldFieldFragment.getExtraDimensions());
766         Expression initializer= oldFieldFragment.getInitializer();
767         if (initializer != null) {
768             Expression newInitializer= null;
769             if (mapping.length > 0)
770                 newInitializer= createPlaceholderForExpression(initializer, field.getCompilationUnit(), mapping, rewrite);
771             else
772                 newInitializer= createPlaceholderForExpression(initializer, field.getCompilationUnit(), rewrite);
773             newFragment.setInitializer(newInitializer);
774         }
775         newFragment.setName(ast.newSimpleName(oldFieldFragment.getName().getIdentifier()));
776         FieldDeclaration newField= ast.newFieldDeclaration(newFragment);
777         FieldDeclaration oldField= ASTNodeSearchUtil.getFieldDeclarationNode(field, declaringCuNode);
778         if (info.copyJavadocToCopiesInSubclasses())
779             copyJavadocNode(rewrite, field, oldField, newField);
780         copyAnnotations(oldField, newField);
781         newField.modifiers().addAll(ASTNodeFactory.newModifiers(ast, info.getNewModifiersForCopyInSubclass(oldField.getModifiers())));
782         Type oldType= oldField.getType();
783         ICompilationUnit cu= field.getCompilationUnit();
784         Type newType= null;
785         if (mapping.length > 0) {
786             newType= createPlaceholderForType(oldType, cu, mapping, rewrite);
787         } else
788             newType= createPlaceholderForType(oldType, cu, rewrite);
789         newField.setType(newType);
790         return newField;
791     }
792
793     private MethodDeclaration createNewMethodDeclarationNode(MemberActionInfo info, CompilationUnit declaringCuNode, TypeVariableMaplet[] mapping, CompilationUnitRewrite rewriter, MethodDeclaration oldMethod) throws JavaModelException {
794         Assert.isTrue(!info.isFieldInfo());
795         IMethod method= (IMethod) info.getMember();
796         ASTRewrite rewrite= rewriter.getASTRewrite();
797         AST ast= rewrite.getAST();
798         MethodDeclaration newMethod= ast.newMethodDeclaration();
799         copyBodyOfPushedDownMethod(rewrite, method, oldMethod, newMethod, mapping);
800         newMethod.setConstructor(oldMethod.isConstructor());
801         newMethod.setExtraDimensions(oldMethod.getExtraDimensions());
802         if (info.copyJavadocToCopiesInSubclasses())
803             copyJavadocNode(rewrite, method, oldMethod, newMethod);
804         final IJavaProject project= rewriter.getCu().getJavaProject();
805         if (info.isNewMethodToBeDeclaredAbstract() && JavaModelUtil.is50OrHigher(project) && JavaPreferencesSettings.getCodeGenerationSettings(project).overrideAnnotation) {
806             final MarkerAnnotation annotation= ast.newMarkerAnnotation();
807             annotation.setTypeName(ast.newSimpleName("Override")); //$NON-NLS-1$
808
newMethod.modifiers().add(annotation);
809         }
810         copyAnnotations(oldMethod, newMethod);
811         newMethod.modifiers().addAll(ASTNodeFactory.newModifiers(ast, info.getNewModifiersForCopyInSubclass(oldMethod.getModifiers())));
812         newMethod.setName(ast.newSimpleName(oldMethod.getName().getIdentifier()));
813         copyReturnType(rewrite, method.getCompilationUnit(), oldMethod, newMethod, mapping);
814         copyParameters(rewrite, method.getCompilationUnit(), oldMethod, newMethod, mapping);
815         copyThrownExceptions(oldMethod, newMethod);
816         copyTypeParameters(oldMethod, newMethod);
817         return newMethod;
818     }
819
820     private void declareMethodAbstract(MemberActionInfo info, CompilationUnitRewrite sourceRewrite, CompilationUnitRewrite unitRewrite) throws JavaModelException {
821         Assert.isTrue(!info.isFieldInfo());
822         IMethod method= (IMethod) info.getMember();
823         if (JdtFlags.isAbstract(method))
824             return;
825         final MethodDeclaration declaration= ASTNodeSearchUtil.getMethodDeclarationNode(method, sourceRewrite.getRoot());
826         unitRewrite.getASTRewrite().remove(declaration.getBody(), null);
827         sourceRewrite.getImportRemover().registerRemovedNode(declaration.getBody());
828         ModifierRewrite.create(unitRewrite.getASTRewrite(), declaration).setModifiers(info.getNewModifiersForOriginal(declaration.getModifiers()), null);
829     }
830
831     private MemberActionInfo[] getAbstractDeclarationInfos() throws JavaModelException {
832         List JavaDoc result= new ArrayList JavaDoc(fMemberInfos.length);
833         for (int index= 0; index < fMemberInfos.length; index++) {
834             MemberActionInfo info= fMemberInfos[index];
835             if (info.isNewMethodToBeDeclaredAbstract())
836                 result.add(info);
837         }
838         return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]);
839     }
840
841     private IType[] getAbstractDestinations(IProgressMonitor monitor) throws JavaModelException {
842         IType[] allDirectSubclasses= getHierarchyOfDeclaringClass(monitor).getSubclasses(getDeclaringType());
843         List JavaDoc result= new ArrayList JavaDoc(allDirectSubclasses.length);
844         for (int index= 0; index < allDirectSubclasses.length; index++) {
845             IType subclass= allDirectSubclasses[index];
846             if (subclass.exists() && !subclass.isBinary() && !subclass.isReadOnly() && subclass.getCompilationUnit() != null && subclass.isStructureKnown())
847                 result.add(subclass);
848         }
849         return (IType[]) result.toArray(new IType[result.size()]);
850     }
851
852     private MemberActionInfo[] getAbstractMemberInfos() throws JavaModelException {
853         List JavaDoc result= new ArrayList JavaDoc(fMemberInfos.length);
854         for (int index= 0; index < fMemberInfos.length; index++) {
855             MemberActionInfo info= fMemberInfos[index];
856             if (info.isToBeCreatedInSubclassesOfDeclaringClass() && JdtFlags.isAbstract(info.getMember()))
857                 result.add(info);
858         }
859         return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]);
860     }
861
862     public IMember[] getAdditionalRequiredMembers(IProgressMonitor monitor) throws JavaModelException {
863         IMember[] members= MemberActionInfo.getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass());
864         monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_calculating_required, members.length);// not
865
// true,
866
// but
867
// not
868
// easy
869
// to
870
// give
871
// anything
872
// better
873
List JavaDoc queue= new ArrayList JavaDoc(members.length);
874         queue.addAll(Arrays.asList(members));
875         if (queue.isEmpty())
876             return new IMember[0];
877         int i= 0;
878         IMember current;
879         do {
880             current= (IMember) queue.get(i);
881             addAllRequiredPushableMembers(queue, current, new SubProgressMonitor(monitor, 1));
882             i++;
883             if (queue.size() == i)
884                 current= null;
885         } while (current != null);
886         queue.removeAll(Arrays.asList(members));// report only additional
887
return (IMember[]) queue.toArray(new IMember[queue.size()]);
888     }
889
890     private IMember[] getDeletableMembers() {
891         List JavaDoc result= new ArrayList JavaDoc(fMemberInfos.length);
892         for (int i= 0; i < fMemberInfos.length; i++) {
893             MemberActionInfo info= fMemberInfos[i];
894             if (info.isToBeDeletedFromDeclaringClass())
895                 result.add(info.getMember());
896         }
897         return (IMember[]) result.toArray(new IMember[result.size()]);
898     }
899
900     private MemberActionInfo[] getEffectedMemberInfos() throws JavaModelException {
901         List JavaDoc result= new ArrayList JavaDoc(fMemberInfos.length);
902         for (int i= 0; i < fMemberInfos.length; i++) {
903             MemberActionInfo info= fMemberInfos[i];
904             if (info.isToBeCreatedInSubclassesOfDeclaringClass() && !JdtFlags.isAbstract(info.getMember()))
905                 result.add(info);
906         }
907         return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]);
908     }
909
910     /**
911      * {@inheritDoc}
912      */

913     public Object JavaDoc[] getElements() {
914         return fMembersToMove;
915     }
916
917     private ITypeHierarchy getHierarchyOfDeclaringClass(IProgressMonitor monitor) throws JavaModelException {
918         try {
919             if (fCachedClassHierarchy != null)
920                 return fCachedClassHierarchy;
921             fCachedClassHierarchy= getDeclaringType().newTypeHierarchy(monitor);
922             return fCachedClassHierarchy;
923         } finally {
924             monitor.done();
925         }
926     }
927
928     /**
929      * {@inheritDoc}
930      */

931     public String JavaDoc getIdentifier() {
932         return IDENTIFIER;
933     }
934
935     private MemberActionInfo[] getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass() throws JavaModelException {
936         MemberActionInfo[] abs= getAbstractMemberInfos();
937         MemberActionInfo[] nonabs= getEffectedMemberInfos();
938         List JavaDoc result= new ArrayList JavaDoc(abs.length + nonabs.length);
939         result.addAll(Arrays.asList(abs));
940         result.addAll(Arrays.asList(nonabs));
941         return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]);
942     }
943
944     public MemberActionInfo[] getMemberActionInfos() {
945         return fMemberInfos;
946     }
947
948     /**
949      * {@inheritDoc}
950      */

951     public String JavaDoc getProcessorName() {
952         return RefactoringCoreMessages.PushDownRefactoring_name;
953     }
954
955     /**
956      * {@inheritDoc}
957      */

958     public RefactoringStatus initialize(RefactoringArguments arguments) {
959         if (arguments instanceof JavaRefactoringArguments) {
960             final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments;
961             String JavaDoc handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT);
962             if (handle != null) {
963                 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
964                 if (element == null || !element.exists() || element.getElementType() != IJavaElement.TYPE)
965                     return ScriptableRefactoring.createInputFatalStatus(element, getRefactoring().getName(), IJavaRefactorings.PUSH_DOWN);
966                 else
967                     fCachedDeclaringType= (IType) element;
968             }
969             int count= 1;
970             final List JavaDoc elements= new ArrayList JavaDoc();
971             final List JavaDoc infos= new ArrayList JavaDoc();
972             String JavaDoc attribute= JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + count;
973             final RefactoringStatus status= new RefactoringStatus();
974             while ((handle= extended.getAttribute(attribute)) != null) {
975                 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
976                 if (element == null || !element.exists())
977                     status.merge(ScriptableRefactoring.createInputWarningStatus(element, getRefactoring().getName(), IJavaRefactorings.PUSH_DOWN));
978                 else
979                     elements.add(element);
980                 if (extended.getAttribute(ATTRIBUTE_ABSTRACT + count) != null)
981                     infos.add(MemberActionInfo.create((IMember) element, MemberActionInfo.PUSH_ABSTRACT_ACTION));
982                 else if (extended.getAttribute(ATTRIBUTE_PUSH + count) != null)
983                     infos.add(MemberActionInfo.create((IMember) element, MemberActionInfo.PUSH_DOWN_ACTION));
984                 else
985                     infos.add(MemberActionInfo.create((IMember) element, MemberActionInfo.NO_ACTION));
986                 count++;
987                 attribute= JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + count;
988             }
989             fMembersToMove= (IMember[]) elements.toArray(new IMember[elements.size()]);
990             fMemberInfos= (MemberActionInfo[]) infos.toArray(new MemberActionInfo[infos.size()]);
991             if (!status.isOK())
992                 return status;
993         } else
994             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
995         return new RefactoringStatus();
996     }
997
998     /**
999      * {@inheritDoc}
1000     */

1001    public boolean isApplicable() throws CoreException {
1002        return RefactoringAvailabilityTester.isPushDownAvailable(fMembersToMove);
1003    }
1004
1005    /**
1006     * {@inheritDoc}
1007     */

1008    protected void rewriteTypeOccurrences(final TextEditBasedChangeManager manager, final ASTRequestor requestor, final CompilationUnitRewrite rewrite, final ICompilationUnit unit, final CompilationUnit node, final Set JavaDoc replacements, final IProgressMonitor monitor) throws CoreException {
1009        // Not needed
1010
}
1011}
Popular Tags