diff -r 000000000000 -r 959103a6100f test/tools/javac/lambda/TestSelfRef.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/lambda/TestSelfRef.java Wed Apr 27 01:34:52 2016 +0800 @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8003280 + * @summary Add lambda tests + * Check that self/forward references from lambda expressions behave + * consistently w.r.t. local inner classes + */ + +import java.net.URI; +import java.util.Arrays; +import javax.tools.Diagnostic; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; +import com.sun.source.util.JavacTask; + +public class TestSelfRef { + + static int checkCount = 0; + + enum RefKind { + SELF_LAMBDA("SAM s = x->{ System.out.println(s); };", true, false), + FORWARD_LAMBDA("SAM s = x->{ System.out.println(f); };\nObject f = null;", false, true), + SELF_ANON("Object s = new Object() { void test() { System.out.println(s); } };", true, false), + FORWARD_ANON("Object s = new Object() { void test() { System.out.println(f); } }; Object f = null;", false, true); + + String refStr; + boolean selfRef; + boolean forwardRef; + + private RefKind(String refStr, boolean selfRef, boolean forwardRef) { + this.refStr = refStr; + this.selfRef = selfRef; + this.forwardRef = forwardRef; + } + } + + enum EnclosingKind { + TOPLEVEL("class C { #S }"), + MEMBER_INNER("class Outer { class C { #S } }"), + NESTED_INNER("class Outer { static class C { #S } }"); + + String enclStr; + + private EnclosingKind(String enclStr) { + this.enclStr = enclStr; + } + } + + enum InnerKind { + NONE("#R"), + LOCAL_NONE("class Local { #R }"), + LOCAL_MTH("class Local { void test() { #R } }"), + ANON_NONE("new Object() { #R };"), + ANON_MTH("new Object() { void test() { #R } };"); + + String innerStr; + + private InnerKind(String innerStr) { + this.innerStr = innerStr; + } + + boolean inMethodContext(SiteKind sk) { + switch (this) { + case LOCAL_MTH: + case ANON_MTH: return true; + case NONE: return sk != SiteKind.NONE; + default: + return false; + } + } + } + + enum SiteKind { + NONE("#I"), + STATIC_INIT("static { #I }"), + INSTANCE_INIT("{ #I }"), + CONSTRUCTOR("C() { #I }"), + METHOD("void test() { #I }"); + + String siteStr; + + private SiteKind(String siteStr) { + this.siteStr = siteStr; + } + } + + public static void main(String... args) throws Exception { + + //create default shared JavaCompiler - reused across multiple compilations + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); + + for (EnclosingKind ek : EnclosingKind.values()) { + for (SiteKind sk : SiteKind.values()) { + if (sk == SiteKind.STATIC_INIT && ek == EnclosingKind.MEMBER_INNER) + continue; + for (InnerKind ik : InnerKind.values()) { + if (ik != InnerKind.NONE && sk == SiteKind.NONE) + break; + for (RefKind rk : RefKind.values()) { + new TestSelfRef(ek, sk, ik, rk).run(comp, fm); + } + } + } + } + System.out.println("Total check executed: " + checkCount); + } + + EnclosingKind ek; + SiteKind sk; + InnerKind ik; + RefKind rk; + JavaSource source; + DiagnosticChecker diagChecker; + + TestSelfRef(EnclosingKind ek, SiteKind sk, InnerKind ik, RefKind rk) { + this.ek = ek; + this.sk = sk; + this.ik = ik; + this.rk = rk; + this.source = new JavaSource(); + this.diagChecker = new DiagnosticChecker(); + } + + class JavaSource extends SimpleJavaFileObject { + + String bodyTemplate = "interface SAM { void test(Object o); }\n#B"; + String source; + + public JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + source = bodyTemplate.replace("#B", + ek.enclStr.replace("#S", sk.siteStr.replace("#I", ik.innerStr.replace("#R", rk.refStr)))); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } + + void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception { + JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker, + null, null, Arrays.asList(source)); + try { + ct.analyze(); + } catch (Throwable ex) { + throw new AssertionError("Error thron when compiling the following code:\n" + source.getCharContent(true)); + } + check(); + } + + boolean isErrorExpected() { + //illegal forward ref + boolean result = ik.inMethodContext(sk) && (rk.selfRef || rk.forwardRef); + result |= (rk == RefKind.SELF_LAMBDA || rk == RefKind.FORWARD_LAMBDA); + return result; + } + + void check() { + checkCount++; + boolean errorExpected = isErrorExpected(); + if (diagChecker.errorFound != errorExpected) { + throw new Error("invalid diagnostics for source:\n" + + source.getCharContent(true) + + "\nFound error: " + diagChecker.errorFound + + "\nExpected error: " + errorExpected); + } + } + + static class DiagnosticChecker implements javax.tools.DiagnosticListener { + + boolean errorFound; + + public void report(Diagnostic diagnostic) { + if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { + errorFound = true; + } + } + } +}