Mon, 08 Apr 2013 15:53:08 +0100
8010404: Lambda debugging: redundant LineNumberTable entry for lambda capture
Summary: Ignore indy entries in LineNumberTable
Reviewed-by: jjg
mcimadamore@1415 | 1 | /* |
mcimadamore@1415 | 2 | * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. |
mcimadamore@1415 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
mcimadamore@1415 | 4 | * |
mcimadamore@1415 | 5 | * This code is free software; you can redistribute it and/or modify it |
mcimadamore@1415 | 6 | * under the terms of the GNU General Public License version 2 only, as |
mcimadamore@1415 | 7 | * published by the Free Software Foundation. |
mcimadamore@1415 | 8 | * |
mcimadamore@1415 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
mcimadamore@1415 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
mcimadamore@1415 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
mcimadamore@1415 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
mcimadamore@1415 | 13 | * accompanied this code). |
mcimadamore@1415 | 14 | * |
mcimadamore@1415 | 15 | * You should have received a copy of the GNU General Public License version |
mcimadamore@1415 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
mcimadamore@1415 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
mcimadamore@1415 | 18 | * |
mcimadamore@1415 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
mcimadamore@1415 | 20 | * or visit www.oracle.com if you need additional information or have any |
mcimadamore@1415 | 21 | * questions. |
mcimadamore@1415 | 22 | */ |
mcimadamore@1415 | 23 | |
mcimadamore@1415 | 24 | /** |
mcimadamore@1415 | 25 | * @test |
mcimadamore@1415 | 26 | * @bug 8003280 |
mcimadamore@1415 | 27 | * @summary Add lambda tests |
mcimadamore@1415 | 28 | * Test SAM conversion of lambda expressions in combinations of different contexts, |
mcimadamore@1415 | 29 | * lambda body types(statement/expression), explict/implicit target type etc, to verify |
mcimadamore@1415 | 30 | * SAM conversion being conducted successfully as expected. |
mcimadamore@1415 | 31 | */ |
mcimadamore@1415 | 32 | |
mcimadamore@1415 | 33 | import com.sun.source.util.JavacTask; |
mcimadamore@1415 | 34 | import java.net.URI; |
mcimadamore@1415 | 35 | import java.util.Arrays; |
mcimadamore@1415 | 36 | import javax.tools.Diagnostic; |
mcimadamore@1415 | 37 | import javax.tools.JavaCompiler; |
mcimadamore@1415 | 38 | import javax.tools.JavaFileObject; |
mcimadamore@1415 | 39 | import javax.tools.SimpleJavaFileObject; |
mcimadamore@1415 | 40 | import javax.tools.ToolProvider; |
mcimadamore@1415 | 41 | |
mcimadamore@1415 | 42 | public class SamConversionComboTest { |
mcimadamore@1415 | 43 | |
mcimadamore@1415 | 44 | enum FInterface { |
mcimadamore@1415 | 45 | A("A", "interface A { Integer m(int i); }"), |
mcimadamore@1415 | 46 | B("B", "interface B { int m(Integer i); }"), |
mcimadamore@1415 | 47 | C("C", "interface C { int m(Integer i) throws Exception; }"); |
mcimadamore@1415 | 48 | |
mcimadamore@1415 | 49 | String interfaceType; |
mcimadamore@1415 | 50 | String interfaceDef; |
mcimadamore@1415 | 51 | |
mcimadamore@1415 | 52 | FInterface(String interfaceType, String interfaceDef) { |
mcimadamore@1415 | 53 | this.interfaceType = interfaceType; |
mcimadamore@1415 | 54 | this.interfaceDef = interfaceDef; |
mcimadamore@1415 | 55 | } |
mcimadamore@1415 | 56 | |
mcimadamore@1415 | 57 | String getParameterType() { |
mcimadamore@1415 | 58 | switch(this) { |
mcimadamore@1415 | 59 | case A: |
mcimadamore@1415 | 60 | return "int"; |
mcimadamore@1415 | 61 | case B: |
mcimadamore@1415 | 62 | case C: |
mcimadamore@1415 | 63 | return "Integer"; |
mcimadamore@1415 | 64 | default: |
mcimadamore@1415 | 65 | return null; |
mcimadamore@1415 | 66 | } |
mcimadamore@1415 | 67 | } |
mcimadamore@1415 | 68 | } |
mcimadamore@1415 | 69 | |
mcimadamore@1415 | 70 | enum Context { |
mcimadamore@1415 | 71 | ASSIGNMENT("#FType f = #LBody;"), |
mcimadamore@1415 | 72 | METHOD_CALL("void method1(#FType f) { }\n" + |
mcimadamore@1415 | 73 | " void method2() {\n" + |
mcimadamore@1415 | 74 | " method1(#LBody);\n" + |
mcimadamore@1415 | 75 | " }"), |
mcimadamore@1415 | 76 | CONSTRUCTOR("X x = new X(#LBody);"), |
mcimadamore@1415 | 77 | RETURN_OF_METHOD("#FType method1() {\n" + |
mcimadamore@1415 | 78 | " return #LBody;\n" + |
mcimadamore@1415 | 79 | "}"), |
mcimadamore@1415 | 80 | ARRAY_INITIALIZER("Object[] oarray = {\"a\", 1, (#FType)#LBody};"), |
mcimadamore@1415 | 81 | LAMBDA_BODY("#FType f = n -> ((#FType)#LBody).m(n);"), |
mcimadamore@1415 | 82 | CAST("void test() throws Exception { int n = ((#FType)#LBody).m(1); }"), |
mcimadamore@1415 | 83 | CONDITIONAL_EXPRESSION("#FType f = 2 > 1 ? #LBody : null;"); |
mcimadamore@1415 | 84 | |
mcimadamore@1415 | 85 | String context; |
mcimadamore@1415 | 86 | |
mcimadamore@1415 | 87 | Context(String context) { |
mcimadamore@1415 | 88 | this.context = context; |
mcimadamore@1415 | 89 | } |
mcimadamore@1415 | 90 | |
mcimadamore@1415 | 91 | String getContext(FInterface f, LambdaKind lk, LambdaBody lb, ReturnValue rv) { |
mcimadamore@1415 | 92 | return context.replace("#FType", f.interfaceType).replace("#LBody", lb.getLambdaBody(f, lk, rv)); |
mcimadamore@1415 | 93 | } |
mcimadamore@1415 | 94 | } |
mcimadamore@1415 | 95 | |
mcimadamore@1415 | 96 | enum LambdaKind { |
mcimadamore@1415 | 97 | EXPRESSION("#VAL"), |
mcimadamore@1415 | 98 | STATEMENT("{return #VAL;}"), |
mcimadamore@1415 | 99 | EXCEPTION_STMT("{throw new Exception();}"); |
mcimadamore@1415 | 100 | |
mcimadamore@1415 | 101 | String stmt; |
mcimadamore@1415 | 102 | |
mcimadamore@1415 | 103 | LambdaKind(String stmt) { |
mcimadamore@1415 | 104 | this.stmt = stmt; |
mcimadamore@1415 | 105 | } |
mcimadamore@1415 | 106 | } |
mcimadamore@1415 | 107 | |
mcimadamore@1415 | 108 | enum ReturnValue { |
mcimadamore@1415 | 109 | INT("i + 1"), |
mcimadamore@1415 | 110 | INTEGER("new Integer(i+1)"), |
mcimadamore@1415 | 111 | INT2("i.intValue() + 1"), |
mcimadamore@1415 | 112 | STRING("i + \"\""), |
mcimadamore@1415 | 113 | DOUBLE("i * 1.0"); |
mcimadamore@1415 | 114 | |
mcimadamore@1415 | 115 | String rValue; |
mcimadamore@1415 | 116 | |
mcimadamore@1415 | 117 | ReturnValue(String rValue) { |
mcimadamore@1415 | 118 | this.rValue = rValue; |
mcimadamore@1415 | 119 | } |
mcimadamore@1415 | 120 | } |
mcimadamore@1415 | 121 | |
mcimadamore@1415 | 122 | enum LambdaBody { |
mcimadamore@1415 | 123 | IMPLICIT("i -> #RET"),//type inferred |
mcimadamore@1415 | 124 | EXPLICIT("(#Type i) -> #RET");//explicit type |
mcimadamore@1415 | 125 | |
mcimadamore@1415 | 126 | String bodyStr; |
mcimadamore@1415 | 127 | |
mcimadamore@1415 | 128 | LambdaBody(String bodyStr) { |
mcimadamore@1415 | 129 | this.bodyStr = bodyStr; |
mcimadamore@1415 | 130 | } |
mcimadamore@1415 | 131 | |
mcimadamore@1415 | 132 | String getLambdaBody(FInterface fi, LambdaKind lk, ReturnValue rv) { |
mcimadamore@1415 | 133 | return bodyStr.replace("#Type", fi.getParameterType()).replace("#RET", lk.stmt.replace("#VAL", rv.rValue)); |
mcimadamore@1415 | 134 | } |
mcimadamore@1415 | 135 | } |
mcimadamore@1415 | 136 | |
mcimadamore@1415 | 137 | boolean checkSamConversion() { |
mcimadamore@1415 | 138 | if(lambdaKind != LambdaKind.EXCEPTION_STMT && (returnValue == ReturnValue.DOUBLE || returnValue == ReturnValue.STRING)) //return type mismatch |
mcimadamore@1415 | 139 | return false; |
mcimadamore@1415 | 140 | if(context != Context.CONSTRUCTOR) {//context other than construcotr argument |
mcimadamore@1415 | 141 | if(fInterface != FInterface.C && lambdaKind == LambdaKind.EXCEPTION_STMT) |
mcimadamore@1415 | 142 | return false; |
mcimadamore@1415 | 143 | if(fInterface == FInterface.A && returnValue == ReturnValue.INT2) |
mcimadamore@1415 | 144 | return false; |
mcimadamore@1415 | 145 | } |
mcimadamore@1415 | 146 | else { //constructor argument context |
mcimadamore@1415 | 147 | //match X(A a) or X(B b) or X(C c) |
mcimadamore@1415 | 148 | if (lambdaKind == LambdaKind.EXCEPTION_STMT) { |
mcimadamore@1415 | 149 | return false; //ambiguous target type |
mcimadamore@1415 | 150 | } |
mcimadamore@1415 | 151 | else if(lambdaBody == LambdaBody.IMPLICIT) { |
mcimadamore@1510 | 152 | return false; |
mcimadamore@1415 | 153 | } |
mcimadamore@1415 | 154 | else { //explicit parameter type |
mcimadamore@1415 | 155 | if(fInterface.getParameterType().equals("Integer")) //ambiguous target type |
mcimadamore@1415 | 156 | //e.g. X x = new X((Integer i) -> i + 1); |
mcimadamore@1415 | 157 | return false; |
mcimadamore@1415 | 158 | if(returnValue == ReturnValue.INT2) |
mcimadamore@1415 | 159 | //e.g. X x = new X(int i -> i.intValue() + 1); |
mcimadamore@1415 | 160 | return false; |
mcimadamore@1415 | 161 | } |
mcimadamore@1415 | 162 | } |
mcimadamore@1415 | 163 | return true; |
mcimadamore@1415 | 164 | } |
mcimadamore@1415 | 165 | |
mcimadamore@1415 | 166 | SourceFile samSourceFile = new SourceFile("FInterface.java", "#C") { |
mcimadamore@1415 | 167 | public String toString() { |
mcimadamore@1415 | 168 | String interfaces = ""; |
mcimadamore@1415 | 169 | for(FInterface fi : FInterface.values()) |
mcimadamore@1415 | 170 | interfaces += fi.interfaceDef + "\n"; |
mcimadamore@1415 | 171 | return template.replace("#C", interfaces); |
mcimadamore@1415 | 172 | } |
mcimadamore@1415 | 173 | }; |
mcimadamore@1415 | 174 | |
mcimadamore@1415 | 175 | String clientTemplate = "class Client {\n" + |
mcimadamore@1415 | 176 | " #Context\n" + |
mcimadamore@1415 | 177 | "}\n\n" + |
mcimadamore@1415 | 178 | |
mcimadamore@1415 | 179 | "class X {\n" + |
mcimadamore@1415 | 180 | " int value = 0;\n\n" + |
mcimadamore@1415 | 181 | |
mcimadamore@1415 | 182 | " X(A a) {\n" + |
mcimadamore@1415 | 183 | " value = a.m(6);\n" + |
mcimadamore@1415 | 184 | " }\n\n" + |
mcimadamore@1415 | 185 | |
mcimadamore@1415 | 186 | " X(B b) {\n" + |
mcimadamore@1415 | 187 | " value = b.m(7);\n" + |
mcimadamore@1415 | 188 | " }\n\n" + |
mcimadamore@1415 | 189 | |
mcimadamore@1415 | 190 | " X(C c) {\n" + |
mcimadamore@1415 | 191 | " try {\n" + |
mcimadamore@1415 | 192 | " value = c.m(8);\n" + |
mcimadamore@1415 | 193 | " } catch (Exception e){}\n" + |
mcimadamore@1415 | 194 | " }\n" + |
mcimadamore@1415 | 195 | "}"; |
mcimadamore@1415 | 196 | SourceFile clientSourceFile = new SourceFile("Client.java", clientTemplate) { |
mcimadamore@1415 | 197 | public String toString() { |
mcimadamore@1415 | 198 | return template.replace("#Context", context.getContext(fInterface, lambdaKind, lambdaBody, returnValue)); |
mcimadamore@1415 | 199 | } |
mcimadamore@1415 | 200 | }; |
mcimadamore@1415 | 201 | |
mcimadamore@1415 | 202 | void test() throws Exception { |
mcimadamore@1415 | 203 | System.out.println("\n===================================="); |
mcimadamore@1415 | 204 | System.out.println(fInterface + ", " + context + ", " + lambdaKind + ", " + lambdaBody + ", " + returnValue); |
mcimadamore@1415 | 205 | System.out.println(samSourceFile + "\n"); |
mcimadamore@1415 | 206 | String clientFileStr = clientSourceFile.toString(); |
mcimadamore@1415 | 207 | System.out.println(clientFileStr.substring(0, clientFileStr.indexOf("\n\n"))); |
mcimadamore@1415 | 208 | |
mcimadamore@1415 | 209 | final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); |
mcimadamore@1415 | 210 | DiagnosticChecker dc = new DiagnosticChecker(); |
mcimadamore@1415 | 211 | JavacTask ct = (JavacTask)tool.getTask(null, null, dc, null, null, Arrays.asList(samSourceFile, clientSourceFile)); |
mcimadamore@1415 | 212 | ct.analyze(); |
mcimadamore@1415 | 213 | if (dc.errorFound == checkSamConversion()) { |
mcimadamore@1415 | 214 | throw new AssertionError(samSourceFile + "\n\n" + clientSourceFile); |
mcimadamore@1415 | 215 | } |
mcimadamore@1415 | 216 | count++; |
mcimadamore@1415 | 217 | } |
mcimadamore@1415 | 218 | |
mcimadamore@1415 | 219 | abstract class SourceFile extends SimpleJavaFileObject { |
mcimadamore@1415 | 220 | |
mcimadamore@1415 | 221 | protected String template; |
mcimadamore@1415 | 222 | |
mcimadamore@1415 | 223 | public SourceFile(String filename, String template) { |
mcimadamore@1415 | 224 | super(URI.create("myfo:/" + filename), JavaFileObject.Kind.SOURCE); |
mcimadamore@1415 | 225 | this.template = template; |
mcimadamore@1415 | 226 | } |
mcimadamore@1415 | 227 | |
mcimadamore@1415 | 228 | @Override |
mcimadamore@1415 | 229 | public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
mcimadamore@1415 | 230 | return toString(); |
mcimadamore@1415 | 231 | } |
mcimadamore@1415 | 232 | |
mcimadamore@1415 | 233 | public abstract String toString(); |
mcimadamore@1415 | 234 | } |
mcimadamore@1415 | 235 | |
mcimadamore@1415 | 236 | static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { |
mcimadamore@1415 | 237 | |
mcimadamore@1415 | 238 | boolean errorFound = false; |
mcimadamore@1415 | 239 | |
mcimadamore@1415 | 240 | public void report(Diagnostic<? extends JavaFileObject> diagnostic) { |
mcimadamore@1415 | 241 | if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { |
mcimadamore@1415 | 242 | errorFound = true; |
mcimadamore@1415 | 243 | } |
mcimadamore@1415 | 244 | } |
mcimadamore@1415 | 245 | } |
mcimadamore@1415 | 246 | |
mcimadamore@1415 | 247 | FInterface fInterface; |
mcimadamore@1415 | 248 | Context context; |
mcimadamore@1415 | 249 | LambdaBody lambdaBody; |
mcimadamore@1415 | 250 | LambdaKind lambdaKind; |
mcimadamore@1415 | 251 | ReturnValue returnValue; |
mcimadamore@1415 | 252 | static int count = 0; |
mcimadamore@1415 | 253 | |
mcimadamore@1415 | 254 | SamConversionComboTest(FInterface f, Context c, LambdaBody lb, LambdaKind lk, ReturnValue rv) { |
mcimadamore@1415 | 255 | fInterface = f; |
mcimadamore@1415 | 256 | context = c; |
mcimadamore@1415 | 257 | lambdaKind = lk; |
mcimadamore@1415 | 258 | lambdaBody = lb; |
mcimadamore@1415 | 259 | returnValue = rv; |
mcimadamore@1415 | 260 | } |
mcimadamore@1415 | 261 | |
mcimadamore@1415 | 262 | public static void main(String[] args) throws Exception { |
mcimadamore@1415 | 263 | for(Context ct : Context.values()) { |
mcimadamore@1415 | 264 | for (FInterface fi : FInterface.values()) { |
mcimadamore@1415 | 265 | for (LambdaKind lk: LambdaKind.values()) { |
mcimadamore@1415 | 266 | for (LambdaBody lb : LambdaBody.values()) { |
mcimadamore@1415 | 267 | for(ReturnValue rv : ReturnValue.values()) { |
mcimadamore@1415 | 268 | new SamConversionComboTest(fi, ct, lb, lk, rv).test(); |
mcimadamore@1415 | 269 | } |
mcimadamore@1415 | 270 | } |
mcimadamore@1415 | 271 | } |
mcimadamore@1415 | 272 | } |
mcimadamore@1415 | 273 | } |
mcimadamore@1415 | 274 | System.out.println("total tests: " + count); |
mcimadamore@1415 | 275 | } |
mcimadamore@1415 | 276 | } |