40 import javax.tools.JavaCompiler; |
40 import javax.tools.JavaCompiler; |
41 import javax.tools.SimpleJavaFileObject; |
41 import javax.tools.SimpleJavaFileObject; |
42 import javax.tools.StandardJavaFileManager; |
42 import javax.tools.StandardJavaFileManager; |
43 import javax.tools.ToolProvider; |
43 import javax.tools.ToolProvider; |
44 |
44 |
|
45 import com.sun.source.tree.BlockTree; |
45 import com.sun.source.tree.CompilationUnitTree; |
46 import com.sun.source.tree.CompilationUnitTree; |
|
47 import com.sun.source.tree.ConditionalExpressionTree; |
|
48 import com.sun.source.tree.IdentifierTree; |
46 import com.sun.source.tree.LambdaExpressionTree; |
49 import com.sun.source.tree.LambdaExpressionTree; |
|
50 import com.sun.source.tree.MethodInvocationTree; |
|
51 import com.sun.source.tree.MethodTree; |
47 import com.sun.source.tree.Scope; |
52 import com.sun.source.tree.Scope; |
|
53 import com.sun.source.tree.Tree; |
48 import com.sun.source.tree.VariableTree; |
54 import com.sun.source.tree.VariableTree; |
49 import com.sun.source.util.JavacTask; |
55 import com.sun.source.util.JavacTask; |
|
56 import com.sun.source.util.TaskEvent; |
|
57 import com.sun.source.util.TaskListener; |
50 import com.sun.source.util.TreePath; |
58 import com.sun.source.util.TreePath; |
51 import com.sun.source.util.TreePathScanner; |
59 import com.sun.source.util.TreePathScanner; |
52 import com.sun.source.util.Trees; |
60 import com.sun.source.util.Trees; |
53 |
61 |
54 import com.sun.tools.javac.api.JavacTool; |
62 import com.sun.tools.javac.api.JavacTool; |
257 protected void analyze(JCStatement statement, Env<AttrContext> env) { |
270 protected void analyze(JCStatement statement, Env<AttrContext> env) { |
258 analyzeCalled = true; |
271 analyzeCalled = true; |
259 super.analyze(statement, env); |
272 super.analyze(statement, env); |
260 } |
273 } |
261 } |
274 } |
|
275 |
|
276 void testVariablesInSwitch() throws IOException { |
|
277 JavacTool c = JavacTool.create(); |
|
278 try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) { |
|
279 class MyFileObject extends SimpleJavaFileObject { |
|
280 MyFileObject() { |
|
281 super(URI.create("myfo:///Test.java"), SOURCE); |
|
282 } |
|
283 @Override |
|
284 public String getCharContent(boolean ignoreEncodingErrors) { |
|
285 return "class Test {" + |
|
286 " void test() {\n" + |
|
287 " E e = E.A;\n" + |
|
288 " Object o = E.A;\n" + |
|
289 " switch (e) {\n" + |
|
290 " case A:\n" + |
|
291 " return;\n" + |
|
292 " case B:\n" + |
|
293 " test();\n" + |
|
294 " E ee = null;\n" + |
|
295 " break;\n" + |
|
296 " }\n" + |
|
297 " }\n" + |
|
298 " enum E {A, B}\n" + |
|
299 "}"; |
|
300 } |
|
301 } |
|
302 Context ctx = new Context(); |
|
303 TestAnalyzer.preRegister(ctx); |
|
304 JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null, |
|
305 List.of(new MyFileObject()), ctx); |
|
306 CompilationUnitTree cut = t.parse().iterator().next(); |
|
307 t.analyze(); |
|
308 |
|
309 new TreePathScanner<Void, Void>() { |
|
310 @Override |
|
311 public Void visitMethodInvocation(MethodInvocationTree node, Void p) { |
|
312 Trees.instance(t).getScope(getCurrentPath()); |
|
313 return super.visitMethodInvocation(node, p); |
|
314 } |
|
315 }.scan(cut, null); |
|
316 } |
|
317 } |
|
318 |
|
319 void testMemberRefs() throws IOException { |
|
320 JavacTool c = JavacTool.create(); |
|
321 try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) { |
|
322 class MyFileObject extends SimpleJavaFileObject { |
|
323 MyFileObject() { |
|
324 super(URI.create("myfo:///Test.java"), SOURCE); |
|
325 } |
|
326 @Override |
|
327 public String getCharContent(boolean ignoreEncodingErrors) { |
|
328 return "class Test {" + |
|
329 " void test() {\n" + |
|
330 " Test t = this;\n" + |
|
331 " Runnable r1 = t::test;\n" + |
|
332 " Runnable r2 = true ? t::test : t::test;\n" + |
|
333 " c(t::test);\n" + |
|
334 " c(true ? t::test : t::test);\n" + |
|
335 " }\n" + |
|
336 " void c(Runnable r) {}\n" + |
|
337 "}"; |
|
338 } |
|
339 } |
|
340 Context ctx = new Context(); |
|
341 TestAnalyzer.preRegister(ctx); |
|
342 JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null, |
|
343 List.of(new MyFileObject()), ctx); |
|
344 CompilationUnitTree cut = t.parse().iterator().next(); |
|
345 t.analyze(); |
|
346 |
|
347 new TreePathScanner<Void, Void>() { |
|
348 @Override |
|
349 public Void visitConditionalExpression(ConditionalExpressionTree node, Void p) { |
|
350 Trees.instance(t).getScope(new TreePath(getCurrentPath(), node.getCondition())); |
|
351 return super.visitConditionalExpression(node, p); |
|
352 } |
|
353 |
|
354 @Override |
|
355 public Void visitBlock(BlockTree node, Void p) { |
|
356 Trees.instance(t).getScope(getCurrentPath()); |
|
357 return super.visitBlock(node, p); |
|
358 } |
|
359 }.scan(cut, null); |
|
360 } |
|
361 } |
|
362 |
|
363 void testAnnotations() throws IOException { |
|
364 JavacTool c = JavacTool.create(); |
|
365 try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) { |
|
366 class MyFileObject extends SimpleJavaFileObject { |
|
367 MyFileObject() { |
|
368 super(URI.create("myfo:///Test.java"), SOURCE); |
|
369 } |
|
370 @Override |
|
371 public String getCharContent(boolean ignoreEncodingErrors) { |
|
372 return "class Test {" + |
|
373 " void test() {\n" + |
|
374 " new Object() {\n" + |
|
375 " @A\n" + |
|
376 " public String t() { return null; }\n" + |
|
377 " };\n" + |
|
378 " }\n" + |
|
379 " @interface A {}\n" + |
|
380 "}"; |
|
381 } |
|
382 } |
|
383 Context ctx = new Context(); |
|
384 TestAnalyzer.preRegister(ctx); |
|
385 JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null, |
|
386 List.of(new MyFileObject()), ctx); |
|
387 CompilationUnitTree cut = t.parse().iterator().next(); |
|
388 t.analyze(); |
|
389 |
|
390 new TreePathScanner<Void, Void>() { |
|
391 @Override |
|
392 public Void visitIdentifier(IdentifierTree node, Void p) { |
|
393 if (node.getName().contentEquals("A")) { |
|
394 Trees.instance(t).getScope(getCurrentPath()); |
|
395 } |
|
396 return super.visitIdentifier(node, p); |
|
397 } |
|
398 |
|
399 @Override |
|
400 public Void visitMethod(MethodTree node, Void p) { |
|
401 super.visitMethod(node, p); |
|
402 if (node.getReturnType() != null) { |
|
403 Trees.instance(t).getScope(new TreePath(getCurrentPath(), node.getReturnType())); |
|
404 } |
|
405 return null; |
|
406 } |
|
407 }.scan(cut, null); |
|
408 } |
|
409 } |
|
410 |
|
411 void testAnnotationsLazy() throws IOException { |
|
412 JavacTool c = JavacTool.create(); |
|
413 try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) { |
|
414 class MyFileObject extends SimpleJavaFileObject { |
|
415 MyFileObject() { |
|
416 super(URI.create("myfo:///Test.java"), SOURCE); |
|
417 } |
|
418 @Override |
|
419 public String getCharContent(boolean ignoreEncodingErrors) { |
|
420 return "import java.lang.annotation.*;\n" + |
|
421 "\n" + |
|
422 "class ClassA {\n" + |
|
423 " Object o = ClassB.lcv;\n" + |
|
424 "}\n" + |
|
425 "\n" + |
|
426 "class ClassB {\n" + |
|
427 " static final String[] lcv = new @TA String[0];\n" + |
|
428 "}\n" + |
|
429 "\n" + |
|
430 "class ClassC {\n" + |
|
431 " static final Object o = (@TA Object) null;\n" + |
|
432 "}\n" + |
|
433 "\n" + |
|
434 "@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})\n" + |
|
435 "@interface TA {}\n"; |
|
436 } |
|
437 } |
|
438 Context ctx = new Context(); |
|
439 TestAnalyzer.preRegister(ctx); |
|
440 JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null, |
|
441 List.of(new MyFileObject()), ctx); |
|
442 t.addTaskListener(new TaskListener() { |
|
443 @Override |
|
444 public void finished(TaskEvent e) { |
|
445 if (e.getKind() == TaskEvent.Kind.ANALYZE) { |
|
446 new TreePathScanner<Void, Void>() { |
|
447 @Override |
|
448 public Void scan(Tree tree, Void p) { |
|
449 if (tree != null) { |
|
450 Trees.instance(t).getScope(new TreePath(getCurrentPath(), tree)); |
|
451 } |
|
452 return super.scan(tree, p); |
|
453 } |
|
454 }.scan(Trees.instance(t).getPath(e.getTypeElement()), null); |
|
455 } |
|
456 } |
|
457 }); |
|
458 |
|
459 t.call(); |
|
460 } |
|
461 } |
|
462 |
|
463 void testCircular() throws IOException { |
|
464 JavacTool c = JavacTool.create(); |
|
465 try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) { |
|
466 class MyFileObject extends SimpleJavaFileObject { |
|
467 MyFileObject() { |
|
468 super(URI.create("myfo:///Test.java"), SOURCE); |
|
469 } |
|
470 @Override |
|
471 public String getCharContent(boolean ignoreEncodingErrors) { |
|
472 return "class Test extends Test {" + |
|
473 " {\n" + |
|
474 " int i;\n" + |
|
475 " }\n" + |
|
476 "}"; |
|
477 } |
|
478 } |
|
479 Context ctx = new Context(); |
|
480 TestAnalyzer.preRegister(ctx); |
|
481 JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null, |
|
482 List.of(new MyFileObject()), ctx); |
|
483 CompilationUnitTree cut = t.parse().iterator().next(); |
|
484 t.analyze(); |
|
485 |
|
486 new TreePathScanner<Void, Void>() { |
|
487 @Override |
|
488 public Void visitBlock(BlockTree node, Void p) { |
|
489 Trees.instance(t).getScope(getCurrentPath()); |
|
490 return super.visitBlock(node, p); |
|
491 } |
|
492 }.scan(cut, null); |
|
493 } |
|
494 } |
|
495 |
262 } |
496 } |
263 |
|