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