1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8205418 27 * @summary Test the outcomes from Trees.getScope 28 * @modules jdk.compiler 29 */ 30 31 import java.io.IOException; 32 import java.net.URI; 33 import java.util.ArrayList; 34 import java.util.List; 35 36 import javax.lang.model.element.Element; 37 import javax.tools.JavaCompiler; 38 import javax.tools.SimpleJavaFileObject; 39 import javax.tools.StandardJavaFileManager; 40 import javax.tools.ToolProvider; 41 42 import com.sun.source.tree.CompilationUnitTree; 43 import com.sun.source.tree.LambdaExpressionTree; 44 import com.sun.source.tree.Scope; 45 import com.sun.source.util.JavacTask; 46 import com.sun.source.util.TreePath; 47 import com.sun.source.util.TreePathScanner; 48 import com.sun.source.util.Trees; 49 50 import static javax.tools.JavaFileObject.Kind.SOURCE; 51 52 public class TestGetScopeResult { 53 public static void main(String... args) throws IOException { 54 new TestGetScopeResult().run(); 55 } 56 57 public void run() throws IOException { 58 String[] simpleLambda = { 59 "s:java.lang.String", 60 "i:Test.I", 61 "super:java.lang.Object", 62 "this:Test" 63 }; 64 doTest("class Test { void test() { I i = s -> { }; } interface I { public void test(String s); } }", 65 simpleLambda); 66 doTest("class Test { void test() { I i = s -> { }; } interface I { public int test(String s); } }", 67 simpleLambda); 68 doTest("class Test { void test() { I i = s -> { }; } interface I { public String test(String s); } }", 69 simpleLambda); 70 doTest("class Test { void test() { I i; inv(s -> { }); } void inv(I i) { } interface I { public void test(String s); } }", 71 simpleLambda); 72 doTest("class Test { void test() { I i; inv(s -> { }); } void inv(I i) { } interface I { public int test(String s); } }", 73 simpleLambda); 74 doTest("class Test { void test() { I i; inv(s -> { }); } void inv(I i) { } interface I { public String test(String s); } }", 75 simpleLambda); 76 String[] dualLambda = { 77 "s:java.lang.String", 78 "i:Test.I1", 79 "super:java.lang.Object", 80 "this:Test", 81 "s:java.lang.CharSequence", 82 "i:Test.I1", 83 "super:java.lang.Object", 84 "this:Test" 85 }; 86 doTest("class Test { void test() { I1 i; inv(s -> { }, s -> { }); } void inv(I1 i, I2 i) { } interface I1 { public String test(String s); } interface I2 { public void test(CharSequence s); } }", 87 dualLambda); 88 doTest("class Test { void test() { I1 i; inv(s -> { }, s -> { }); } void inv(I1 i, I2 i) { } interface I1 { public String test(String s); } interface I2 { public int test(CharSequence s); } }", 89 dualLambda); 90 String[] brokenType = { 91 "s:<any>", 92 "u:Undefined", 93 "super:java.lang.Object", 94 "this:Test" 95 }; 96 doTest("class Test { void test() { Undefined u = s -> { }; } }", 97 brokenType); 98 String[] multipleCandidates1 = { 99 "s:<any>", 100 "super:java.lang.Object", 101 "this:Test" 102 }; 103 doTest("class Test { void test() { cand1(s -> { }); } void cand1(I1 i) { } void cand1(I2 i) { } interface I1 { public String test(String s); } interface I2 { public int test(CharSequence s); } }", 104 multipleCandidates1); 105 String[] multipleCandidates2 = { 106 "s:java.lang.String", 107 "super:java.lang.Object", 108 "this:Test" 109 }; 110 doTest("class Test { void test() { cand1(s -> { }); } void cand1(I1 i) { } void cand1(I2 i, int i) { } interface I1 { public String test(String s); } interface I2 { public int test(CharSequence s); } }", 111 multipleCandidates2); 112 } 113 114 public void doTest(String code, String... expected) throws IOException { 115 JavaCompiler c = ToolProvider.getSystemJavaCompiler(); 116 try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) { 117 class MyFileObject extends SimpleJavaFileObject { 118 MyFileObject() { 119 super(URI.create("myfo:///Test.java"), SOURCE); 120 } 121 @Override 122 public String getCharContent(boolean ignoreEncodingErrors) { 123 return code; 124 } 125 } 126 JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null, List.of(new MyFileObject())); 127 CompilationUnitTree cut = t.parse().iterator().next(); 128 t.analyze(); 129 130 List<String> actual = new ArrayList<>(); 131 132 new TreePathScanner<Void, Void>() { 133 @Override 134 public Void visitLambdaExpression(LambdaExpressionTree node, Void p) { 135 Scope scope = Trees.instance(t).getScope(new TreePath(getCurrentPath(), node.getBody())); 136 while (scope.getEnclosingClass() != null) { 137 for (Element el : scope.getLocalElements()) { 138 actual.add(el.getSimpleName() + ":" +el.asType().toString()); 139 } 140 scope = scope.getEnclosingScope(); 141 } 142 return super.visitLambdaExpression(node, p); 143 } 144 }.scan(cut, null); 145 146 List<String> expectedList = List.of(expected); 147 148 if (!expectedList.equals(actual)) { 149 throw new IllegalStateException("Unexpected scope content: " + actual); 150 } 151 } 152 } 153 154 } 155