KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > rename > RippleMethodFinder


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 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.rename;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashSet JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Set JavaDoc;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.core.runtime.NullProgressMonitor;
21 import org.eclipse.core.runtime.OperationCanceledException;
22 import org.eclipse.core.runtime.SubProgressMonitor;
23
24 import org.eclipse.jdt.core.IMethod;
25 import org.eclipse.jdt.core.IType;
26 import org.eclipse.jdt.core.ITypeHierarchy;
27 import org.eclipse.jdt.core.JavaModelException;
28 import org.eclipse.jdt.core.WorkingCopyOwner;
29
30 import org.eclipse.jdt.internal.corext.Assert;
31 import org.eclipse.jdt.internal.corext.refactoring.Checks;
32 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
33 import org.eclipse.jdt.internal.corext.util.JdtFlags;
34
35 /**
36  * This class is used to find methods along the 'ripple'. When you rename a
37  * method that is declared in an interface, you must also rename its
38  * implementations. But because of multiple interface inheritance you have to go
39  * up and down the hierarchy to collect all the methods.
40  */

41 public class RippleMethodFinder {
42     
43     private RippleMethodFinder(){
44         //no instances
45
}
46     
47     /**
48      * Finds all methods along the 'ripple'.
49      *
50      * @param method an {@link IMethod} which must be "most abstract",
51      * i.e. it must not override or implement another method
52      * @param pm a {@link IProgressMonitor}
53      * @param owner a {@link WorkingCopyOwner}, or <code>null</code>
54      * @return the ripple methods
55      * @throws JavaModelException if something is wrong with <code>method</code> or its ripple.
56      */

57     public static IMethod[] getRelatedMethods(IMethod method, IProgressMonitor pm, WorkingCopyOwner owner) throws JavaModelException {
58         try{
59             if (! MethodChecks.isVirtual(method) && ! method.getDeclaringType().isInterface())
60                 return new IMethod[]{method};
61             
62             return getAllRippleMethods(method, pm, owner);
63         } finally{
64             pm.done();
65         }
66     }
67     
68     /*
69      * We use the following algorithm to find methods to rename:
70      * Input: type T, method m
71        Assumption: No supertype of T declares m
72        Output: variable result contains the list of types that declared the method to be renamed
73
74         result:= empty set // set of types that declare methods to rename
75         visited:= empty set //set of already visited types
76         q:= empty queue //queue of types to visit
77         q.insert(T)
78
79         while (!q.isEmpty()){
80             t:= q.remove();
81             //assert(t is an interface or declares m as virtual)
82             //assert(!visited.contains(t))
83             visited.add(t);
84             result.add(t);
85             forall: i in: t.subTypes do:
86                 if ((! visited.contains(i)) && (i declares m)) result.add(i);
87             forall: i in: t.subTypes do:
88                 q.insert(x)
89                     where x is any type satisfying the followowing:
90                     a. x is a supertype of i
91                     b. x is an interface and declares m or
92                         x declares m as a virtual method
93                     c. no supertype of x is an interface that declares m and
94                         no supertype of x is a class that declares m as a virtual method
95                     d. ! visited.contains(x)
96                     e. ! q.contains(x)
97         }
98      */

99     private static IMethod[] getAllRippleMethods(IMethod method, IProgressMonitor pm, WorkingCopyOwner owner) throws JavaModelException {
100         pm.beginTask("", 4); //$NON-NLS-1$
101
Set JavaDoc result= new HashSet JavaDoc();
102         Set JavaDoc visitedTypes= new HashSet JavaDoc();
103         List JavaDoc methodQueue= new ArrayList JavaDoc();
104         Set JavaDoc hierarchies= new HashSet JavaDoc();
105         methodQueue.add(method);
106         while (! methodQueue.isEmpty()){
107             IMethod m= (IMethod)methodQueue.remove(0);
108             
109             /* must check for binary - otherwise will go all the way on all types
110              * happens on toString() for example */

111             if (m.isBinary())
112                 continue;
113             IType type= m.getDeclaringType();
114             Assert.isTrue(! visitedTypes.contains(type), "! visitedTypes.contains(type)"); //$NON-NLS-1$
115
Assert.isTrue(type.isInterface() || declaresAsVirtual(type, method), "second condition"); //$NON-NLS-1$
116

117             visitedTypes.add(type);
118             result.add(m);
119             
120             IType[] subTypes= getAllSubtypes(pm, owner, type, hierarchies);
121             for (int i= 0; i < subTypes.length; i++){
122                 if (!visitedTypes.contains(subTypes[i])){
123                     IMethod subTypeMethod= Checks.findSimilarMethod(m, subTypes[i]);
124                     if (subTypeMethod != null)
125                         result.add(subTypeMethod);
126                 }
127             }
128             
129             for (int i= 0; i < subTypes.length; i++){
130                 IMethod toAdd= findAppropriateMethod(owner, visitedTypes, methodQueue, subTypes[i], method, new NullProgressMonitor());
131                 if (toAdd != null)
132                     methodQueue.add(toAdd);
133             }
134             if (pm.isCanceled())
135                 throw new OperationCanceledException();
136         }
137         return (IMethod[]) result.toArray(new IMethod[result.size()]);
138     }
139     
140     private static IType[] getAllSubtypes(IProgressMonitor pm, WorkingCopyOwner owner, IType type, Set JavaDoc cachedHierarchies) throws JavaModelException {
141         //first, try in the cached hierarchies
142
for (Iterator JavaDoc iter= cachedHierarchies.iterator(); iter.hasNext();) {
143             ITypeHierarchy hierarchy= (ITypeHierarchy) iter.next();
144             if (hierarchy.contains(type))
145                 return hierarchy.getAllSubtypes(type);
146         }
147         SubProgressMonitor subPm= new SubProgressMonitor(pm, 1);
148         ITypeHierarchy hierarchy= newTypeHierarchy(type, owner, subPm);
149         cachedHierarchies.add(hierarchy);
150         return hierarchy.getAllSubtypes(type);
151     }
152     
153     private static IMethod findAppropriateMethod(WorkingCopyOwner owner, Set JavaDoc visitedTypes, List JavaDoc methodQueue, IType type, IMethod method, IProgressMonitor pm) throws JavaModelException{
154         pm.beginTask(RefactoringCoreMessages.RippleMethodFinder_analizing_hierarchy, 1);
155         IType[] superTypes= newSupertypeHierarchy(type, owner, new SubProgressMonitor(pm, 1)).getAllSupertypes(type);
156         for (int i= 0; i< superTypes.length; i++){
157             IType t= superTypes[i];
158             if (visitedTypes.contains(t))
159                 continue;
160             IMethod found= Checks.findSimilarMethod(method, t);
161             if (found == null)
162                 continue;
163             if (! declaresAsVirtual(t, method))
164                 continue;
165             if (methodQueue.contains(found))
166                 continue;
167             return getTopMostMethod(owner, visitedTypes, methodQueue, method, t, new NullProgressMonitor());
168         }
169         return null;
170     }
171     
172     private static IMethod getTopMostMethod(WorkingCopyOwner owner, Set JavaDoc visitedTypes, List JavaDoc methodQueue, IMethod method, IType type, IProgressMonitor pm)throws JavaModelException{
173         pm.beginTask("", 1); //$NON-NLS-1$
174
IMethod methodInThisType= Checks.findSimilarMethod(method, type);
175         Assert.isTrue(methodInThisType != null);
176         IType[] superTypes= newSupertypeHierarchy(type, owner, new SubProgressMonitor(pm, 1)).getAllSupertypes(type);
177         for (int i= 0; i < superTypes.length; i++){
178             IType t= superTypes[i];
179             if (visitedTypes.contains(t))
180                 continue;
181             IMethod found= Checks.findSimilarMethod(method, t);
182             if (found == null)
183                 continue;
184             if (! declaresAsVirtual(t, method))
185                 continue;
186             if (methodQueue.contains(found))
187                 continue;
188             return getTopMostMethod(owner, visitedTypes, methodQueue, method, t, new NullProgressMonitor());
189         }
190         return methodInThisType;
191     }
192     
193     private static boolean declaresAsVirtual(IType type, IMethod m) throws JavaModelException{
194         IMethod found= Checks.findSimilarMethod(m, type);
195         if (found == null)
196             return false;
197         if (JdtFlags.isStatic(found))
198             return false;
199         if (JdtFlags.isPrivate(found))
200             return false;
201         return true;
202     }
203     
204     //---
205

206     private static ITypeHierarchy newTypeHierarchy(IType type, WorkingCopyOwner owner, IProgressMonitor pm) throws JavaModelException {
207         if (owner == null)
208             return type.newTypeHierarchy(pm);
209         else
210             return type.newTypeHierarchy(owner, pm);
211     }
212
213     private static ITypeHierarchy newSupertypeHierarchy(IType type, WorkingCopyOwner owner, IProgressMonitor pm) throws JavaModelException {
214         if (owner == null)
215             return type.newSupertypeHierarchy(pm);
216         else
217             return type.newSupertypeHierarchy(owner, pm);
218     }
219 }
220
Popular Tags