1 /* 2 * Copyright (c) 2013, 2019, 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 8231827 27 * @summary Ensure the LV table entries are generated for bindings 28 * @modules jdk.jdeps/com.sun.tools.classfile 29 * @compile -g --enable-preview -source ${jdk.version} LocalVariableTable.java 30 * @run main/othervm --enable-preview LocalVariableTable 31 */ 32 33 import java.io.*; 34 import java.lang.annotation.*; 35 import java.util.*; 36 import com.sun.tools.classfile.*; 37 38 /* 39 * The test checks that a LocalVariableTable attribute is generated for the 40 * method bodies containing patterns, and checks that the expected 41 * set of entries is found in the attribute. 42 * 43 * The test looks for test cases represented by nested classes whose 44 * name begins with "Pattern". Each such class contains a method 45 * with patterns, and because the test is compiled 46 * with -g, these methods should have a LocalVariableTable. The set of 47 * expected names in the LVT is provided in an annotation on the class for 48 * the test case. 49 */ 50 //Copied from: test/langtools/tools/javac/lambda/LocalVariableTable.java 51 public class LocalVariableTable { 52 public static void main(String... args) throws Exception { 53 new LocalVariableTable().run(); 54 } 55 56 void run() throws Exception { 57 // the declared classes are returned in an unspecified order, 58 // so for neatness, sort them by name before processing them 59 Class<?>[] classes = getClass().getDeclaredClasses(); 60 Arrays.sort(classes, (c1, c2) -> c1.getName().compareTo(c2.getName())); 61 62 for (Class<?> c : classes) { 63 if (c.getSimpleName().startsWith("Pattern")) 64 check(c); 65 } 66 if (errors > 0) 67 throw new Exception(errors + " errors found"); 68 } 69 70 /** Check an individual test case. */ 71 void check(Class<?> c) throws Exception { 72 System.err.println("Checking " + c.getSimpleName()); 73 74 Expect expect = c.getAnnotation(Expect.class); 75 if (expect == null) { 76 error("@Expect not found for class " + c.getSimpleName()); 77 return; 78 } 79 80 ClassFile cf = ClassFile.read(getClass().getResource(c.getName() + ".class").openStream()); 81 Method m = getMethodByName(cf, c.getSimpleName().contains("Lambda") ? "lambda$" : "test"); 82 if (m == null) { 83 error("test method not found"); 84 return; 85 } 86 87 Code_attribute code = (Code_attribute) m.attributes.get(Attribute.Code); 88 if (code == null) { 89 error("Code attribute not found"); 90 return; 91 } 92 93 LocalVariableTable_attribute lvt = 94 (LocalVariableTable_attribute) code.attributes.get(Attribute.LocalVariableTable); 95 if (lvt == null) { 96 error("LocalVariableTable attribute not found"); 97 return; 98 } 99 100 Set<String> foundNames = new LinkedHashSet<>(); 101 for (LocalVariableTable_attribute.Entry e: lvt.local_variable_table) { 102 foundNames.add(cf.constant_pool.getUTF8Value(e.name_index)); 103 } 104 105 Set<String> expectNames = new LinkedHashSet<>(Arrays.asList(expect.value())); 106 if (!foundNames.equals(expectNames)) { 107 Set<String> foundOnly = new LinkedHashSet<>(foundNames); 108 foundOnly.removeAll(expectNames); 109 for (String s: foundOnly) 110 error("Unexpected name found: " + s); 111 Set<String> expectOnly = new LinkedHashSet<>(expectNames); 112 expectOnly.removeAll(foundNames); 113 for (String s: expectOnly) 114 error("Expected name not found: " + s); 115 } 116 } 117 118 Method getMethodByName(ClassFile cf, String name) throws ConstantPoolException { 119 for (Method m: cf.methods) { 120 if (m.getName(cf.constant_pool).startsWith(name)) 121 return m; 122 } 123 return null; 124 } 125 126 /** Report an error. */ 127 void error(String msg) { 128 System.err.println("Error: " + msg); 129 errors++; 130 } 131 132 int errors; 133 134 /** 135 * Annotation used to provide the set of names expected in the LVT attribute. 136 */ 137 @Retention(RetentionPolicy.RUNTIME) 138 @interface Expect { 139 String[] value(); 140 } 141 142 /* 143 * ---------- Test cases --------------------------------------------------- 144 */ 145 146 @Expect({ "o", "s" }) 147 static class Pattern_Simple { 148 public static void test(Object o) { 149 if (o instanceof String s) { 150 s.length(); 151 } 152 } 153 } 154 155 @Expect({ "s" }) 156 static class Pattern_Lambda { 157 public static void test(Object o) { 158 if (o instanceof String s) { 159 Runnable r = () -> { 160 s.length(); 161 }; 162 } 163 } 164 } 165 166 } 167