langtools/test/tools/javac/lambda/LambdaConversionTest.java
changeset 14723 46aa71a5e4e0
parent 14722 aaa39655aa2e
child 14724 b542db73539a
equal deleted inserted replaced
14722:aaa39655aa2e 14723:46aa71a5e4e0
     1 /*
       
     2  * Copyright (c) 2011, 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  */
       
    23 
       
    24 /**
       
    25  * @test
       
    26  * @bug 8003280
       
    27  * @summary Add lambda tests
       
    28  *  perform several automated checks in lambda conversion, esp. around accessibility
       
    29  * @author  Maurizio Cimadamore
       
    30  * @run main LambdaConversionTest
       
    31  */
       
    32 
       
    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.ToolProvider;
       
    41 
       
    42 public class LambdaConversionTest {
       
    43 
       
    44     enum PackageKind {
       
    45         NO_PKG(""),
       
    46         PKG_A("a");
       
    47 
       
    48         String pkg;
       
    49 
       
    50         PackageKind(String pkg) {
       
    51             this.pkg = pkg;
       
    52         }
       
    53 
       
    54         String getPkgDecl() {
       
    55             return this == NO_PKG ?
       
    56                 "" :
       
    57                 "package " + pkg + ";";
       
    58         }
       
    59 
       
    60         String getImportStat() {
       
    61             return this == NO_PKG ?
       
    62                 "" :
       
    63                 "import " + pkg + ".*;";
       
    64         }
       
    65     }
       
    66 
       
    67     enum SamKind {
       
    68         CLASS("public class Sam {  }"),
       
    69         ABSTACT_CLASS("public abstract class Sam {  }"),
       
    70         ANNOTATION("public @interface Sam {  }"),
       
    71         ENUM("public enum Sam { }"),
       
    72         INTERFACE("public interface Sam { \n #METH; \n }");
       
    73 
       
    74         String sam_str;
       
    75 
       
    76         SamKind(String sam_str) {
       
    77             this.sam_str = sam_str;
       
    78         }
       
    79 
       
    80         String getSam(String methStr) {
       
    81             return sam_str.replaceAll("#METH", methStr);
       
    82         }
       
    83     }
       
    84 
       
    85     enum ModifierKind {
       
    86         PUBLIC("public"),
       
    87         PACKAGE("");
       
    88 
       
    89         String modifier_str;
       
    90 
       
    91         ModifierKind(String modifier_str) {
       
    92             this.modifier_str = modifier_str;
       
    93         }
       
    94 
       
    95         boolean stricterThan(ModifierKind that) {
       
    96             return this.ordinal() > that.ordinal();
       
    97         }
       
    98     }
       
    99 
       
   100     enum TypeKind {
       
   101         EXCEPTION("Exception"),
       
   102         PKG_CLASS("PackageClass");
       
   103 
       
   104         String typeStr;
       
   105 
       
   106         private TypeKind(String typeStr) {
       
   107             this.typeStr = typeStr;
       
   108         }
       
   109     }
       
   110 
       
   111     enum MethodKind {
       
   112         NONE(""),
       
   113         NON_GENERIC("public #R m(#ARG s) throws #T;"),
       
   114         GENERIC("public <X> #R m(#ARG s) throws #T;");
       
   115 
       
   116         String methodTemplate;
       
   117 
       
   118         private MethodKind(String methodTemplate) {
       
   119             this.methodTemplate = methodTemplate;
       
   120         }
       
   121 
       
   122         String getMethod(TypeKind retType, TypeKind argType, TypeKind thrownType) {
       
   123             return methodTemplate.replaceAll("#R", retType.typeStr).
       
   124                     replaceAll("#ARG", argType.typeStr).
       
   125                     replaceAll("#T", thrownType.typeStr);
       
   126         }
       
   127     }
       
   128 
       
   129     public static void main(String[] args) throws Exception {
       
   130         for (PackageKind samPkg : PackageKind.values()) {
       
   131             for (ModifierKind modKind : ModifierKind.values()) {
       
   132                 for (SamKind samKind : SamKind.values()) {
       
   133                     for (MethodKind meth : MethodKind.values()) {
       
   134                         for (TypeKind retType : TypeKind.values()) {
       
   135                             for (TypeKind argType : TypeKind.values()) {
       
   136                                 for (TypeKind thrownType : TypeKind.values()) {
       
   137                                     new LambdaConversionTest(samPkg, modKind, samKind,
       
   138                                             meth, retType, argType, thrownType).test();
       
   139                                 }
       
   140                             }
       
   141                         }
       
   142                     }
       
   143                 }
       
   144             }
       
   145         }
       
   146     }
       
   147 
       
   148     PackageKind samPkg;
       
   149     ModifierKind modKind;
       
   150     SamKind samKind;
       
   151     MethodKind meth;
       
   152     TypeKind retType;
       
   153     TypeKind argType;
       
   154     TypeKind thrownType;
       
   155 
       
   156     SourceFile samSourceFile = new SourceFile("Sam.java", "#P \n #C") {
       
   157         public String toString() {
       
   158             return template.replaceAll("#P", samPkg.getPkgDecl()).
       
   159                     replaceAll("#C", samKind.getSam(meth.getMethod(retType, argType, thrownType)));
       
   160         }
       
   161     };
       
   162 
       
   163     SourceFile pkgClassSourceFile = new SourceFile("PackageClass.java",
       
   164                                                    "#P\n #M class PackageClass extends Exception { }") {
       
   165         public String toString() {
       
   166             return template.replaceAll("#P", samPkg.getPkgDecl()).
       
   167                     replaceAll("#M", modKind.modifier_str);
       
   168         }
       
   169     };
       
   170 
       
   171     SourceFile clientSourceFile = new SourceFile("Client.java",
       
   172                                                  "#I\n class Client { Sam s = x -> null; }") {
       
   173         public String toString() {
       
   174             return template.replaceAll("#I", samPkg.getImportStat());
       
   175         }
       
   176     };
       
   177 
       
   178     LambdaConversionTest(PackageKind samPkg, ModifierKind modKind, SamKind samKind,
       
   179             MethodKind meth, TypeKind retType, TypeKind argType, TypeKind thrownType) {
       
   180         this.samPkg = samPkg;
       
   181         this.modKind = modKind;
       
   182         this.samKind = samKind;
       
   183         this.meth = meth;
       
   184         this.retType = retType;
       
   185         this.argType = argType;
       
   186         this.thrownType = thrownType;
       
   187     }
       
   188 
       
   189     void test() throws Exception {
       
   190         final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
       
   191         DiagnosticChecker dc = new DiagnosticChecker();
       
   192         JavacTask ct = (JavacTask)tool.getTask(null, null, dc,
       
   193                 null, null, Arrays.asList(samSourceFile, pkgClassSourceFile, clientSourceFile));
       
   194         ct.analyze();
       
   195         if (dc.errorFound == checkSamConversion()) {
       
   196             throw new AssertionError(samSourceFile + "\n\n" + pkgClassSourceFile + "\n\n" + clientSourceFile);
       
   197         }
       
   198     }
       
   199 
       
   200     boolean checkSamConversion() {
       
   201         if (samKind != SamKind.INTERFACE) {
       
   202             //sam type must be an interface
       
   203             return false;
       
   204         } else if (meth != MethodKind.NON_GENERIC) {
       
   205             //target method must be non-generic
       
   206             return false;
       
   207         } else if (samPkg != PackageKind.NO_PKG &&
       
   208                 modKind != ModifierKind.PUBLIC &&
       
   209                 (retType == TypeKind.PKG_CLASS ||
       
   210                 argType == TypeKind.PKG_CLASS ||
       
   211                 thrownType == TypeKind.PKG_CLASS)) {
       
   212             //target must not contain inaccessible types
       
   213             return false;
       
   214         } else {
       
   215             return true;
       
   216         }
       
   217     }
       
   218 
       
   219     abstract class SourceFile extends SimpleJavaFileObject {
       
   220 
       
   221         protected String template;
       
   222 
       
   223         public SourceFile(String filename, String template) {
       
   224             super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE);
       
   225             this.template = template;
       
   226         }
       
   227 
       
   228         @Override
       
   229         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
       
   230             return toString();
       
   231         }
       
   232 
       
   233         public abstract String toString();
       
   234     }
       
   235 
       
   236     static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
       
   237 
       
   238         boolean errorFound = false;
       
   239 
       
   240         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
       
   241             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
       
   242                 errorFound = true;
       
   243             }
       
   244         }
       
   245     }
       
   246 }