1 /* 2 * Copyright (c) 2012, 2015, 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 * Test SAM conversion of method references in combinations of different contexts, 29 * lambda body types(statement/expression), boxing/unboxing etc, to verify 30 * SAM conversion being conducted successfully as expected. 31 * @modules jdk.compiler 32 */ 33 34 import com.sun.source.util.JavacTask; 35 import java.net.URI; 36 import java.util.Arrays; 37 import javax.tools.Diagnostic; 38 import javax.tools.JavaCompiler; 39 import javax.tools.JavaFileObject; 40 import javax.tools.SimpleJavaFileObject; 41 import javax.tools.ToolProvider; 42 import javax.tools.StandardJavaFileManager; 43 44 public class SamConversionComboTest { 45 46 enum FInterface { 47 A("A", "interface A { Integer m(int i); }"), 48 B("B", "interface B { int m(Integer i); }"), 49 C("C", "interface C { int m(int i) throws Exception; }"); 50 51 String interfaceType; 52 String interfaceDef; 53 FInterface(String interfaceType, String interfaceDef)54 FInterface(String interfaceType, String interfaceDef) { 55 this.interfaceType = interfaceType; 56 this.interfaceDef = interfaceDef; 57 } 58 } 59 60 enum Context { 61 ASSIGNMENT("#FType f = #MR;"), 62 METHOD_CALL("void method1(#FType f) { }\n" + 63 "void method2() {\n" + 64 " method1(#MR);\n" + 65 "}"), 66 CONSTRUCTOR("X x = new X(#MR);"), 67 RETURN_OF_METHOD("#FType method1() {\n" + 68 " return #MR;\n" + 69 "}"), 70 ARRAY_INITIALIZER("#FType[] oarray = {#MR};"), 71 LAMBDA_BODY("#FType f = n -> ((#FType)#MR).m(n);"), 72 CAST("void test() throws Exception { int n = ((#FType)#MR).m(1); }"), 73 CONDITIONAL_EXPRESSION("#FType f = 2 > 1 ? #MR : null;"); 74 75 String context; 76 Context(String context)77 Context(String context) { 78 this.context = context; 79 } 80 getContext(FInterface f, MethodReference mr)81 String getContext(FInterface f, MethodReference mr) { 82 return context.replace("#FType", f.interfaceType).replace("#MR", mr.mrValue); 83 } 84 } 85 86 enum MethodReference { 87 METHOD1("X::method1"), 88 METHOD2("new X()::method2"), 89 METHOD3("X::method3"), 90 METHOD4("new X()::method4"), 91 METHOD5("new X()::method5"), 92 METHOD6("X::method6"), 93 METHOD7("X::method7"), 94 METHOD8("X::method8"); 95 96 String mrValue; 97 MethodReference(String mr)98 MethodReference(String mr) { 99 mrValue = mr; 100 } 101 } 102 103 enum MethodDef { 104 METHOD1(" static Integer method1(int n) {\n" + 105 " return n + 1;\n" + 106 " }\n", 0), 107 METHOD2(" int method2(Integer n) {\n" + 108 " return value == 0 ? n + 2 : n + value;\n" + 109 " }\n", 1), 110 METHOD3(" static int method3(int n) {\n" + 111 " return n + 3;\n" + 112 " }\n", 2), 113 METHOD4(" Integer method4(Integer n) {\n" + 114 " return value == 0 ? n + 4 : n + value;\n" + 115 " }\n", 3), 116 METHOD5(" Integer method5(Integer n) {\n" + 117 " return value == 0 ? new Integer(n + 5) : new Integer(n + value);\n" + 118 " }\n", 4), 119 METHOD6(" static int method6(Integer n) throws Exception{\n" + 120 " throw new Exception();\n" + 121 " }\n", 5), 122 METHOD7(" static int method7(String s){\n" + 123 " return s.length();\n" + 124 " }\n", 6), 125 METHOD8(" static String method8(Integer n){\n" + 126 " return n + \"\";\n" + 127 " }\n", 7); 128 129 String methodStr; 130 int index; 131 MethodDef(String ms, int i)132 MethodDef(String ms, int i) { 133 methodStr = ms; 134 index = i; 135 } 136 getMethodReference()137 MethodReference getMethodReference() { 138 return MethodReference.values()[index]; 139 } 140 } 141 142 SourceFile samSourceFile = new SourceFile("FInterface.java", "#C") { 143 public String toString() { 144 String interfaces = ""; 145 for(FInterface fi : FInterface.values()) 146 interfaces += fi.interfaceDef + "\n"; 147 return template.replace("#C", interfaces); 148 } 149 }; 150 151 String clientTemplate = "class Client {\n" + 152 " #Context\n" + 153 "}\n\n" + 154 155 "class X {\n" + 156 " int value = 0;\n\n" + 157 158 " X() {\n" + 159 " }\n\n" + 160 161 " X(A a) {\n" + 162 " value = a.m(9);\n" + 163 " }\n\n" + 164 165 " X(B b) {\n" + 166 " value = b.m(9);\n" + 167 " }\n\n" + 168 169 " X(C c) {\n" + 170 " try {\n" + 171 " value = c.m(9);\n" + 172 " } catch (Exception e){}\n" + 173 " }\n\n" + 174 175 "#MethodDef" + 176 "}"; 177 178 SourceFile clientSourceFile = new SourceFile("Client.java", clientTemplate) { 179 public String toString() { 180 return template.replace("#Context", context.getContext(fInterface, methodReference)).replace("#MethodDef", methodDef.methodStr); 181 } 182 }; 183 checkSamConversion()184 boolean checkSamConversion() { 185 if(methodDef == MethodDef.METHOD7 || methodDef == MethodDef.METHOD8)//method signature mismatch 186 return false; 187 if(context != Context.CONSTRUCTOR && fInterface != FInterface.C && methodDef == MethodDef.METHOD6) 188 //method that throws exceptions not thrown by the interface method is a mismatch 189 return false; 190 if(context == Context.CONSTRUCTOR) 191 return false; 192 return true; 193 } 194 test()195 void test() throws Exception { 196 System.out.println("\n===================================="); 197 System.out.println(fInterface + ", " + context + ", " + methodReference); 198 System.out.println(samSourceFile + "\n" + clientSourceFile); 199 200 DiagnosticChecker dc = new DiagnosticChecker(); 201 JavacTask ct = (JavacTask)comp.getTask(null, fm, dc, null, null, Arrays.asList(samSourceFile, clientSourceFile)); 202 ct.analyze(); 203 if (dc.errorFound == checkSamConversion()) { 204 throw new AssertionError(samSourceFile + "\n\n" + clientSourceFile); 205 } 206 count++; 207 } 208 209 abstract class SourceFile extends SimpleJavaFileObject { 210 211 protected String template; 212 SourceFile(String filename, String template)213 public SourceFile(String filename, String template) { 214 super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE); 215 this.template = template; 216 } 217 218 @Override getCharContent(boolean ignoreEncodingErrors)219 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 220 return toString(); 221 } 222 toString()223 public abstract String toString(); 224 } 225 226 static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { 227 228 boolean errorFound = false; 229 report(Diagnostic<? extends JavaFileObject> diagnostic)230 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 231 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { 232 errorFound = true; 233 } 234 } 235 } 236 237 FInterface fInterface; 238 Context context; 239 MethodDef methodDef; 240 MethodReference methodReference; 241 static int count = 0; 242 243 static JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); 244 static StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); 245 SamConversionComboTest(FInterface f, Context c, MethodDef md)246 SamConversionComboTest(FInterface f, Context c, MethodDef md) { 247 fInterface = f; 248 context = c; 249 methodDef = md; 250 methodReference = md.getMethodReference(); 251 } 252 main(String[] args)253 public static void main(String[] args) throws Exception { 254 try { 255 for(Context ct : Context.values()) { 256 for (FInterface fi : FInterface.values()) { 257 for (MethodDef md: MethodDef.values()) { 258 new SamConversionComboTest(fi, ct, md).test(); 259 } 260 } 261 } 262 System.out.println("total tests: " + count); 263 } finally { 264 fm.close(); 265 } 266 } 267 } 268