test/tools/javac/lambda/FunctionalInterfaceConversionTest.java

Fri, 30 Nov 2012 15:14:25 +0000

author
mcimadamore
date
Fri, 30 Nov 2012 15:14:25 +0000
changeset 1434
34d1ebaf4645
child 1482
954541f13717
permissions
-rw-r--r--

8004102: Add support for generic functional descriptors
Summary: Method references are allowed to have a generic functional interface descriptor target
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  */
    24 /**
    25  * @test
    26  * @bug 8003280 8004102
    27  * @summary Add lambda tests
    28  *  perform several automated checks in lambda conversion, esp. around accessibility
    29  * @author  Maurizio Cimadamore
    30  * @run main FunctionalInterfaceConversionTest
    31  */
    33 import com.sun.source.util.JavacTask;
    34 import java.net.URI;
    35 import java.util.Arrays;
    36 import javax.tools.Diagnostic;
    37 import javax.tools.JavaCompiler;
    38 import javax.tools.JavaFileObject;
    39 import javax.tools.SimpleJavaFileObject;
    40 import javax.tools.StandardJavaFileManager;
    41 import javax.tools.ToolProvider;
    43 public class FunctionalInterfaceConversionTest {
    45     enum PackageKind {
    46         NO_PKG(""),
    47         PKG_A("a");
    49         String pkg;
    51         PackageKind(String pkg) {
    52             this.pkg = pkg;
    53         }
    55         String getPkgDecl() {
    56             return this == NO_PKG ?
    57                 "" :
    58                 "package " + pkg + ";";
    59         }
    61         String getImportStat() {
    62             return this == NO_PKG ?
    63                 "" :
    64                 "import " + pkg + ".*;";
    65         }
    66     }
    68     enum SamKind {
    69         CLASS("public class Sam {  }"),
    70         ABSTACT_CLASS("public abstract class Sam {  }"),
    71         ANNOTATION("public @interface Sam {  }"),
    72         ENUM("public enum Sam { }"),
    73         INTERFACE("public interface Sam { \n #METH; \n }");
    75         String sam_str;
    77         SamKind(String sam_str) {
    78             this.sam_str = sam_str;
    79         }
    81         String getSam(String methStr) {
    82             return sam_str.replaceAll("#METH", methStr);
    83         }
    84     }
    86     enum ModifierKind {
    87         PUBLIC("public"),
    88         PACKAGE("");
    90         String modifier_str;
    92         ModifierKind(String modifier_str) {
    93             this.modifier_str = modifier_str;
    94         }
    96         boolean stricterThan(ModifierKind that) {
    97             return this.ordinal() > that.ordinal();
    98         }
    99     }
   101     enum TypeKind {
   102         EXCEPTION("Exception"),
   103         PKG_CLASS("PackageClass");
   105         String typeStr;
   107         private TypeKind(String typeStr) {
   108             this.typeStr = typeStr;
   109         }
   110     }
   112     enum ExprKind {
   113         LAMBDA("x -> null"),
   114         MREF("this::m");
   116         String exprStr;
   118         private ExprKind(String exprStr) {
   119             this.exprStr = exprStr;
   120         }
   121     }
   123     enum MethodKind {
   124         NONE(""),
   125         NON_GENERIC("public abstract #R m(#ARG s) throws #T;"),
   126         GENERIC("public abstract <X> #R m(#ARG s) throws #T;");
   128         String methodTemplate;
   130         private MethodKind(String methodTemplate) {
   131             this.methodTemplate = methodTemplate;
   132         }
   134         String getMethod(TypeKind retType, TypeKind argType, TypeKind thrownType) {
   135             return methodTemplate.replaceAll("#R", retType.typeStr).
   136                     replaceAll("#ARG", argType.typeStr).
   137                     replaceAll("#T", thrownType.typeStr);
   138         }
   139     }
   141     public static void main(String[] args) throws Exception {
   142         final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
   143         StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
   144         for (PackageKind samPkg : PackageKind.values()) {
   145             for (ModifierKind modKind : ModifierKind.values()) {
   146                 for (SamKind samKind : SamKind.values()) {
   147                     for (MethodKind samMeth : MethodKind.values()) {
   148                         for (MethodKind clientMeth : MethodKind.values()) {
   149                             for (TypeKind retType : TypeKind.values()) {
   150                                 for (TypeKind argType : TypeKind.values()) {
   151                                     for (TypeKind thrownType : TypeKind.values()) {
   152                                         for (ExprKind exprKind : ExprKind.values()) {
   153                                             new FunctionalInterfaceConversionTest(samPkg, modKind, samKind,
   154                                                     samMeth, clientMeth, retType, argType, thrownType, exprKind).test(comp, fm);
   155                                         }
   156                                     }
   157                                 }
   158                             }
   159                         }
   160                     }
   161                 }
   162             }
   163         }
   164     }
   166     PackageKind samPkg;
   167     ModifierKind modKind;
   168     SamKind samKind;
   169     MethodKind samMeth;
   170     MethodKind clientMeth;
   171     TypeKind retType;
   172     TypeKind argType;
   173     TypeKind thrownType;
   174     ExprKind exprKind;
   175     DiagnosticChecker dc;
   177     SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") {
   178         public String toString() {
   179             return template.replaceAll("#P", samPkg.getPkgDecl()).
   180                     replaceAll("#C", samKind.getSam(samMeth.getMethod(retType, argType, thrownType)));
   181         }
   182     };
   184     SourceFile pkgClassSourceFile = new SourceFile("PackageClass.java",
   185                                                    "#P\n #M class PackageClass extends Exception { }") {
   186         public String toString() {
   187             return template.replaceAll("#P", samPkg.getPkgDecl()).
   188                     replaceAll("#M", modKind.modifier_str);
   189         }
   190     };
   192     SourceFile clientSourceFile = new SourceFile("Client.java",
   193                                                  "#I\n abstract class Client { \n" +
   194                                                  "  Sam s = #E;\n" +
   195                                                  "  #M \n }") {
   196         public String toString() {
   197             return template.replaceAll("#I", samPkg.getImportStat())
   198                     .replaceAll("#E", exprKind.exprStr)
   199                     .replaceAll("#M", clientMeth.getMethod(retType, argType, thrownType));
   200         }
   201     };
   203     FunctionalInterfaceConversionTest(PackageKind samPkg, ModifierKind modKind, SamKind samKind,
   204             MethodKind samMeth, MethodKind clientMeth, TypeKind retType, TypeKind argType,
   205             TypeKind thrownType, ExprKind exprKind) {
   206         this.samPkg = samPkg;
   207         this.modKind = modKind;
   208         this.samKind = samKind;
   209         this.samMeth = samMeth;
   210         this.clientMeth = clientMeth;
   211         this.retType = retType;
   212         this.argType = argType;
   213         this.thrownType = thrownType;
   214         this.exprKind = exprKind;
   215         this.dc = new DiagnosticChecker();
   216     }
   218     void test(JavaCompiler comp, StandardJavaFileManager fm) throws Exception {
   219         JavacTask ct = (JavacTask)comp.getTask(null, fm, dc,
   220                 null, null, Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile));
   221         ct.analyze();
   222         if (dc.errorFound == checkSamConversion()) {
   223             throw new AssertionError(samSourceFile + "\n\n" + pkgClassSourceFile + "\n\n" + clientSourceFile);
   224         }
   225     }
   227     boolean checkSamConversion() {
   228         if (samKind != SamKind.INTERFACE) {
   229             //sam type must be an interface
   230             return false;
   231         } else if (samMeth == MethodKind.NONE) {
   232             //interface must have at least a method
   233             return false;
   234         } else if (exprKind == ExprKind.LAMBDA &&
   235                 samMeth != MethodKind.NON_GENERIC) {
   236             //target method for lambda must be non-generic
   237             return false;
   238         } else if (exprKind == ExprKind.MREF &&
   239                 clientMeth == MethodKind.NONE) {
   240             return false;
   241         } else if (samPkg != PackageKind.NO_PKG &&
   242                 modKind != ModifierKind.PUBLIC &&
   243                 (retType == TypeKind.PKG_CLASS ||
   244                 argType == TypeKind.PKG_CLASS ||
   245                 thrownType == TypeKind.PKG_CLASS)) {
   246             //target must not contain inaccessible types
   247             return false;
   248         } else {
   249             return true;
   250         }
   251     }
   253     abstract class SourceFile extends SimpleJavaFileObject {
   255         protected String template;
   257         public SourceFile(String filename, String template) {
   258             super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
   259             this.template = template;
   260         }
   262         @Override
   263         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   264             return toString();
   265         }
   267         public abstract String toString();
   268     }
   270     static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
   272         boolean errorFound = false;
   274         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   275             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
   276                 errorFound = true;
   277             }
   278         }
   279     }
   280 }

mercurial