mcimadamore@1415: /* mcimadamore@1415: * Copyright (c) 2011, 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: * Test SAM conversion of lambda expressions in combinations of different contexts, mcimadamore@1415: * lambda body types(statement/expression), explict/implicit target type etc, to verify mcimadamore@1415: * SAM conversion being conducted successfully as expected. 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.ToolProvider; mcimadamore@1415: mcimadamore@1415: public class SamConversionComboTest { mcimadamore@1415: mcimadamore@1415: enum FInterface { mcimadamore@1415: A("A", "interface A { Integer m(int i); }"), mcimadamore@1415: B("B", "interface B { int m(Integer i); }"), mcimadamore@1415: C("C", "interface C { int m(Integer i) throws Exception; }"); mcimadamore@1415: mcimadamore@1415: String interfaceType; mcimadamore@1415: String interfaceDef; mcimadamore@1415: mcimadamore@1415: FInterface(String interfaceType, String interfaceDef) { mcimadamore@1415: this.interfaceType = interfaceType; mcimadamore@1415: this.interfaceDef = interfaceDef; mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: String getParameterType() { mcimadamore@1415: switch(this) { mcimadamore@1415: case A: mcimadamore@1415: return "int"; mcimadamore@1415: case B: mcimadamore@1415: case C: mcimadamore@1415: return "Integer"; mcimadamore@1415: default: mcimadamore@1415: return null; mcimadamore@1415: } mcimadamore@1415: } mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: enum Context { mcimadamore@1415: ASSIGNMENT("#FType f = #LBody;"), mcimadamore@1415: METHOD_CALL("void method1(#FType f) { }\n" + mcimadamore@1415: " void method2() {\n" + mcimadamore@1415: " method1(#LBody);\n" + mcimadamore@1415: " }"), mcimadamore@1415: CONSTRUCTOR("X x = new X(#LBody);"), mcimadamore@1415: RETURN_OF_METHOD("#FType method1() {\n" + mcimadamore@1415: " return #LBody;\n" + mcimadamore@1415: "}"), mcimadamore@1415: ARRAY_INITIALIZER("Object[] oarray = {\"a\", 1, (#FType)#LBody};"), mcimadamore@1415: LAMBDA_BODY("#FType f = n -> ((#FType)#LBody).m(n);"), mcimadamore@1415: CAST("void test() throws Exception { int n = ((#FType)#LBody).m(1); }"), mcimadamore@1415: CONDITIONAL_EXPRESSION("#FType f = 2 > 1 ? #LBody : null;"); mcimadamore@1415: mcimadamore@1415: String context; mcimadamore@1415: mcimadamore@1415: Context(String context) { mcimadamore@1415: this.context = context; mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: String getContext(FInterface f, LambdaKind lk, LambdaBody lb, ReturnValue rv) { mcimadamore@1415: return context.replace("#FType", f.interfaceType).replace("#LBody", lb.getLambdaBody(f, lk, rv)); mcimadamore@1415: } mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: enum LambdaKind { mcimadamore@1415: EXPRESSION("#VAL"), mcimadamore@1415: STATEMENT("{return #VAL;}"), mcimadamore@1415: EXCEPTION_STMT("{throw new Exception();}"); mcimadamore@1415: mcimadamore@1415: String stmt; mcimadamore@1415: mcimadamore@1415: LambdaKind(String stmt) { mcimadamore@1415: this.stmt = stmt; mcimadamore@1415: } mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: enum ReturnValue { mcimadamore@1415: INT("i + 1"), mcimadamore@1415: INTEGER("new Integer(i+1)"), mcimadamore@1415: INT2("i.intValue() + 1"), mcimadamore@1415: STRING("i + \"\""), mcimadamore@1415: DOUBLE("i * 1.0"); mcimadamore@1415: mcimadamore@1415: String rValue; mcimadamore@1415: mcimadamore@1415: ReturnValue(String rValue) { mcimadamore@1415: this.rValue = rValue; mcimadamore@1415: } mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: enum LambdaBody { mcimadamore@1415: IMPLICIT("i -> #RET"),//type inferred mcimadamore@1415: EXPLICIT("(#Type i) -> #RET");//explicit type mcimadamore@1415: mcimadamore@1415: String bodyStr; mcimadamore@1415: mcimadamore@1415: LambdaBody(String bodyStr) { mcimadamore@1415: this.bodyStr = bodyStr; mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: String getLambdaBody(FInterface fi, LambdaKind lk, ReturnValue rv) { mcimadamore@1415: return bodyStr.replace("#Type", fi.getParameterType()).replace("#RET", lk.stmt.replace("#VAL", rv.rValue)); mcimadamore@1415: } mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: boolean checkSamConversion() { mcimadamore@1415: if(lambdaKind != LambdaKind.EXCEPTION_STMT && (returnValue == ReturnValue.DOUBLE || returnValue == ReturnValue.STRING)) //return type mismatch mcimadamore@1415: return false; mcimadamore@1415: if(context != Context.CONSTRUCTOR) {//context other than construcotr argument mcimadamore@1415: if(fInterface != FInterface.C && lambdaKind == LambdaKind.EXCEPTION_STMT) mcimadamore@1415: return false; mcimadamore@1415: if(fInterface == FInterface.A && returnValue == ReturnValue.INT2) mcimadamore@1415: return false; mcimadamore@1415: } mcimadamore@1415: else { //constructor argument context mcimadamore@1415: //match X(A a) or X(B b) or X(C c) mcimadamore@1415: if (lambdaKind == LambdaKind.EXCEPTION_STMT) { mcimadamore@1415: return false; //ambiguous target type mcimadamore@1415: } mcimadamore@1415: else if(lambdaBody == LambdaBody.IMPLICIT) { mcimadamore@1415: if(returnValue != ReturnValue.INTEGER) //ambiguous target type mcimadamore@1415: return false; mcimadamore@1415: } mcimadamore@1415: else { //explicit parameter type mcimadamore@1415: if(fInterface.getParameterType().equals("Integer")) //ambiguous target type mcimadamore@1415: //e.g. X x = new X((Integer i) -> i + 1); mcimadamore@1415: return false; mcimadamore@1415: if(returnValue == ReturnValue.INT2) mcimadamore@1415: //e.g. X x = new X(int i -> i.intValue() + 1); mcimadamore@1415: return false; mcimadamore@1415: } mcimadamore@1415: } mcimadamore@1415: return true; mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: SourceFile samSourceFile = new SourceFile("FInterface.java", "#C") { mcimadamore@1415: public String toString() { mcimadamore@1415: String interfaces = ""; mcimadamore@1415: for(FInterface fi : FInterface.values()) mcimadamore@1415: interfaces += fi.interfaceDef + "\n"; mcimadamore@1415: return template.replace("#C", interfaces); mcimadamore@1415: } mcimadamore@1415: }; mcimadamore@1415: mcimadamore@1415: String clientTemplate = "class Client {\n" + mcimadamore@1415: " #Context\n" + mcimadamore@1415: "}\n\n" + mcimadamore@1415: mcimadamore@1415: "class X {\n" + mcimadamore@1415: " int value = 0;\n\n" + mcimadamore@1415: mcimadamore@1415: " X(A a) {\n" + mcimadamore@1415: " value = a.m(6);\n" + mcimadamore@1415: " }\n\n" + mcimadamore@1415: mcimadamore@1415: " X(B b) {\n" + mcimadamore@1415: " value = b.m(7);\n" + mcimadamore@1415: " }\n\n" + mcimadamore@1415: mcimadamore@1415: " X(C c) {\n" + mcimadamore@1415: " try {\n" + mcimadamore@1415: " value = c.m(8);\n" + mcimadamore@1415: " } catch (Exception e){}\n" + mcimadamore@1415: " }\n" + mcimadamore@1415: "}"; mcimadamore@1415: SourceFile clientSourceFile = new SourceFile("Client.java", clientTemplate) { mcimadamore@1415: public String toString() { mcimadamore@1415: return template.replace("#Context", context.getContext(fInterface, lambdaKind, lambdaBody, returnValue)); mcimadamore@1415: } mcimadamore@1415: }; mcimadamore@1415: mcimadamore@1415: void test() throws Exception { mcimadamore@1415: System.out.println("\n===================================="); mcimadamore@1415: System.out.println(fInterface + ", " + context + ", " + lambdaKind + ", " + lambdaBody + ", " + returnValue); mcimadamore@1415: System.out.println(samSourceFile + "\n"); mcimadamore@1415: String clientFileStr = clientSourceFile.toString(); mcimadamore@1415: System.out.println(clientFileStr.substring(0, clientFileStr.indexOf("\n\n"))); mcimadamore@1415: mcimadamore@1415: final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); mcimadamore@1415: DiagnosticChecker dc = new DiagnosticChecker(); mcimadamore@1415: JavacTask ct = (JavacTask)tool.getTask(null, null, dc, null, null, Arrays.asList(samSourceFile, clientSourceFile)); mcimadamore@1415: ct.analyze(); mcimadamore@1415: if (dc.errorFound == checkSamConversion()) { mcimadamore@1415: throw new AssertionError(samSourceFile + "\n\n" + clientSourceFile); mcimadamore@1415: } mcimadamore@1415: count++; mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: abstract class SourceFile extends SimpleJavaFileObject { mcimadamore@1415: mcimadamore@1415: protected String template; mcimadamore@1415: mcimadamore@1415: public SourceFile(String filename, String template) { mcimadamore@1415: super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE); mcimadamore@1415: this.template = template; mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: @Override mcimadamore@1415: public CharSequence getCharContent(boolean ignoreEncodingErrors) { mcimadamore@1415: return toString(); mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: public abstract String toString(); mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: static class DiagnosticChecker implements javax.tools.DiagnosticListener { mcimadamore@1415: mcimadamore@1415: boolean errorFound = false; 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: mcimadamore@1415: FInterface fInterface; mcimadamore@1415: Context context; mcimadamore@1415: LambdaBody lambdaBody; mcimadamore@1415: LambdaKind lambdaKind; mcimadamore@1415: ReturnValue returnValue; mcimadamore@1415: static int count = 0; mcimadamore@1415: mcimadamore@1415: SamConversionComboTest(FInterface f, Context c, LambdaBody lb, LambdaKind lk, ReturnValue rv) { mcimadamore@1415: fInterface = f; mcimadamore@1415: context = c; mcimadamore@1415: lambdaKind = lk; mcimadamore@1415: lambdaBody = lb; mcimadamore@1415: returnValue = rv; mcimadamore@1415: } mcimadamore@1415: mcimadamore@1415: public static void main(String[] args) throws Exception { mcimadamore@1415: for(Context ct : Context.values()) { mcimadamore@1415: for (FInterface fi : FInterface.values()) { mcimadamore@1415: for (LambdaKind lk: LambdaKind.values()) { mcimadamore@1415: for (LambdaBody lb : LambdaBody.values()) { mcimadamore@1415: for(ReturnValue rv : ReturnValue.values()) { mcimadamore@1415: new SamConversionComboTest(fi, ct, lb, lk, rv).test(); mcimadamore@1415: } mcimadamore@1415: } mcimadamore@1415: } mcimadamore@1415: } mcimadamore@1415: } mcimadamore@1415: System.out.println("total tests: " + count); mcimadamore@1415: } mcimadamore@1415: }