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