KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-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.HashMap JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Map JavaDoc;
20 import java.util.Set JavaDoc;
21
22 import org.eclipse.text.edits.ReplaceEdit;
23 import org.eclipse.text.edits.TextEdit;
24
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.core.runtime.OperationCanceledException;
28 import org.eclipse.core.runtime.SubProgressMonitor;
29
30 import org.eclipse.jdt.core.ICompilationUnit;
31 import org.eclipse.jdt.core.IField;
32 import org.eclipse.jdt.core.IJavaElement;
33 import org.eclipse.jdt.core.IJavaProject;
34 import org.eclipse.jdt.core.IMember;
35 import org.eclipse.jdt.core.IMethod;
36 import org.eclipse.jdt.core.ISourceRange;
37 import org.eclipse.jdt.core.IType;
38 import org.eclipse.jdt.core.IWorkingCopy;
39 import org.eclipse.jdt.core.JavaModelException;
40 import org.eclipse.jdt.core.ToolFactory;
41 import org.eclipse.jdt.core.WorkingCopyOwner;
42 import org.eclipse.jdt.core.compiler.IProblem;
43 import org.eclipse.jdt.core.compiler.IScanner;
44 import org.eclipse.jdt.core.compiler.ITerminalSymbols;
45 import org.eclipse.jdt.core.dom.ASTNode;
46 import org.eclipse.jdt.core.dom.ArrayAccess;
47 import org.eclipse.jdt.core.dom.ArrayCreation;
48 import org.eclipse.jdt.core.dom.ArrayType;
49 import org.eclipse.jdt.core.dom.CompilationUnit;
50 import org.eclipse.jdt.core.dom.Expression;
51 import org.eclipse.jdt.core.dom.FieldDeclaration;
52 import org.eclipse.jdt.core.dom.IBinding;
53 import org.eclipse.jdt.core.dom.IMethodBinding;
54 import org.eclipse.jdt.core.dom.ITypeBinding;
55 import org.eclipse.jdt.core.dom.IVariableBinding;
56 import org.eclipse.jdt.core.dom.MethodDeclaration;
57 import org.eclipse.jdt.core.dom.Type;
58 import org.eclipse.jdt.core.dom.TypeDeclaration;
59 import org.eclipse.jdt.core.dom.VariableDeclaration;
60 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
61 import org.eclipse.jdt.core.search.IJavaSearchConstants;
62 import org.eclipse.jdt.core.search.IJavaSearchScope;
63 import org.eclipse.jdt.core.search.SearchPattern;
64
65 import org.eclipse.jface.text.Document;
66
67 import org.eclipse.jdt.internal.corext.Assert;
68 import org.eclipse.jdt.internal.corext.SourceRange;
69 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
70 import org.eclipse.jdt.internal.corext.codemanipulation.ImportRewrite;
71 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
72 import org.eclipse.jdt.internal.corext.dom.Bindings;
73 import org.eclipse.jdt.internal.corext.dom.TokenScanner;
74 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
75 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
76 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
77 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStringStatusContext;
78 import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
79 import org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringScopeFactory;
80 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ASTCreator;
81 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange;
82 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompositeOrTypeConstraint;
83 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintCollector;
84 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintOperator;
85 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintVariable;
86 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintVariableFactory;
87 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.DeclaringTypeVariable;
88 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ExpressionVariable;
89 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.FullConstraintCreator;
90 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ITypeConstraint;
91 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ParameterTypeVariable;
92 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.RawBindingVariable;
93 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ReturnTypeVariable;
94 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.SimpleTypeConstraint;
95 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.TypeBindings;
96 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.TypeConstraintFactory;
97 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.TypeVariable;
98 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
99 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
100 import org.eclipse.jdt.internal.corext.util.WorkingCopyUtil;
101
102 import org.eclipse.jdt.internal.ui.JavaPlugin;
103
104 import org.eclipse.jdt.ui.JavaUI;
105
106 import org.eclipse.ltk.core.refactoring.DocumentChange;
107 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
108 import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
109 import org.eclipse.ltk.core.refactoring.TextChange;
110
111 class ExtractInterfaceUtil {
112
113     private final ICompilationUnit fInputTypeWorkingCopy;
114     private final ICompilationUnit fSupertypeWorkingCopy;//can be null
115
private final WorkingCopyOwner fWorkingCopyOwner;
116     private static ICompilationUnit fCu;
117     private final IType fInputType;
118
119     private ExtractInterfaceUtil(ICompilationUnit inputTypeWorkingCopy, ICompilationUnit supertypeWorkingCopy, WorkingCopyOwner workingCopyOwner, IType inputType){
120         Assert.isNotNull(inputTypeWorkingCopy);
121         fSupertypeWorkingCopy= supertypeWorkingCopy;
122         fInputTypeWorkingCopy= inputTypeWorkingCopy;
123         fWorkingCopyOwner= workingCopyOwner;
124         fInputType= inputType;
125     }
126     
127     private static ConstraintVariable[] getAllOfType(ITypeConstraint[] constraints, ITypeBinding binding){
128         Set JavaDoc result= new HashSet JavaDoc();
129         ITypeBinding typeBinding= binding;
130         for (int i= 0; i < constraints.length; i++) {
131             ITypeConstraint constraint= constraints[i];
132             if (constraint.isSimpleTypeConstraint()){
133                 SimpleTypeConstraint simple= (SimpleTypeConstraint)constraint;
134                 if (simple.getLeft().isEqualBinding(typeBinding))
135                     result.add(simple.getLeft());
136                 if (simple.getRight().isEqualBinding(typeBinding))
137                     result.add(simple.getRight());
138
139                 if (simple.getRight().getBinding() != null && simple.getRight().getBinding().isArray() && Bindings.equals(simple.getRight().getBinding().getElementType(), typeBinding))
140                     result.add(simple.getRight());
141                 if (simple.getLeft().getBinding() != null && simple.getLeft().getBinding().isArray() && Bindings.equals(simple.getLeft().getBinding().getElementType(), typeBinding))
142                     result.add(simple.getLeft());
143                     
144             } else {
145                 CompositeOrTypeConstraint cotc= (CompositeOrTypeConstraint)constraint;
146                 result.addAll(Arrays.asList(getAllOfType(cotc.getConstraints(), binding)));
147             }
148         }
149         return (ConstraintVariable[]) result.toArray(new ConstraintVariable[result.size()]);
150     }
151
152     private ConstraintVariable[] getUpdatableVariables(ITypeBinding inputTypeBinding, IType theType, IType theSupertype, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException{
153         ITypeBinding interfaceBinding= getSuperTypeBinding(inputTypeBinding, theSupertype);
154         ICompilationUnit[] referringCus= getCusToParse(theType, theSupertype, pm, status);
155         checkCompileErrors(referringCus, status);
156         if (status.hasFatalError())
157             return new ConstraintVariable[0];
158         ITypeConstraint[] constraints= getConstraints(referringCus);
159         return getUpdatableVariables(constraints, inputTypeBinding, interfaceBinding);
160     }
161
162     private void checkCompileErrors(ICompilationUnit[] referringCus, RefactoringStatus status) throws JavaModelException {
163         for (int i= 0; i < referringCus.length; i++) {
164             ICompilationUnit unit= referringCus[i];
165             String JavaDoc source= unit.getSource();
166             CompilationUnit cuNode= getAST(unit);
167             IProblem[] problems= ASTNodes.getProblems(cuNode, ASTNodes.INCLUDE_ALL_PARENTS, ASTNodes.ERROR);
168             for (int j= 0; j < problems.length; j++) {
169                 IProblem problem= problems[j];
170                 if (problem.isError()) {
171                     RefactoringStatusContext context= new JavaStringStatusContext(source, new SourceRange(problem));
172                     status.addFatalError(problem.getMessage(), context);
173                 }
174             }
175         }
176     }
177
178     private static ITypeBinding getSuperTypeBinding(ITypeBinding typeBinding, IType superType) {
179         Set JavaDoc setOfAll= TypeBindings.getSuperTypes(typeBinding);
180         
181         // otherwise does not contain java.lang.Object
182
setOfAll.add(ASTCreator.createAST(fCu, null).getAST().resolveWellKnownType("java.lang.Object")); //$NON-NLS-1$
183

184         
185         ITypeBinding[] all= (ITypeBinding[]) setOfAll.toArray(new ITypeBinding[setOfAll.size()]);
186         for (int i= 0; i < all.length; i++) {
187             ITypeBinding superTypeBinding= all[i];
188             if (isBindingForType(superTypeBinding, superType))
189                 return superTypeBinding;
190         }
191         return null;
192     }
193
194     private static boolean isBindingForType(ITypeBinding typeBinding, IType type) {
195         if (! typeBinding.getName().equals(type.getElementName()))
196             return false;
197         //cannot compare names of unnamed/default packages (one is "UNNAMED", other is "")
198
if (typeBinding.getPackage().isUnnamed() != type.getPackageFragment().isDefaultPackage())
199             return false;
200         if (! typeBinding.getPackage().isUnnamed() && !type.getPackageFragment().isDefaultPackage()){
201             if (! typeBinding.getPackage().getName().equals(type.getPackageFragment().getElementName()))
202                 return false;
203         }
204         return true;
205     }
206
207     public static CompilationUnitRange[] updateReferences(TextChangeManager manager, IType inputType, IType supertypeToUse, WorkingCopyOwner workingCopyOwner, boolean updateInputTypeCu, IProgressMonitor pm, RefactoringStatus status, CodeGenerationSettings settings) throws CoreException{
208         ICompilationUnit typeWorkingCopy= inputType.getCompilationUnit();
209         fCu= typeWorkingCopy;
210         ExtractInterfaceUtil inst= new ExtractInterfaceUtil(typeWorkingCopy, supertypeToUse.getCompilationUnit(), workingCopyOwner, inputType);
211         ITypeBinding inputTypeBinding= getTypeBinding(inputType, workingCopyOwner);
212         ConstraintVariable[] updatableVars= inst.getUpdatableVariables(inputTypeBinding, inputType, supertypeToUse, pm, status);
213         if (status.hasFatalError())
214             return new CompilationUnitRange[0];
215         String JavaDoc typeName= inputType.getElementName();
216         CompilationUnitRange[] ranges= inst.getCompilationUnitRanges(updatableVars, inputType, inputTypeBinding);
217         Set JavaDoc cus= new HashSet JavaDoc();
218         Map JavaDoc cuToImportType= new HashMap JavaDoc();
219         for (int i= 0; i < ranges.length; i++) {
220             if (pm.isCanceled())
221                 throw new OperationCanceledException();
222             CompilationUnitRange range= ranges[i];
223             ICompilationUnit cu= range.getCompilationUnit();
224             if (updateInputTypeCu || ! cu.equals(typeWorkingCopy)){
225                 TextChange change= getTextChange(manager, cu);
226                 if (!cus.contains(cu)) {
227                     cus.add(cu);
228                     ImportRewrite importRewrite= new ImportRewrite(cu);
229                     cuToImportType.put(cu, importRewrite.addImport(supertypeToUse.getFullyQualifiedName()));
230                     TextEdit importEdit= importRewrite.createEdit(new Document(cu.getSource()));
231                     TextChangeCompatibility.addTextEdit(
232                         change,
233                         RefactoringCoreMessages.getString("ExtractInterfaceUtil.update_imports"), importEdit); //$NON-NLS-1$
234
}
235                 TextChangeCompatibility.addTextEdit(change,
236                     RefactoringCoreMessages.getString("ExtractInterfaceUtil.update_reference"), //$NON-NLS-1$
237
createTypeUpdateEdit(range.getSourceRange(), typeName, (String JavaDoc)cuToImportType.get(cu)));
238             }
239         }
240         return ranges;
241     }
242
243     public static TextChange getTextChange(TextChangeManager manager, ICompilationUnit cu) throws CoreException {
244         // workaround for bug 39630 CompilationUnitChange cannot handle in-memory-only compilation units
245
if (manager.containsChangesIn(cu) || cu.getResource().exists())
246             return manager.get(cu);
247         DocumentChange result= new DocumentChange(cu.getElementName(), new Document(cu.getSource()));
248         manager.manage(cu, result);
249         return result;
250     }
251
252     private static TextEdit createTypeUpdateEdit(ISourceRange sourceRange, String JavaDoc className, String JavaDoc interfaceName) {
253         int offset= sourceRange.getOffset() + sourceRange.getLength() - className.length();
254         return new ReplaceEdit(offset, className.length(), interfaceName);
255     }
256     
257     private static ConstraintVariable[] getUpdatableVariables(ITypeConstraint[] constraints, ITypeBinding classBinding, ITypeBinding interfaceBinding){
258         Set JavaDoc allVariablesOfType= new HashSet JavaDoc(Arrays.asList(getAllOfType(constraints, classBinding)));
259         Set JavaDoc badVariables= new HashSet JavaDoc();
260         Set JavaDoc badConstraints= new HashSet JavaDoc();
261         ConstraintVariable[] initialBad= getInitialBad(allVariablesOfType, badVariables, badConstraints, constraints, interfaceBinding);
262         if (initialBad == null || initialBad.length == 0)//TODO to be removed after it's optimized
263
return (ConstraintVariable[]) allVariablesOfType.toArray(new ConstraintVariable[allVariablesOfType.size()]);
264         badVariables.addAll(Arrays.asList(initialBad));
265         boolean repeat= false;
266         do{
267             //TODO can optimize here - don't have to walk the whole constraints array, bad would be enough
268
int sizeOfBad= badVariables.size();
269             for (int i= 0; i < constraints.length; i++) {
270                 ITypeConstraint constraint= constraints[i];
271                 if(! constraint.isSimpleTypeConstraint())
272                     continue;
273                 SimpleTypeConstraint con= (SimpleTypeConstraint)constraint;
274                 ConstraintVariable left= con.getLeft();
275                 ConstraintVariable right= con.getRight();
276                 if (allVariablesOfType.contains(left) && badVariables.contains(right) && ! badVariables.contains(left))
277                     badVariables.add(left);
278                 if (con.isEqualsConstraint() || con.isDefinesConstraint()){
279                     if (allVariablesOfType.contains(right) && badVariables.contains(left) && ! badVariables.contains(right))
280                         badVariables.add(right);
281                 }
282             }
283             repeat= sizeOfBad < badVariables.size();
284         } while(repeat);
285         Set JavaDoc updatable= new HashSet JavaDoc(allVariablesOfType);
286         updatable.removeAll(badVariables);
287         return (ConstraintVariable[]) updatable.toArray(new ConstraintVariable[updatable.size()]);
288     }
289     
290     private static ConstraintVariable[] getInitialBad(Set JavaDoc setOfAll, Set JavaDoc badVariables, Set JavaDoc badConstraints, ITypeConstraint[] constraints, ITypeBinding interfaceBinding){
291         ConstraintVariable interfaceVariable= new RawBindingVariable(interfaceBinding);
292         for (int i= 0; i < constraints.length; i++) {
293             ITypeConstraint constraint= constraints[i];
294             if (constraint.isSimpleTypeConstraint()){
295                 SimpleTypeConstraint simple= (SimpleTypeConstraint)constraint;
296                 if (simple.isSubtypeConstraint() && canAddLeftSideToInitialBadSet(simple, setOfAll, interfaceVariable)) {
297                     badVariables.add(simple.getLeft());
298                     badConstraints.add(simple);
299                 }
300             } else if (constraint instanceof CompositeOrTypeConstraint){
301                 ITypeConstraint[] subConstraints= ((CompositeOrTypeConstraint)constraint).getConstraints();
302                 if (canAddLeftSideToInitialBadSet(subConstraints, setOfAll, interfaceVariable)) {
303                     badVariables.add(((SimpleTypeConstraint)subConstraints[0]).getLeft());
304                     badConstraints.add(subConstraints[0]);
305                     badConstraints.add(constraint);
306                 }
307             }
308         }
309         return (ConstraintVariable[]) badVariables.toArray(new ConstraintVariable[badVariables.size()]);
310     }
311     
312     private static boolean canAddLeftSideToInitialBadSet(SimpleTypeConstraint sc, Set JavaDoc setOfAll, ConstraintVariable interfaceVariable) {
313         ConstraintVariable left= sc.getLeft();
314         ConstraintVariable right= sc.getRight();
315         if (! (left instanceof ExpressionVariable) && ! (left instanceof TypeVariable))
316             return false;
317         else if (! setOfAll.contains(left))
318             return false;
319         else if (interfaceVariable.isSubtypeOf(right))
320             return false;
321         //DeclaringTypeVariables are different - they can never be updated by this refactoring
322
else if (setOfAll.contains(right) && ! (right instanceof DeclaringTypeVariable))
323             return false;
324         else if (right instanceof DeclaringTypeVariable && right.getBinding() == null)
325             return false; // calls to [].length do not give rise to badness
326
else
327             return true;
328     }
329
330     private static boolean canAddLeftSideToInitialBadSet(ITypeConstraint[] subConstraints, Set JavaDoc setOfAll, ConstraintVariable interfaceVariable) {
331         if (subConstraints.length == 0)
332             return false;
333         if (! allAreSimpleConstraints(subConstraints))
334             return false;
335         
336         SimpleTypeConstraint[] simpleTypeConstraints= toSimpleConstraintArray(subConstraints);
337         if (! allHaveSameLeftSide(simpleTypeConstraints))
338             return false;
339         
340         ConstraintVariable left= (simpleTypeConstraints[0]).getLeft();
341         if (! (left instanceof ExpressionVariable))
342             return false;
343         if (! setOfAll.contains(left))
344             return false;
345         if (rightSideIsSubtypeOf(simpleTypeConstraints, interfaceVariable))
346             return false;
347         return true;
348     }
349
350     private static boolean rightSideIsSubtypeOf(SimpleTypeConstraint[] simpleTypeConstraints, ConstraintVariable interfaceVariable) {
351         for (int i= 0; i < simpleTypeConstraints.length; i++) {
352             ConstraintVariable right= simpleTypeConstraints[i].getRight();
353             if (right.isSubtypeOf(interfaceVariable))
354                 return true;
355         }
356         return false;
357     }
358     
359     private static SimpleTypeConstraint[] toSimpleConstraintArray(ITypeConstraint[] subConstraints) {
360         List JavaDoc result= Arrays.asList(subConstraints);
361         return (SimpleTypeConstraint[]) result.toArray(new SimpleTypeConstraint[result.size()]);
362     }
363
364     private static boolean allAreSimpleConstraints(ITypeConstraint[] subConstraints) {
365         for (int i= 0; i < subConstraints.length; i++) {
366             if (! subConstraints[i].isSimpleTypeConstraint())
367                 return false;
368         }
369         return true;
370     }
371
372     private static boolean allHaveSameLeftSide(SimpleTypeConstraint[] constraints) {
373         Assert.isTrue(constraints.length > 0);
374         ConstraintVariable first= constraints[0].getLeft();
375         for (int i= 1; i < constraints.length; i++) {
376             if (! first.equals(constraints[i].getLeft()))
377                 return false;
378         }
379         return true;
380     }
381
382     private ITypeConstraint[] getConstraints(ICompilationUnit[] referringCus) {
383         Set JavaDoc result= new HashSet JavaDoc();
384         ConstraintCollector collector= new ConstraintCollector(new ExtractInterfaceConstraintCreator(fInputType));
385         
386         for (int i= 0; i < referringCus.length; i++) {
387             ICompilationUnit unit= referringCus[i];
388             getAST(unit).accept(collector);
389             result.addAll(Arrays.asList(collector.getConstraints()));
390             collector.clear();
391         }
392         return (ITypeConstraint[]) result.toArray(new ITypeConstraint[result.size()]);
393     }
394     
395     private CompilationUnit getAST(ICompilationUnit unit) {
396         return ASTCreator.createAST(unit, fWorkingCopyOwner);
397     }
398
399     /*
400      * we need to parse not only the cus that reference the type directly but also those that
401      * reference a field or a method that reference the type. this method is used to find these cus.
402      */

403     private ICompilationUnit[] getCusToParse(IType theType, IType theSupertype, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException{
404         try{
405             pm.beginTask("", 2); //$NON-NLS-1$
406
SearchPattern pattern= SearchPattern.createPattern(theType, IJavaSearchConstants.REFERENCES);
407             IJavaSearchScope scope= RefactoringScopeFactory.create(theType);
408             ICompilationUnit[] workingCopies= getWorkingCopies(theType.getCompilationUnit(), theSupertype.getCompilationUnit());
409             if (workingCopies.length == 0)
410                 workingCopies= null;
411             SearchResultGroup[] typeReferences= RefactoringSearchEngine.search(pattern, scope, new SubProgressMonitor(pm, 1), workingCopies, status);
412             ICompilationUnit[] typeReferencingCus= getCus(typeReferences);
413             ICompilationUnit[] fieldAndMethodReferencingCus= fieldAndMethodReferringCus(theType, typeReferences, workingCopies, new SubProgressMonitor(pm, 1), status);
414             return merge(fieldAndMethodReferencingCus, typeReferencingCus);
415         } finally{
416             pm.done();
417         }
418     }
419
420     private ASTNode[] getAstNodes(SearchResultGroup searchResultGroup) {
421         ICompilationUnit cu= searchResultGroup.getCompilationUnit();
422         if (cu == null)
423             return new ASTNode[0];
424         CompilationUnit cuNode= getAST(cu);
425         return ASTNodeSearchUtil.getAstNodes(searchResultGroup.getSearchResults(), cuNode);
426     }
427     
428     private ICompilationUnit[] fieldAndMethodReferringCus(IType theType, SearchResultGroup[] typeReferences, ICompilationUnit[] wcs, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException {
429         SearchPattern pattern= createPatternForReferencingFieldsAndMethods(typeReferences);
430         if (pattern == null)
431             return new ICompilationUnit[0];
432         IJavaSearchScope scope= RefactoringScopeFactory.create(theType);
433         ICompilationUnit[] units= RefactoringSearchEngine.findAffectedCompilationUnits(pattern, scope, pm, status);
434         Set JavaDoc result= new HashSet JavaDoc(units.length);
435         for (int i= 0; i < units.length; i++) {
436             result.add(getUnproceededElement(units[i], wcs));
437         }
438         return (ICompilationUnit[]) result.toArray(new ICompilationUnit[result.size()]);
439     }
440
441     private static ICompilationUnit getUnproceededElement(ICompilationUnit unit, ICompilationUnit[] wcs) {
442         if (wcs == null)
443             return unit;
444         for (int i= 0; i < wcs.length; i++) {
445             if (proceeds(wcs[i], unit))
446                 return wcs[i];
447         }
448         return unit;
449     }
450
451     private static boolean proceeds(ICompilationUnit wc, ICompilationUnit unit) {
452         return wc.getResource() == null || wc.getResource().equals(unit.getResource());
453     }
454
455     private SearchPattern createPatternForReferencingFieldsAndMethods(SearchResultGroup[] typeReferences) throws JavaModelException {
456         return RefactoringSearchEngine.createOrPattern(getReferencingFieldsAndMethods(typeReferences), IJavaSearchConstants.ALL_OCCURRENCES);
457     }
458
459     private IMethod[] getReferencingMethods(ASTNode[] typeReferenceNodes) throws JavaModelException {
460         List JavaDoc result= new ArrayList JavaDoc();
461         for (int i= 0; i < typeReferenceNodes.length; i++) {
462             ASTNode node= typeReferenceNodes[i];
463             IJavaProject scope= ASTCreator.getCu(node).getJavaProject();
464             IMethod method= getMethod(node, scope);
465             if (method != null)
466                 result.add(method);
467         }
468         return (IMethod[]) result.toArray(new IMethod[result.size()]);
469     }
470
471     private IField[] getReferencingFields(ASTNode[] typeReferenceNodes) throws JavaModelException {
472         List JavaDoc result= new ArrayList JavaDoc();
473         for (int i= 0; i < typeReferenceNodes.length; i++) {
474             ASTNode node= typeReferenceNodes[i];
475             IJavaProject scope= ASTCreator.getCu(node).getJavaProject();
476             result.addAll(Arrays.asList(getFields(node, scope)));
477         }
478         return (IField[]) result.toArray(new IField[result.size()]);
479     }
480     
481     private IMember[] getReferencingFieldsAndMethods(SearchResultGroup[] typeReferences) throws JavaModelException {
482         List JavaDoc result= new ArrayList JavaDoc();
483         for (int i= 0; i < typeReferences.length; i++) {
484             SearchResultGroup group= typeReferences[i];
485             ASTNode[] typeReferenceNodes= getAstNodes(group);
486             result.addAll(Arrays.asList(getReferencingMethods(typeReferenceNodes)));
487             result.addAll(Arrays.asList(getReferencingFields(typeReferenceNodes)));
488         }
489         return (IMember[]) result.toArray(new IMember[result.size()]);
490     }
491
492     private static IMethod getMethod(ASTNode node, IJavaProject scope) throws JavaModelException {
493         if (node instanceof Type && node.getParent() instanceof MethodDeclaration){
494             MethodDeclaration declaration= (MethodDeclaration)node.getParent();
495             IMethodBinding binding= declaration.resolveBinding();
496             if (binding != null)
497                 return Bindings.findMethod(binding, scope);
498         } else if (node instanceof Type && isMethodParameter(node.getParent())){
499             MethodDeclaration declaration= (MethodDeclaration)node.getParent().getParent();
500             IMethodBinding binding= declaration.resolveBinding();
501             if (binding != null)
502                 return Bindings.findMethod(binding, scope);
503         }
504         return null;
505     }
506
507     private static boolean isMethodParameter(ASTNode node){
508         return (node instanceof VariableDeclaration) &&
509                (node.getParent() instanceof MethodDeclaration) &&
510                 ((MethodDeclaration)node.getParent()).parameters().contains(node);
511     }
512     
513     private static IField[] getFields(ASTNode node, IJavaProject scope) throws JavaModelException {
514         if (node instanceof Type && node.getParent() instanceof FieldDeclaration){
515             FieldDeclaration parent= (FieldDeclaration)node.getParent();
516             if (parent.getType() == node){
517                 List JavaDoc result= new ArrayList JavaDoc(parent.fragments().size());
518                 for (Iterator JavaDoc iter= parent.fragments().iterator(); iter.hasNext();) {
519                     VariableDeclarationFragment fragment= (VariableDeclarationFragment) iter.next();
520                     IField field= getField(fragment, scope);
521                     if (field != null)
522                         result.add(field);
523                 }
524                 return (IField[]) result.toArray(new IField[result.size()]);
525             }
526         }
527         return new IField[0];
528     }
529
530     private static IField getField(VariableDeclarationFragment fragment, IJavaProject in) throws JavaModelException {
531         IBinding binding= fragment.getName().resolveBinding();
532         if (! (binding instanceof IVariableBinding))
533             return null;
534         IVariableBinding variableBinding= (IVariableBinding)binding;
535         if (! variableBinding.isField())
536             return null;
537         return Bindings.findField(variableBinding, in);
538     }
539
540     private static ICompilationUnit[] merge(ICompilationUnit[] array1, ICompilationUnit[] array2){
541         Set JavaDoc result= new HashSet JavaDoc();
542         result.addAll(Arrays.asList(array1));
543         result.addAll(Arrays.asList(array2));
544         return (ICompilationUnit[]) result.toArray(new ICompilationUnit[result.size()]);
545     }
546     
547     private static ICompilationUnit[] getCus(SearchResultGroup[] groups) {
548         List JavaDoc result= new ArrayList JavaDoc(groups.length);
549         for (int i= 0; i < groups.length; i++) {
550             SearchResultGroup group= groups[i];
551             ICompilationUnit cu= group.getCompilationUnit();
552             if (cu != null)
553                 result.add(WorkingCopyUtil.getWorkingCopyIfExists(cu));
554         }
555         return (ICompilationUnit[]) result.toArray(new ICompilationUnit[result.size()]);
556     }
557
558     private static ICompilationUnit[] getWorkingCopies(ICompilationUnit precedingWC1, ICompilationUnit precedingWC2) {
559         if (JavaPlugin.USE_WORKING_COPY_OWNERS) {
560             ArrayList JavaDoc result= new ArrayList JavaDoc(2);
561             if (precedingWC1 != null && precedingWC1.isWorkingCopy()) {
562                 result.add(precedingWC1);
563             }
564             if (precedingWC2 != null && precedingWC2.isWorkingCopy()) {
565                 result.add(precedingWC2);
566             }
567             return (ICompilationUnit[]) result.toArray(new ICompilationUnit[result.size()]);
568         }
569         
570         
571         // XXX: This is a layer breaker - should not access jdt.ui
572
IWorkingCopy[] copies= JavaUI.getSharedWorkingCopiesOnClasspath();
573         Set JavaDoc result= new HashSet JavaDoc(copies.length);
574         ICompilationUnit original1= null, original2= null;
575         if (precedingWC1 != null && precedingWC1.isWorkingCopy()) {
576             result.add(precedingWC1);
577             original1= precedingWC1.getPrimary();
578         }
579         if (precedingWC2 != null && precedingWC2.isWorkingCopy()) {
580             result.add(precedingWC2);
581             original2= precedingWC2.getPrimary();
582         }
583         for (int i= 0; i < copies.length; i++) {
584             IWorkingCopy copy= copies[i];
585             if (copy.isWorkingCopy() && copy instanceof ICompilationUnit){
586                 IJavaElement original= copy.getOriginalElement();
587                 if (!original.equals(original1) && !original.equals(original2))
588                     result.add(copy);
589             }
590         }
591         return (ICompilationUnit[]) result.toArray(new ICompilationUnit[result.size()]);
592     }
593
594     private static ITypeBinding getTypeBinding(IType theType, WorkingCopyOwner workingCopyOwner) throws JavaModelException {
595         return getTypeDeclarationNode(theType, workingCopyOwner).resolveBinding();
596     }
597
598     private static TypeDeclaration getTypeDeclarationNode(IType theType, WorkingCopyOwner workingCopyOwner) throws JavaModelException {
599         return ASTNodeSearchUtil.getTypeDeclarationNode(theType, ASTCreator.createAST(theType.getCompilationUnit(), workingCopyOwner));
600     }
601
602     private CompilationUnitRange[] getCompilationUnitRanges(ConstraintVariable[] variables, IType inputType, ITypeBinding inputTypeBinding) throws CoreException {
603         Set JavaDoc ranges= new HashSet JavaDoc();
604         IJavaProject scope= inputType.getJavaProject(); //TODO check if scope is correct
605
for (int i= 0; i < variables.length; i++) {
606             CompilationUnitRange range= getRange(variables[i], scope, inputTypeBinding);
607             if (range != null)
608                 ranges.add(range);
609         }
610         return (CompilationUnitRange[]) ranges.toArray(new CompilationUnitRange[ranges.size()]);
611     }
612     
613     private CompilationUnitRange getRange(ConstraintVariable variable, IJavaProject scope, ITypeBinding inputTypeBinding) throws CoreException {
614         if (variable instanceof DeclaringTypeVariable)
615             return null;
616         else if (variable instanceof RawBindingVariable)
617             return null;
618         else if (variable instanceof ParameterTypeVariable)
619             return getRange((ParameterTypeVariable)variable, scope);
620         else if (variable instanceof ReturnTypeVariable)
621             return getRange((ReturnTypeVariable)variable, scope);
622         else if (variable instanceof TypeVariable)
623             return getRange((TypeVariable)variable);
624         else if (variable instanceof ExpressionVariable)
625             return getRange((ExpressionVariable)variable, inputTypeBinding);
626         else //TODO is this enough?
627
return null;
628     }
629
630     private CompilationUnitRange getRange(ExpressionVariable variable, ITypeBinding inputTypeBinding) {
631         if (inputTypeBinding == null) return null;
632         if (variable.getExpressionType() == ASTNode.SIMPLE_NAME || variable.getExpressionType() == ASTNode.QUALIFIED_NAME) {
633             if (Bindings.equals(inputTypeBinding, variable.getExpressionBinding()))
634                 return variable.getCompilationUnitRange();
635         }
636         return null;
637     }
638
639     private CompilationUnitRange getRange(TypeVariable variable) {
640         return variable.getCompilationUnitRange();
641     }
642
643     private CompilationUnitRange getRange(ReturnTypeVariable variable, IJavaProject scope) throws CoreException {
644         IMethodBinding methodBinding= variable.getMethodBinding();
645         IMethod method= getMethod(methodBinding, scope);
646         if (method == null)
647             return null;
648         return new CompilationUnitRange(method.getCompilationUnit(), getReturnTypeRange(method));
649     }
650     
651     private CompilationUnitRange getRange(ParameterTypeVariable variable, IJavaProject scope) throws CoreException {
652         IMethodBinding methodBinding= variable.getMethodBinding();
653         int paramIndex= variable.getParameterIndex();
654         IMethod method= getMethod(methodBinding, scope);
655         if (method == null)
656             return null;
657         return new CompilationUnitRange(method.getCompilationUnit(), getParameterTypeRange(method, paramIndex));
658     }
659
660     private static ISourceRange getReturnTypeRange(IMethod method) throws CoreException {
661         IScanner scanner= ToolFactory.createScanner(false, false, false, false);
662         scanner.setSource(method.getSource().toCharArray());
663         TokenScanner tokenScanner= new TokenScanner(scanner);
664         skipModifiers(tokenScanner);
665         return new SourceRange(method.getSourceRange().getOffset() + tokenScanner.getCurrentStartOffset(), tokenScanner.getCurrentLength());
666     }
667
668     private static void skipModifiers(TokenScanner scanner) throws CoreException {
669         int token= scanner.readNext(true);
670         while (token != ITerminalSymbols.TokenNameEOF) {
671             if (!TokenScanner.isModifier(token))
672                 return;
673             token= scanner.readNext(true);
674         }
675     }
676
677     private static ISourceRange getParameterTypeRange(IMethod method, int paramIndex) throws CoreException {
678         Assert.isTrue(0 <= paramIndex, "incorrect parameter"); //$NON-NLS-1$
679
Assert.isTrue(paramIndex < method.getNumberOfParameters(), "too few method parameters"); //$NON-NLS-1$
680
IScanner scanner= ToolFactory.createScanner(false, false, false, false);
681         scanner.setSource(method.getSource().toCharArray());
682         TokenScanner tokenScanner= new TokenScanner(scanner);
683         tokenScanner.readToToken(ITerminalSymbols.TokenNameLPAREN);
684         for (int i= 0; i < paramIndex; i++) {
685             tokenScanner.readToToken(ITerminalSymbols.TokenNameCOMMA);
686         }
687         tokenScanner.readNext(true);
688         return new SourceRange(method.getSourceRange().getOffset() + tokenScanner.getCurrentStartOffset(), tokenScanner.getCurrentLength());
689     }
690
691     private IMethod getMethod(IMethodBinding methodBinding, IJavaProject scope) throws JavaModelException {
692         IMethod method= Bindings.findMethod(methodBinding, scope);
693         IJavaElement e1= JavaModelUtil.findInCompilationUnit(fInputTypeWorkingCopy, method);
694         if (e1 instanceof IMethod){
695             method= (IMethod) e1;
696         } else if (fSupertypeWorkingCopy != null){
697             e1= JavaModelUtil.findInCompilationUnit(fSupertypeWorkingCopy, method);
698             if (e1 instanceof IMethod)
699                 method= (IMethod) e1;
700         }
701         return method;
702     }
703     
704     private static class ExtractInterfaceConstraintCreator extends FullConstraintCreator{
705
706         public ExtractInterfaceConstraintCreator(final IType inputType){
707             super(new ConstraintVariableFactory(), new TypeConstraintFactory(){
708                 public boolean filter(ConstraintVariable v1, ConstraintVariable v2, ConstraintOperator o){
709                     ITypeBinding v1Binding= v1.getBinding();
710                     ITypeBinding v2Binding= v2.getBinding();
711                     if (v1Binding != null && v2Binding != null){
712                         String JavaDoc inputTypeName= inputType.getFullyQualifiedName();
713                         String JavaDoc v1Name= (!v1Binding.isArray()) ? v1Binding.getQualifiedName()
714                                                               : v1Binding.getElementType().getQualifiedName();
715                         String JavaDoc v2Name= (!v2Binding.isArray()) ? v2Binding.getQualifiedName()
716                                                               : v2Binding.getElementType().getQualifiedName();
717                         if (!v1Name.equals(inputTypeName) && !v2Name.equals(inputTypeName)){
718                             if (PRINT_STATS) fNrFiltered++;
719                             return true;
720                         }
721                     }
722                     return super.filter(v1, v2, o);
723                 }
724             });
725         }
726         
727         /* (non-Javadoc)
728          * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintCreator#create(org.eclipse.jdt.core.dom.ArrayCreation)
729          */

730         public ITypeConstraint[] create(ArrayCreation node) {
731             ConstraintVariable arrayCreationVar= getConstraintVariableFactory().makeExpressionOrTypeVariable(node, getContext());
732             ConstraintVariable typeVar= getConstraintVariableFactory().makeTypeVariable(node.getType());
733             ITypeConstraint[] equals= getConstraintFactory().createEqualsConstraint(arrayCreationVar, typeVar);
734             return equals;
735         }
736
737         /* (non-Javadoc)
738          * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintCreator#create(org.eclipse.jdt.core.dom.ArrayAccess)
739          */

740         public ITypeConstraint[] create(ArrayAccess node) {
741             Expression expression= node.getArray();
742             ITypeConstraint[] equals= getConstraintFactory().createEqualsConstraint(getConstraintVariableFactory().makeExpressionOrTypeVariable(node, getContext()), getConstraintVariableFactory().makeExpressionOrTypeVariable(expression, getContext()));
743             return equals;
744         }
745     
746         /* (non-Javadoc)
747          * @see org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintCreator#create(org.eclipse.jdt.core.dom.ArrayType)
748          */

749         public ITypeConstraint[] create(ArrayType node) {
750             ConstraintVariable component= getConstraintVariableFactory().makeTypeVariable(node.getComponentType());
751             ITypeConstraint[] equals= getConstraintFactory().createEqualsConstraint(getConstraintVariableFactory().makeTypeVariable(node), component);
752             return equals;
753         }
754     }
755 }
756
Popular Tags