KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > editor > semantic > MethodExitDetector


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.java.editor.semantic;
20
21 import com.sun.source.tree.CatchTree;
22 import com.sun.source.tree.CompilationUnitTree;
23 import com.sun.source.tree.IfTree;
24 import com.sun.source.tree.MethodTree;
25 import com.sun.source.tree.MethodInvocationTree;
26 import com.sun.source.tree.NewClassTree;
27 import com.sun.source.tree.ReturnTree;
28 import com.sun.source.tree.ThrowTree;
29 import com.sun.source.tree.Tree;
30 import com.sun.source.tree.TryTree;
31 import com.sun.source.util.TreePath;
32 import com.sun.source.util.TreePathScanner;
33 import java.util.ArrayList JavaDoc;
34 import java.util.Collection JavaDoc;
35 import java.util.Collections JavaDoc;
36 import java.util.EnumSet JavaDoc;
37 import java.util.HashMap JavaDoc;
38 import java.util.HashSet JavaDoc;
39 import java.util.List JavaDoc;
40 import java.util.Map JavaDoc;
41 import java.util.Set JavaDoc;
42 import java.util.Stack JavaDoc;
43 import javax.lang.model.element.Element;
44 import javax.lang.model.element.ElementKind;
45 import javax.lang.model.element.ExecutableElement;
46 import javax.lang.model.type.TypeMirror;
47 import javax.lang.model.util.Types;
48 import javax.swing.text.Document JavaDoc;
49 import org.netbeans.api.java.source.CompilationInfo;
50 import org.netbeans.api.java.source.support.CancellableTreePathScanner;
51 import org.netbeans.modules.editor.highlights.spi.Highlight;
52
53 /**
54  *
55  * @author Jan Lahoda
56  */

