aoqi@0: /* aoqi@0: * Copyright (c) 2012, 2014, 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 8004102 8006694 aoqi@0: * @summary Add lambda tests aoqi@0: * perform several automated checks in lambda conversion, esp. around accessibility aoqi@0: * temporarily workaround combo tests are causing time out in several platforms aoqi@0: * @author Maurizio Cimadamore aoqi@0: * @library ../lib aoqi@0: * @build JavacTestingAbstractThreadedTest aoqi@0: * @run main/timeout=600/othervm FunctionalInterfaceConversionTest aoqi@0: */ aoqi@0: aoqi@0: // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) aoqi@0: // see JDK-8006746 aoqi@0: aoqi@0: import java.io.IOException; 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.ToolProvider; aoqi@0: import com.sun.source.util.JavacTask; aoqi@0: aoqi@0: public class FunctionalInterfaceConversionTest aoqi@0: extends JavacTestingAbstractThreadedTest aoqi@0: implements Runnable { aoqi@0: aoqi@0: enum PackageKind { aoqi@0: NO_PKG(""), aoqi@0: PKG_A("a"); aoqi@0: aoqi@0: String pkg; aoqi@0: aoqi@0: PackageKind(String pkg) { aoqi@0: this.pkg = pkg; aoqi@0: } aoqi@0: aoqi@0: String getPkgDecl() { aoqi@0: return this == NO_PKG ? aoqi@0: "" : aoqi@0: "package " + pkg + ";"; aoqi@0: } aoqi@0: aoqi@0: String getImportStat() { aoqi@0: return this == NO_PKG ? aoqi@0: "" : aoqi@0: "import " + pkg + ".*;"; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: enum SamKind { aoqi@0: CLASS("public class Sam { }"), aoqi@0: ABSTACT_CLASS("public abstract class Sam { }"), aoqi@0: ANNOTATION("public @interface Sam { }"), aoqi@0: ENUM("public enum Sam { }"), aoqi@0: INTERFACE("public interface Sam { \n #METH; \n }"); aoqi@0: aoqi@0: String sam_str; aoqi@0: aoqi@0: SamKind(String sam_str) { aoqi@0: this.sam_str = sam_str; aoqi@0: } aoqi@0: aoqi@0: String getSam(String methStr) { aoqi@0: return sam_str.replaceAll("#METH", methStr); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: enum ModifierKind { aoqi@0: PUBLIC("public"), aoqi@0: PACKAGE(""); aoqi@0: aoqi@0: String modifier_str; aoqi@0: aoqi@0: ModifierKind(String modifier_str) { aoqi@0: this.modifier_str = modifier_str; aoqi@0: } aoqi@0: aoqi@0: boolean stricterThan(ModifierKind that) { aoqi@0: return this.ordinal() > that.ordinal(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: enum TypeKind { aoqi@0: EXCEPTION("Exception"), aoqi@0: PKG_CLASS("PackageClass"); aoqi@0: aoqi@0: String typeStr; aoqi@0: aoqi@0: private TypeKind(String typeStr) { aoqi@0: this.typeStr = typeStr; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: enum ExprKind { aoqi@0: LAMBDA("x -> null"), aoqi@0: MREF("this::m"); aoqi@0: aoqi@0: String exprStr; aoqi@0: aoqi@0: private ExprKind(String exprStr) { aoqi@0: this.exprStr = exprStr; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: enum MethodKind { aoqi@0: NONE(""), aoqi@0: NON_GENERIC("public abstract #R m(#ARG s) throws #T;"), aoqi@0: GENERIC("public abstract #R m(#ARG s) throws #T;"); aoqi@0: aoqi@0: String methodTemplate; aoqi@0: aoqi@0: private MethodKind(String methodTemplate) { aoqi@0: this.methodTemplate = methodTemplate; aoqi@0: } aoqi@0: aoqi@0: String getMethod(TypeKind retType, TypeKind argType, TypeKind thrownType) { aoqi@0: return methodTemplate.replaceAll("#R", retType.typeStr). aoqi@0: replaceAll("#ARG", argType.typeStr). aoqi@0: replaceAll("#T", thrownType.typeStr); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public static void main(String[] args) throws Exception { aoqi@0: for (PackageKind samPkg : PackageKind.values()) { aoqi@0: for (ModifierKind modKind : ModifierKind.values()) { aoqi@0: for (SamKind samKind : SamKind.values()) { aoqi@0: for (MethodKind samMeth : MethodKind.values()) { aoqi@0: for (MethodKind clientMeth : MethodKind.values()) { aoqi@0: for (TypeKind retType : TypeKind.values()) { aoqi@0: for (TypeKind argType : TypeKind.values()) { aoqi@0: for (TypeKind thrownType : TypeKind.values()) { aoqi@0: for (ExprKind exprKind : ExprKind.values()) { aoqi@0: pool.execute( aoqi@0: new FunctionalInterfaceConversionTest( aoqi@0: samPkg, modKind, samKind, aoqi@0: samMeth, clientMeth, retType, aoqi@0: argType, thrownType, exprKind)); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: checkAfterExec(false); aoqi@0: } aoqi@0: aoqi@0: PackageKind samPkg; aoqi@0: ModifierKind modKind; aoqi@0: SamKind samKind; aoqi@0: MethodKind samMeth; aoqi@0: MethodKind clientMeth; aoqi@0: TypeKind retType; aoqi@0: TypeKind argType; aoqi@0: TypeKind thrownType; aoqi@0: ExprKind exprKind; aoqi@0: DiagnosticChecker dc; aoqi@0: aoqi@0: SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") { aoqi@0: @Override aoqi@0: public String toString() { aoqi@0: return template.replaceAll("#P", samPkg.getPkgDecl()). aoqi@0: replaceAll("#C", samKind.getSam( aoqi@0: samMeth.getMethod(retType, argType, thrownType))); aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: SourceFile pkgClassSourceFile = aoqi@0: new SourceFile("PackageClass.java", aoqi@0: "#P\n #M class PackageClass extends Exception { }") { aoqi@0: @Override aoqi@0: public String toString() { aoqi@0: return template.replaceAll("#P", samPkg.getPkgDecl()). aoqi@0: replaceAll("#M", modKind.modifier_str); aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: SourceFile clientSourceFile = aoqi@0: new SourceFile("Client.java", aoqi@0: "#I\n abstract class Client { \n" + aoqi@0: " Sam s = #E;\n" + aoqi@0: " #M \n }") { aoqi@0: @Override aoqi@0: public String toString() { aoqi@0: return template.replaceAll("#I", samPkg.getImportStat()) aoqi@0: .replaceAll("#E", exprKind.exprStr) aoqi@0: .replaceAll("#M", clientMeth.getMethod(retType, argType, thrownType)); aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: FunctionalInterfaceConversionTest(PackageKind samPkg, ModifierKind modKind, aoqi@0: SamKind samKind, MethodKind samMeth, MethodKind clientMeth, aoqi@0: TypeKind retType, TypeKind argType, TypeKind thrownType, aoqi@0: ExprKind exprKind) { aoqi@0: this.samPkg = samPkg; aoqi@0: this.modKind = modKind; aoqi@0: this.samKind = samKind; aoqi@0: this.samMeth = samMeth; aoqi@0: this.clientMeth = clientMeth; aoqi@0: this.retType = retType; aoqi@0: this.argType = argType; aoqi@0: this.thrownType = thrownType; aoqi@0: this.exprKind = exprKind; aoqi@0: this.dc = new DiagnosticChecker(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void run() { aoqi@0: final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); aoqi@0: aoqi@0: JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), dc, null, null, aoqi@0: Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile)); aoqi@0: try { aoqi@0: ct.analyze(); aoqi@0: } catch (IOException ex) { aoqi@0: throw new AssertionError("Test failing with cause", ex.getCause()); aoqi@0: } aoqi@0: if (dc.errorFound == checkSamConversion()) { aoqi@0: throw new AssertionError(samSourceFile + "\n\n" + aoqi@0: pkgClassSourceFile + "\n\n" + clientSourceFile); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: boolean checkSamConversion() { aoqi@0: if (samKind != SamKind.INTERFACE) { aoqi@0: //sam type must be an interface aoqi@0: return false; aoqi@0: } else if (samMeth == MethodKind.NONE) { aoqi@0: //interface must have at least a method aoqi@0: return false; aoqi@0: } else if (exprKind == ExprKind.LAMBDA && aoqi@0: samMeth != MethodKind.NON_GENERIC) { aoqi@0: //target method for lambda must be non-generic aoqi@0: return false; aoqi@0: } else if (exprKind == ExprKind.MREF && aoqi@0: clientMeth == MethodKind.NONE) { aoqi@0: return false; aoqi@0: } else if (samPkg != PackageKind.NO_PKG && aoqi@0: modKind != ModifierKind.PUBLIC && aoqi@0: (retType == TypeKind.PKG_CLASS || aoqi@0: argType == TypeKind.PKG_CLASS || aoqi@0: thrownType == TypeKind.PKG_CLASS)) { aoqi@0: //target must not contain inaccessible types aoqi@0: return false; aoqi@0: } else { aoqi@0: return true; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: abstract class SourceFile extends SimpleJavaFileObject { aoqi@0: aoqi@0: protected String template; aoqi@0: aoqi@0: public SourceFile(String filename, String template) { aoqi@0: super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE); aoqi@0: this.template = template; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public CharSequence getCharContent(boolean ignoreEncodingErrors) { aoqi@0: return toString(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public abstract String toString(); aoqi@0: } aoqi@0: aoqi@0: static class DiagnosticChecker aoqi@0: implements javax.tools.DiagnosticListener { aoqi@0: aoqi@0: boolean errorFound = false; aoqi@0: aoqi@0: @Override 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: }