KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > code > TargetProvider


1 /*******************************************************************************
2  * Copyright (c) 2000, 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  * Dmitry Stalnov (dstalnov@fusionone.com) - contributed fixes for:
11  * o Allow 'this' constructor to be inlined
12  * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38093)
13  *******************************************************************************/

14 package org.eclipse.jdt.internal.corext.refactoring.code;
15
16 import java.util.ArrayList JavaDoc;
17 import java.util.HashMap JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Map JavaDoc;
20 import java.util.Set JavaDoc;
21 import java.util.Stack JavaDoc;
22
23 import org.eclipse.core.runtime.Assert;
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.runtime.SubProgressMonitor;
26
27 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
28
29 import org.eclipse.jdt.core.ICompilationUnit;
30 import org.eclipse.jdt.core.IJavaElement;
31 import org.eclipse.jdt.core.IMethod;
32 import org.eclipse.jdt.core.IType;
33 import org.eclipse.jdt.core.JavaModelException;
34 import org.eclipse.jdt.core.dom.AST;
35 import org.eclipse.jdt.core.dom.ASTNode;
36 import org.eclipse.jdt.core.dom.ASTVisitor;
37 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
38 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
39 import org.eclipse.jdt.core.dom.BodyDeclaration;
40 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
41 import org.eclipse.jdt.core.dom.ConstructorInvocation;
42 import org.eclipse.jdt.core.dom.EnumDeclaration;
43 import org.eclipse.jdt.core.dom.FieldDeclaration;
44 import org.eclipse.jdt.core.dom.IBinding;
45 import org.eclipse.jdt.core.dom.IMethodBinding;
46 import org.eclipse.jdt.core.dom.ITypeBinding;
47 import org.eclipse.jdt.core.dom.Initializer;
48 import org.eclipse.jdt.core.dom.MethodDeclaration;
49 import org.eclipse.jdt.core.dom.MethodInvocation;
50 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
51 import org.eclipse.jdt.core.dom.TypeDeclaration;
52 import org.eclipse.jdt.core.search.IJavaSearchConstants;
53 import org.eclipse.jdt.core.search.SearchMatch;
54 import org.eclipse.jdt.core.search.SearchPattern;
55
56 import org.eclipse.jdt.internal.corext.SourceRange;
57 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
58 import org.eclipse.jdt.internal.corext.refactoring.IRefactoringSearchRequestor;
59 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
60 import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
61 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2;
62 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
63 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
64 import org.eclipse.jdt.internal.corext.util.SearchUtils;
65
66 /**
67  * A TargetProvider provides all targets that have to be adapted, i.e. all method invocations that should be inlined.
68  */

