1 /* 2 * Copyright (c) 2009, 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 * @summary Verify type annotation on binding patterns 27 * @library /tools/lib 28 * @modules java.compiler 29 * jdk.jdeps/com.sun.tools.javap 30 * @build toolbox.JavapTask 31 * @compile --enable-preview -source ${jdk.version} Patterns.java 32 * @run main/othervm --enable-preview Patterns 33 */ 34 35 import java.lang.annotation.*; 36 import java.util.regex.Matcher; 37 import java.util.regex.Pattern; 38 import java.util.stream.Collectors; 39 40 import toolbox.JavapTask; 41 import toolbox.Task; 42 import toolbox.ToolBox; 43 44 public class Patterns { 45 46 private ToolBox tb = new ToolBox(); 47 main(String[] args)48 public static void main(String[] args) throws Exception { 49 new Patterns().run(); 50 } 51 run()52 public void run() throws Exception { 53 String out = new JavapTask(tb) 54 .options("-private", 55 "-verbose") 56 .classpath(System.getProperty("test.classes")) 57 .classes("Patterns$SimpleBindingPattern") 58 .run() 59 .getOutputLines(Task.OutputKind.DIRECT) 60 .stream() 61 .collect(Collectors.joining("\n")); 62 63 String constantPool = out.substring(0, out.indexOf('{')); 64 65 out = out.replaceAll("(?ms) *Code:.*?\n( *RuntimeInvisibleTypeAnnotations:)", "$1"); 66 out = out.substring(out.indexOf('{')); 67 out = out.substring(0, out.lastIndexOf('}') + 1); 68 69 String A = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$A;"); 70 String CA = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$CA;"); 71 String value = snipCPNumber(constantPool, "value"); 72 73 String expected = """ 74 { 75 private static final java.lang.Object o; 76 descriptor: Ljava/lang/Object; 77 flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL 78 79 private static final boolean B1s; 80 descriptor: Z 81 flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL 82 83 private static final boolean B1m; 84 descriptor: Z 85 flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL 86 87 private final boolean B2s; 88 descriptor: Z 89 flags: (0x0012) ACC_PRIVATE, ACC_FINAL 90 91 private final boolean B2m; 92 descriptor: Z 93 flags: (0x0012) ACC_PRIVATE, ACC_FINAL 94 95 public Patterns$SimpleBindingPattern(); 96 descriptor: ()V 97 flags: (0x0001) ACC_PUBLIC 98 RuntimeInvisibleTypeAnnotations: 99 0: #_A_(): LOCAL_VARIABLE, {start_pc=206, length=11, index=2} 100 Patterns$SimpleBindingPattern$A 101 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=238, length=11, index=3} 102 Patterns$SimpleBindingPattern$CA( 103 value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] 104 ) 105 2: #_A_(): LOCAL_VARIABLE, {start_pc=21, length=11, index=1} 106 Patterns$SimpleBindingPattern$A 107 3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=53, length=11, index=1} 108 Patterns$SimpleBindingPattern$CA( 109 value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] 110 ) 111 4: #_A_(): LOCAL_VARIABLE, {start_pc=84, length=11, index=2} 112 Patterns$SimpleBindingPattern$A 113 5: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=116, length=11, index=3} 114 Patterns$SimpleBindingPattern$CA( 115 value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] 116 ) 117 6: #_A_(): LOCAL_VARIABLE, {start_pc=145, length=11, index=2} 118 Patterns$SimpleBindingPattern$A 119 7: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=177, length=11, index=3} 120 Patterns$SimpleBindingPattern$CA( 121 value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] 122 ) 123 124 void testPatterns(); 125 descriptor: ()V 126 flags: (0x0000) 127 RuntimeInvisibleTypeAnnotations: 128 0: #_A_(): LOCAL_VARIABLE, {start_pc=16, length=11, index=2} 129 Patterns$SimpleBindingPattern$A 130 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=48, length=11, index=3} 131 Patterns$SimpleBindingPattern$CA( 132 value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] 133 ) 134 135 void testPatternsDesugared(); 136 descriptor: ()V 137 flags: (0x0000) 138 RuntimeInvisibleTypeAnnotations: 139 0: #_A_(): LOCAL_VARIABLE, {start_pc=17, length=15, index=1; start_pc=51, length=15, index=1} 140 Patterns$SimpleBindingPattern$A 141 142 static {}; 143 descriptor: ()V 144 flags: (0x0008) ACC_STATIC 145 RuntimeInvisibleTypeAnnotations: 146 0: #_A_(): LOCAL_VARIABLE, {start_pc=21, length=11, index=0} 147 Patterns$SimpleBindingPattern$A 148 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=52, length=11, index=0} 149 Patterns$SimpleBindingPattern$CA( 150 value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] 151 ) 152 2: #_A_(): LOCAL_VARIABLE, {start_pc=83, length=11, index=1} 153 Patterns$SimpleBindingPattern$A 154 3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=112, length=11, index=2} 155 Patterns$SimpleBindingPattern$CA( 156 value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] 157 ) 158 }""".replace("_A_", A).replace("_CA_", CA).replace("_value_", value); 159 160 if (!expected.equals(out)) { 161 throw new AssertionError("Unexpected output:\n" + out + "\nexpected:\n" + expected); 162 } 163 } 164 snipCPNumber(String constantPool, String expectedConstant)165 private String snipCPNumber(String constantPool, String expectedConstant) { 166 Matcher m = Pattern.compile("#([0-9]+).*" + Pattern.quote(expectedConstant)) 167 .matcher(constantPool); 168 if (!m.find()) { 169 throw new AssertionError("Cannot find constant pool item"); 170 } 171 172 return m.group(1); 173 } 174 175 /*********************** Test class *************************/ 176 static class SimpleBindingPattern { 177 @Target(ElementType.TYPE_USE) 178 @Repeatable(CA.class) 179 @interface A {} 180 @Target(ElementType.TYPE_USE) 181 @interface CA { value()182 public A[] value(); 183 } 184 185 private static final Object o = ""; 186 private static final boolean B1s = o instanceof @A String s && s.isEmpty(); 187 private static final boolean B1m = o instanceof @A @A String s && s.isEmpty(); 188 private final boolean B2s = o instanceof @A String s && s.isEmpty(); 189 private final boolean B2m = o instanceof @A @A String s && s.isEmpty(); 190 191 static { 192 boolean B3s = o instanceof @A String s && s.isEmpty(); 193 boolean B3m = o instanceof @A @A String s && s.isEmpty(); 194 } 195 196 { 197 boolean B4s = o instanceof @A String s && s.isEmpty(); 198 boolean B4m = o instanceof @A @A String s && s.isEmpty(); 199 } 200 201 { 202 boolean B5s = o instanceof @A String s && s.isEmpty(); 203 boolean B5m = o instanceof @A @A String s && s.isEmpty(); 204 } 205 SimpleBindingPattern()206 public SimpleBindingPattern() { 207 boolean B6s = o instanceof @A String s && s.isEmpty(); 208 boolean B6m = o instanceof @A @A String s && s.isEmpty(); 209 } 210 testPatterns()211 void testPatterns() { 212 boolean B7s = o instanceof @A String s && s.isEmpty(); 213 boolean B7m = o instanceof @A @A String s && s.isEmpty(); 214 } 215 testPatternsDesugared()216 void testPatternsDesugared() { 217 @A String s; 218 boolean B8s = o instanceof String && (s = (String) o) == s && s.isEmpty(); 219 boolean B8sx = o instanceof String && (s = (String) o) == s && s.isEmpty(); 220 } 221 } 222 } 223