57 public class MethodExitDetector extends CancellableTreePathScanner<Boolean JavaDoc, Stack JavaDoc<Tree>> {
58     
59     /** Creates a new instance of MethodExitDetector */
60     public MethodExitDetector() {
61     }
62     
63     private CompilationInfo info;
64     private Document JavaDoc doc;
65     private Set JavaDoc<Highlight> highlights;
66     private Collection JavaDoc<TypeMirror> exceptions;
67     private Stack JavaDoc<Map JavaDoc<TypeMirror, List JavaDoc<Highlight>>> exceptions2HighlightsStack;
68     
69     public Set JavaDoc<Highlight> process(CompilationInfo info, Document JavaDoc document, MethodTree methoddecl, Collection JavaDoc<Tree> excs) {
70         this.info = info;
71         this.doc = document;
72         this.highlights = new HashSet JavaDoc<Highlight>();
73         this.exceptions2HighlightsStack = new Stack JavaDoc<Map JavaDoc<TypeMirror, List JavaDoc<Highlight>>>();
74         this.exceptions2HighlightsStack.push(null);
75         
76         try {
77             Set JavaDoc<Highlight> result = new HashSet JavaDoc<Highlight>();
78             
79             CompilationUnitTree cu = info.getCompilationUnit();
80             
81             Boolean JavaDoc wasReturn = scan(TreePath.getPath(cu, methoddecl), null);
82             
83             if (isCanceled())
84                 return Collections.emptySet();
85             
86             if (excs == null) {
87                 //"return" exit point only if not searching for exceptions:
88
result.addAll(highlights);
89                 
90                 if (wasReturn != Boolean.TRUE) {
91                     int lastBracket = Utilities.findLastBracket(methoddecl, cu, info.getTrees().getSourcePositions(), document);
92                     
93                     if (lastBracket != (-1)) {
94                         //highlight the "fall over" exitpoint:
95
result.add(Utilities.createHighlight(cu, info.getTrees().getSourcePositions(), document, lastBracket, lastBracket + 1, EnumSet.of(ColoringAttributes.MARK_OCCURRENCES), MarkOccurencesHighlighter.ES_COLOR));
96                     }
97                 }
98             }
99             
100             List JavaDoc<TypeMirror> exceptions = null;
101             
102             if (excs != null) {
103                 exceptions = new ArrayList JavaDoc<TypeMirror>();
104                 
105                 for (Tree t : excs) {
106                     if (isCanceled())
107                         return Collections.emptySet();
108                     
109                     TypeMirror m = info.getTrees().getTypeMirror(TreePath.getPath(cu, t));
110                     
111                     if (m != null) {
112                         exceptions.add(m);
113                     }
114                 }
115             }
116             
117             Types t = info.getTypes();
118             
119             assert exceptions2HighlightsStack.size() == 1 : exceptions2HighlightsStack.size();
120             
121             Map JavaDoc<TypeMirror, List JavaDoc<Highlight>> exceptions2Highlights = exceptions2HighlightsStack.peek();
122             
123             //exceptions2Highlights may be null if the method is empty (or not finished, like "public void")
124
//see ExitPointsEmptyMethod and ExitPointsStartedMethod tests:
125
if (exceptions2Highlights != null) {
126                 for (TypeMirror type1 : exceptions2Highlights.keySet()) {
127                     if (isCanceled())
128                         return Collections.emptySet();
129                     
130                     boolean add = true;
131                     
132                     if (exceptions != null) {
133                         add = false;
134                         
135                         for (TypeMirror type2 : exceptions) {
136                             add |= t.isAssignable(type1, type2);
137                         }
138                     }
139                     
140                     if (add) {
141                         result.addAll(exceptions2Highlights.get(type1));
142                     }
143                 }
144             }
145             
146             return result;
147         } finally {
148             //clean-up:
149
this.info = null;
150             this.doc = null;
151             this.highlights = null;
152             this.exceptions2HighlightsStack = null;
153         }
154     }
155     
156     private void addToExceptionsMap(TypeMirror key, Highlight value) {
157         if (value == null)
158             return ;
159         
160         Map JavaDoc<TypeMirror, List JavaDoc<Highlight>> map = exceptions2HighlightsStack.peek();
161         
162         if (map == null) {
163             map = new HashMap JavaDoc<TypeMirror, List JavaDoc<Highlight>>();
164             exceptions2HighlightsStack.pop();
165             exceptions2HighlightsStack.push(map);
166         }
167         
168         List JavaDoc<Highlight> l = map.get(key);
169         
170         if (l == null) {
171             map.put(key, l = new ArrayList JavaDoc<Highlight>());
172         }
173         
174         l.add(value);
175     }
176     
177     private void doPopup() {
178         Map JavaDoc<TypeMirror, List JavaDoc<Highlight>> top = exceptions2HighlightsStack.pop();
179         
180         if (top == null)
181             return ;
182         
183         Map JavaDoc<TypeMirror, List JavaDoc<Highlight>> result = exceptions2HighlightsStack.pop();
184         
185         if (result == null) {
186             exceptions2HighlightsStack.push(top);
187             return ;
188         }
189         
190         for (TypeMirror key : top.keySet()) {
191             List JavaDoc<Highlight> topKey = top.get(key);
192             List JavaDoc<Highlight> resultKey = result.get(key);
193             
194             if (topKey == null)
195                 continue;
196             
197             if (resultKey == null) {
198                 result.put(key, topKey);
199                 continue;
200             }
201             
202             resultKey.addAll(topKey);
203         }
204         
205         exceptions2HighlightsStack.push(result);
206     }
207     
208     private Highlight createHighlight(TreePath tree) {
209         return Utilities.createHighlight(info.getCompilationUnit(), info.getTrees().getSourcePositions(), doc, tree, EnumSet.of(ColoringAttributes.MARK_OCCURRENCES), MarkOccurencesHighlighter.ES_COLOR);
210     }
211     
212     @Override JavaDoc
213     public Boolean JavaDoc visitTry(TryTree tree, Stack JavaDoc<Tree> d) {
214         exceptions2HighlightsStack.push(null);
215         
216         Boolean JavaDoc returnInTryBlock = scan(tree.getBlock(), d);
217         
218         boolean returnInCatchBlock = true;
219         
220         for (Tree t : tree.getCatches()) {
221             Boolean JavaDoc b = scan(t, d);
222             
223             returnInCatchBlock &= b == Boolean.TRUE;
224         }
225         
226         Boolean JavaDoc returnInFinallyBlock = scan(tree.getFinallyBlock(), d);
227         
228         doPopup();
229         
230         if (returnInTryBlock == Boolean.TRUE && returnInCatchBlock)
231             return Boolean.TRUE;
232         
233         return returnInFinallyBlock;
234     }
235     
236     @Override JavaDoc
237     public Boolean JavaDoc visitReturn(ReturnTree tree, Stack JavaDoc<Tree> d) {
238         if (exceptions == null) {
239             Highlight h = createHighlight(getCurrentPath());
240             
241             if (h != null) {
242                 highlights.add(h);
243             }
244         }
245         
246         super.visitReturn(tree, d);
247         return Boolean.TRUE;
248     }
249     
250     @Override JavaDoc
251     public Boolean JavaDoc visitCatch(CatchTree tree, Stack JavaDoc<Tree> d) {
252         TypeMirror type1 = info.getTrees().getTypeMirror(new TreePath(new TreePath(getCurrentPath(), tree.getParameter()), tree.getParameter().getType()));
253         Types t = info.getTypes();
254         
255         if (type1 != null) {
256             Set JavaDoc<TypeMirror> toRemove = new HashSet JavaDoc<TypeMirror>();
257             Map JavaDoc<TypeMirror, List JavaDoc<Highlight>> exceptions2Highlights = exceptions2HighlightsStack.peek();
258             
259             if (exceptions2Highlights != null) {
260                 for (TypeMirror type2 : exceptions2Highlights.keySet()) {
261                     if (t.isAssignable(type2, type1)) {
262                         toRemove.add(type2);
263                     }
264                 }
265                 
266                 for (TypeMirror type : toRemove) {
267                     exceptions2Highlights.remove(type);
268                 }
269             }
270             
271         }
272         
273         scan(tree.getParameter(), d);
274         return scan(tree.getBlock(), d);
275     }
276     
277     @Override JavaDoc
278     public Boolean JavaDoc visitMethodInvocation(MethodInvocationTree tree, Stack JavaDoc<Tree> d) {
279         Element el = info.getTrees().getElement(new TreePath(getCurrentPath(), tree.getMethodSelect()));
280         
281         if (el == null) {
282             System.err.println("Warning: decl == null");
283             System.err.println("tree=" + tree);
284         }
285         
286         if (el != null && el.getKind() == ElementKind.METHOD) {
287             for (TypeMirror m : ((ExecutableElement) el).getThrownTypes()) {
288                 addToExceptionsMap(m, createHighlight(getCurrentPath()));
289             }
290         }
291         
292         super.visitMethodInvocation(tree, d);
293         return null;
294     }
295     
296     @Override JavaDoc
297     public Boolean JavaDoc visitThrow(ThrowTree tree, Stack JavaDoc<Tree> d) {
298         addToExceptionsMap(info.getTrees().getTypeMirror(new TreePath(getCurrentPath(), tree.getExpression())), createHighlight(getCurrentPath()));
299         
300         super.visitThrow(tree, d);
301         
302         return Boolean.TRUE;
303     }
304     
305     @Override JavaDoc
306     public Boolean JavaDoc visitNewClass(NewClassTree tree, Stack JavaDoc<Tree> d) {
307         Element el = info.getTrees().getElement(getCurrentPath());
308         
309         if (el != null && el.getKind() == ElementKind.CONSTRUCTOR) {
310             for (TypeMirror m : ((ExecutableElement) el).getThrownTypes()) {
311                 addToExceptionsMap(m, createHighlight(getCurrentPath()));
312             }
313         }
314         
315         super.visitNewClass(tree, d);
316         return null;
317     }
318     
319     @Override JavaDoc
320     public Boolean JavaDoc visitMethod(MethodTree node, Stack JavaDoc<Tree> p) {
321         scan(node.getModifiers(), p);
322         scan(node.getReturnType(), p);
323         scan(node.getTypeParameters(), p);
324         scan(node.getParameters(), p);
325         scan(node.getThrows(), p);
326         return scan(node.getBody(), p);
327     }
328     
329     @Override JavaDoc
330     public Boolean JavaDoc visitIf(IfTree node, Stack JavaDoc<Tree> p) {
331         scan(node.getCondition(), p);
332         Boolean JavaDoc thenResult = scan(node.getThenStatement(), p);
333         Boolean JavaDoc elseResult = scan(node.getElseStatement(), p);
334         
335         if (thenResult == Boolean.TRUE && elseResult == Boolean.TRUE)
336             return Boolean.TRUE;
337         
338         return null;
339     }
340     
341 }
342
Popular Tags