69 abstract class TargetProvider {
70
71     public static final boolean BUG_CORE_130317= true; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=130317
72

73     protected SourceProvider fSourceProvider;
74
75     //TODO: not used...
76
public void setSourceProvider(SourceProvider sourceProvider) {
77         Assert.isNotNull(sourceProvider);
78         fSourceProvider= sourceProvider;
79     }
80
81     public abstract void initialize();
82
83     public abstract ICompilationUnit[] getAffectedCompilationUnits(RefactoringStatus status, IProgressMonitor pm) throws JavaModelException;
84     
85     public abstract BodyDeclaration[] getAffectedBodyDeclarations(ICompilationUnit unit, IProgressMonitor pm);
86     
87     // constructor invocation is not an expression but a statement
88
public abstract ASTNode[] getInvocations(BodyDeclaration declaration, IProgressMonitor pm);
89     
90     public abstract RefactoringStatus checkActivation() throws JavaModelException;
91     
92     public abstract int getStatusSeverity();
93     
94     public boolean isSingle() {
95         return false;
96     }
97     
98     public static TargetProvider create(ICompilationUnit cu, MethodInvocation invocation) {
99         return new SingleCallTargetProvider(cu, invocation);
100     }
101
102     public static TargetProvider create(ICompilationUnit cu, SuperMethodInvocation invocation) {
103         return new SingleCallTargetProvider(cu, invocation);
104     }
105
106     public static TargetProvider create(ICompilationUnit cu, ConstructorInvocation invocation) {
107         return new SingleCallTargetProvider(cu, invocation);
108     }
109
110     public static TargetProvider create(MethodDeclaration declaration) {
111         IMethodBinding method= declaration.resolveBinding();
112         if (method == null)
113             return new ErrorTargetProvider(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.TargetProvider_method_declaration_not_unique));
114         ITypeBinding type= method.getDeclaringClass();
115         if (type.isLocal()) {
116             if (((IType) type.getJavaElement()).isBinary()) {
117                 return new ErrorTargetProvider(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.TargetProvider_cannot_local_method_in_binary));
118             } else {
119                 IType declaringClassOfLocal= (IType) type.getDeclaringClass().getJavaElement();
120                 return new LocalTypeTargetProvider(declaringClassOfLocal.getCompilationUnit(), declaration);
121             }
122         } else {
123             return new MemberTypeTargetProvider(declaration.resolveBinding());
124         }
125     }
126
127     public static TargetProvider create(IMethodBinding methodBinding) {
128         return new MemberTypeTargetProvider(methodBinding);
129     }
130     
131     static void fastDone(IProgressMonitor pm) {
132         if (pm == null)
133             return;
134         pm.beginTask("", 1); //$NON-NLS-1$
135
pm.worked(1);
136         pm.done();
137     }
138     
139     static class ErrorTargetProvider extends TargetProvider {
140         private RefactoringStatus fErrorStatus;
141         public ErrorTargetProvider(RefactoringStatus status) {
142             fErrorStatus= status;
143         }
144         public RefactoringStatus checkActivation() throws JavaModelException {
145             return fErrorStatus;
146         }
147         public void initialize() {
148         }
149         public ICompilationUnit[] getAffectedCompilationUnits(RefactoringStatus status, IProgressMonitor pm) throws JavaModelException {
150             return null;
151         }
152         public BodyDeclaration[] getAffectedBodyDeclarations(ICompilationUnit unit, IProgressMonitor pm) {
153             return null;
154         }
155         public ASTNode[] getInvocations(BodyDeclaration declaration, IProgressMonitor pm) {
156             return null;
157         }
158         public int getStatusSeverity() {
159             return 0;
160         }
161     }
162     
163     static class SingleCallTargetProvider extends TargetProvider {
164         private ICompilationUnit fCUnit;
165         private ASTNode fInvocation;
166         private boolean fIterated;
167         public SingleCallTargetProvider(ICompilationUnit cu, ASTNode invocation) {
168             Assert.isNotNull(cu);
169             Assert.isNotNull(invocation);
170             Assert.isTrue(Invocations.isInvocation(invocation));
171             fCUnit= cu;
172             fInvocation= invocation;
173         }
174         public void initialize() {
175             fIterated= false;
176         }
177         public ICompilationUnit[] getAffectedCompilationUnits(RefactoringStatus status, IProgressMonitor pm) {
178             return new ICompilationUnit[] { fCUnit };
179         }
180         public BodyDeclaration[] getAffectedBodyDeclarations(ICompilationUnit unit, IProgressMonitor pm) {
181             Assert.isTrue(unit == fCUnit);
182             if (fIterated)
183                 return new BodyDeclaration[0];
184             fastDone(pm);
185             return new BodyDeclaration[] {
186                 (BodyDeclaration)ASTNodes.getParent(fInvocation, BodyDeclaration.class)
187             };
188         }
189     
190         public ASTNode[] getInvocations(BodyDeclaration declaration, IProgressMonitor pm) {
191             fastDone(pm);
192             if (fIterated)
193                 return null;
194             fIterated= true;
195             return new ASTNode[] { fInvocation };
196         }
197         public RefactoringStatus checkActivation() throws JavaModelException {
198             return new RefactoringStatus();
199         }
200         public int getStatusSeverity() {
201             return RefactoringStatus.FATAL;
202         }
203         public boolean isSingle() {
204             return true;
205         }
206     }
207
208     private static class BodyData {
209         public BodyDeclaration fBody;
210         private List JavaDoc fInvocations;
211         public BodyData(BodyDeclaration declaration) {
212             fBody= declaration;
213         }
214         public void addInvocation(ASTNode node) {
215             if (fInvocations == null)
216                 fInvocations= new ArrayList JavaDoc(2);
217             fInvocations.add(node);
218         }
219         public ASTNode[] getInvocations() {
220             return (ASTNode[])fInvocations.toArray(new ASTNode[fInvocations.size()]);
221         }
222         public boolean hasInvocations() {
223             return fInvocations != null && !fInvocations.isEmpty();
224         }
225         public BodyDeclaration getDeclaration() {
226             return fBody;
227         }
228     }
229
230     private static class InvocationFinder extends ASTVisitor {
231         Map JavaDoc/*<BodyDeclaration, BodyData>*/ result= new HashMap JavaDoc(2);
232         Stack JavaDoc/*<BodyData>*/ fBodies= new Stack JavaDoc();
233         BodyData fCurrent;
234         private IMethodBinding fBinding;
235         public InvocationFinder(IMethodBinding binding) {
236             Assert.isNotNull(binding);
237             fBinding= binding.getMethodDeclaration();
238             Assert.isNotNull(fBinding);
239         }
240         public boolean visit(MethodInvocation node) {
241             if (matches(node.getName().resolveBinding()) && fCurrent != null) {
242                 fCurrent.addInvocation(node);
243             }
244             return true;
245         }
246         public boolean visit(SuperMethodInvocation node) {
247             if (matches(node.getName().resolveBinding()) && fCurrent != null) {
248                 fCurrent.addInvocation(node);
249             }
250             return true;
251         }
252         public boolean visit(ConstructorInvocation node) {
253             if (matches(node.resolveConstructorBinding()) && fCurrent != null) {
254                 fCurrent.addInvocation(node);
255             }
256             return true;
257         }
258         public boolean visit(ClassInstanceCreation node) {
259             if (matches(node.resolveConstructorBinding()) && fCurrent != null) {
260                 fCurrent.addInvocation(node);
261             }
262             return true;
263         }
264         public boolean visit(TypeDeclaration node) {
265             return visitType();
266         }
267         public void endVisit(TypeDeclaration node) {
268             endVisitType();
269         }
270         public boolean visit(EnumDeclaration node) {
271             return visitType();
272         }
273         public void endVisit(EnumDeclaration node) {
274             endVisitType();
275         }
276         public boolean visit(AnnotationTypeDeclaration node) {
277             return visitType();
278         }
279         public void endVisit(AnnotationTypeDeclaration node) {
280             endVisitType();
281         }
282         private boolean visitType() {
283             fBodies.add(fCurrent);
284             fCurrent= null;
285             return true;
286         }
287         private void endVisitType() {
288             fCurrent= (BodyData)fBodies.remove(fBodies.size() - 1);
289         }
290         public boolean visit(FieldDeclaration node) {
291             fBodies.add(fCurrent);
292             fCurrent= new BodyData(node);
293             return true;
294         }
295         public void endVisit(FieldDeclaration node) {
296             if (fCurrent.hasInvocations()) {
297                 result.put(node, fCurrent);
298             }
299             endVisitType();
300         }
301         public boolean visit(MethodDeclaration node) {
302             fBodies.add(fCurrent);
303             fCurrent= new BodyData(node);
304             return true;
305         }
306         public void endVisit(MethodDeclaration node) {
307             if (fCurrent.hasInvocations()) {
308                 result.put(node, fCurrent);
309             }
310             endVisitType();
311             
312         }
313         public boolean visit(Initializer node) {
314             fBodies.add(fCurrent);
315             fCurrent= new BodyData(node);
316             return true;
317         }
318         public void endVisit(Initializer node) {
319             if (fCurrent.hasInvocations()) {
320                 result.put(node, fCurrent);
321             }
322             endVisitType();
323         }
324         private boolean matches(IBinding binding) {
325             if (!(binding instanceof IMethodBinding))
326                 return false;
327             if (BUG_CORE_130317)
328                 return fBinding.getKey().equals(((IMethodBinding)binding).getMethodDeclaration().getKey());
329             else
330                 return fBinding.isEqualTo(((IMethodBinding)binding).getMethodDeclaration());
331         }
332     }
333     
334     private static class LocalTypeTargetProvider extends TargetProvider {
335         private ICompilationUnit fCUnit;
336         private MethodDeclaration fDeclaration;
337         private Map JavaDoc fBodies;
338         public LocalTypeTargetProvider(ICompilationUnit unit, MethodDeclaration declaration) {
339             Assert.isNotNull(unit);
340             Assert.isNotNull(declaration);
341             fCUnit= unit;
342             fDeclaration= declaration;
343         }
344         public void initialize() {
345             InvocationFinder finder= new InvocationFinder(fDeclaration.resolveBinding());
346             ASTNode type= ASTNodes.getParent(fDeclaration, AbstractTypeDeclaration.class);
347             type.accept(finder);
348             fBodies= finder.result;
349         }
350         public ICompilationUnit[] getAffectedCompilationUnits(RefactoringStatus status, IProgressMonitor pm) {
351             fastDone(pm);
352             return new ICompilationUnit[] { fCUnit };
353         }
354     
355         public BodyDeclaration[] getAffectedBodyDeclarations(ICompilationUnit unit, IProgressMonitor pm) {
356             Assert.isTrue(unit == fCUnit);
357             Set JavaDoc result= fBodies.keySet();
358             fastDone(pm);
359             return (BodyDeclaration[])result.toArray(new BodyDeclaration[result.size()]);
360         }
361     
362         public ASTNode[] getInvocations(BodyDeclaration declaration, IProgressMonitor pm) {
363             BodyData data= (BodyData)fBodies.get(declaration);
364             Assert.isNotNull(data);
365             fastDone(pm);
366             return data.getInvocations();
367         }
368     
369         public RefactoringStatus checkActivation() throws JavaModelException {
370             return new RefactoringStatus();
371         }
372         
373         public int getStatusSeverity() {
374             return RefactoringStatus.ERROR;
375         }
376     }
377     
378     private static class MemberTypeTargetProvider extends TargetProvider {
379         private final IMethodBinding fMethodBinding;
380         private Map JavaDoc fCurrentBodies;
381         public MemberTypeTargetProvider(IMethodBinding methodBinding) {
382             Assert.isNotNull(methodBinding);
383             fMethodBinding= methodBinding;
384         }
385         public void initialize() {
386             // do nothing.
387
}
388
389         public ICompilationUnit[] getAffectedCompilationUnits(final RefactoringStatus status, IProgressMonitor pm) throws JavaModelException {
390             IMethod method= (IMethod)fMethodBinding.getJavaElement();
391             Assert.isTrue(method != null);
392             final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(method, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE));
393             engine.setGranularity(RefactoringSearchEngine2.GRANULARITY_COMPILATION_UNIT);
394             engine.setFiltering(true, true);
395             engine.setScope(RefactoringScopeFactory.create(method));
396             engine.setRequestor(new IRefactoringSearchRequestor() {
397                 public SearchMatch acceptSearchMatch(SearchMatch match) {
398                     if (match.isInsideDocComment())
399                         return null;
400                     if (match.getAccuracy() == SearchMatch.A_INACCURATE) {
401                         Object JavaDoc element= match.getElement();
402                         if (element instanceof IJavaElement) {
403                             IJavaElement jElement= (IJavaElement)element;
404                             ICompilationUnit unit= (ICompilationUnit)jElement.getAncestor(IJavaElement.COMPILATION_UNIT);
405                             if (unit != null) {
406                                 status.addError(RefactoringCoreMessages.TargetProvider_inaccurate_match,
407                                     JavaStatusContext.create(unit, new SourceRange(match.getOffset(), match.getLength())));
408                                 return null;
409                             }
410                         }
411                         status.addError(RefactoringCoreMessages.TargetProvider_inaccurate_match);
412                         return null;
413                     } else {
414                         return match;
415                     }
416                 }
417             });
418             engine.searchPattern(new SubProgressMonitor(pm, 1));
419             return engine.getAffectedCompilationUnits();
420         }
421
422         public BodyDeclaration[] getAffectedBodyDeclarations(ICompilationUnit unit, IProgressMonitor pm) {
423             ASTNode root= new RefactoringASTParser(AST.JLS3).parse(unit, true);
424             InvocationFinder finder= new InvocationFinder(fMethodBinding);
425             root.accept(finder);
426             fCurrentBodies= finder.result;
427             Set JavaDoc result= fCurrentBodies.keySet();
428             fastDone(pm);
429             return (BodyDeclaration[])result.toArray(new BodyDeclaration[result.size()]);
430         }
431     
432         public ASTNode[] getInvocations(BodyDeclaration declaration, IProgressMonitor pm) {
433             BodyData data= (BodyData)fCurrentBodies.get(declaration);
434             Assert.isNotNull(data);
435             fastDone(pm);
436             return data.getInvocations();
437         }
438     
439         public RefactoringStatus checkActivation() throws JavaModelException {
440             return new RefactoringStatus();
441         }
442         
443         public int getStatusSeverity() {
444             return RefactoringStatus.ERROR;
445         }
446     }
447 }
448
Popular Tags