1 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 ; 34 import java.util.Collection ; 35 import java.util.Collections ; 36 import java.util.EnumSet ; 37 import java.util.HashMap ; 38 import java.util.HashSet ; 39 import java.util.List ; 40 import java.util.Map ; 41 import java.util.Set ; 42 import java.util.Stack ; 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 ; 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 57 public class MethodExitDetector extends CancellableTreePathScanner<Boolean , Stack <Tree>> { 58 59 60 public MethodExitDetector() { 61 } 62 63 private CompilationInfo info; 64 private Document doc; 65 private Set <Highlight> highlights; 66 private Collection <TypeMirror> exceptions; 67 private Stack <Map <TypeMirror, List <Highlight>>> exceptions2HighlightsStack; 68 69 public Set <Highlight> process(CompilationInfo info, Document document, MethodTree methoddecl, Collection <Tree> excs) { 70 this.info = info; 71 this.doc = document; 72 this.highlights = new HashSet <Highlight>(); 73 this.exceptions2HighlightsStack = new Stack <Map <TypeMirror, List <Highlight>>>(); 74 this.exceptions2HighlightsStack.push(null); 75 76 try { 77 Set <Highlight> result = new HashSet <Highlight>(); 78 79 CompilationUnitTree cu = info.getCompilationUnit(); 80 81 Boolean wasReturn = scan(TreePath.getPath(cu, methoddecl), null); 82 83 if (isCanceled()) 84 return Collections.emptySet(); 85 86 if (excs == null) { 87 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 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 <TypeMirror> exceptions = null; 101 102 if (excs != null) { 103 exceptions = new ArrayList <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 <TypeMirror, List <Highlight>> exceptions2Highlights = exceptions2HighlightsStack.peek(); 122 123 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 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 <TypeMirror, List <Highlight>> map = exceptions2HighlightsStack.peek(); 161 162 if (map == null) { 163 map = new HashMap <TypeMirror, List <Highlight>>(); 164 exceptions2HighlightsStack.pop(); 165 exceptions2HighlightsStack.push(map); 166 } 167 168 List <Highlight> l = map.get(key); 169 170 if (l == null) { 171 map.put(key, l = new ArrayList <Highlight>()); 172 } 173 174 l.add(value); 175 } 176 177 private void doPopup() { 178 Map <TypeMirror, List <Highlight>> top = exceptions2HighlightsStack.pop(); 179 180 if (top == null) 181 return ; 182 183 Map <TypeMirror, List <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 <Highlight> topKey = top.get(key); 192 List <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 213 public Boolean visitTry(TryTree tree, Stack <Tree> d) { 214 exceptions2HighlightsStack.push(null); 215 216 Boolean returnInTryBlock = scan(tree.getBlock(), d); 217 218 boolean returnInCatchBlock = true; 219 220 for (Tree t : tree.getCatches()) { 221 Boolean b = scan(t, d); 222 223 returnInCatchBlock &= b == Boolean.TRUE; 224 } 225 226 Boolean 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 237 public Boolean visitReturn(ReturnTree tree, Stack <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 251 public Boolean visitCatch(CatchTree tree, Stack <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 <TypeMirror> toRemove = new HashSet <TypeMirror>(); 257 Map <TypeMirror, List <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 278 public Boolean visitMethodInvocation(MethodInvocationTree tree, Stack <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 297 public Boolean visitThrow(ThrowTree tree, Stack <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 306 public Boolean visitNewClass(NewClassTree tree, Stack <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 320 public Boolean visitMethod(MethodTree node, Stack <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 330 public Boolean visitIf(IfTree node, Stack <Tree> p) { 331 scan(node.getCondition(), p); 332 Boolean thenResult = scan(node.getThenStatement(), p); 333 Boolean 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 |