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