1 /*
   2  * Copyright (c) 2019, 2020, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /**
  27  * RecordCompilationTests
  28  *
  29  * @test 8250629
  30  * @summary Negative compilation tests, and positive compilation (smoke) tests for records
  31  * @library /lib/combo /tools/lib /tools/javac/lib
  32  * @modules
  33  *      jdk.compiler/com.sun.tools.javac.api
  34  *      jdk.compiler/com.sun.tools.javac.code
  35  *      jdk.compiler/com.sun.tools.javac.util
  36  *      jdk.jdeps/com.sun.tools.classfile
  37  * @build JavacTestingAbstractProcessor
  38  * @compile --enable-preview -source ${jdk.version} RecordCompilationTests.java
  39  * @run testng/othervm -DuseAP=false --enable-preview RecordCompilationTests
  40  * @run testng/othervm -DuseAP=true --enable-preview RecordCompilationTests
  41  */
  42 
  43 import java.io.File;
  44 
  45 import java.lang.annotation.ElementType;
  46 import java.util.Arrays;
  47 import java.util.EnumMap;
  48 import java.util.EnumSet;
  49 import java.util.HashSet;
  50 import java.util.List;
  51 import java.util.Map;
  52 import java.util.Set;
  53 import java.util.stream.Collectors;
  54 import java.util.stream.Stream;
  55 
  56 
  57 import com.sun.tools.javac.util.Assert;
  58 
  59 import javax.annotation.processing.AbstractProcessor;
  60 import javax.annotation.processing.RoundEnvironment;
  61 import javax.annotation.processing.SupportedAnnotationTypes;
  62 
  63 import javax.lang.model.element.AnnotationMirror;
  64 import javax.lang.model.element.AnnotationValue;
  65 import javax.lang.model.element.Element;
  66 import javax.lang.model.element.ElementKind;
  67 import javax.lang.model.element.ExecutableElement;
  68 import javax.lang.model.element.RecordComponentElement;
  69 import javax.lang.model.element.TypeElement;
  70 import javax.lang.model.element.VariableElement;
  71 
  72 import javax.lang.model.type.ArrayType;
  73 import javax.lang.model.type.TypeMirror;
  74 
  75 import com.sun.tools.classfile.AccessFlags;
  76 import com.sun.tools.classfile.Annotation;
  77 import com.sun.tools.classfile.Attribute;
  78 import com.sun.tools.classfile.Attributes;
  79 import com.sun.tools.classfile.ClassFile;
  80 import com.sun.tools.classfile.Code_attribute;
  81 import com.sun.tools.classfile.ConstantPool;
  82 import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info;
  83 import com.sun.tools.classfile.ConstantPool.CPInfo;
  84 import com.sun.tools.classfile.Field;
  85 import com.sun.tools.classfile.Instruction;
  86 import com.sun.tools.classfile.Method;
  87 import com.sun.tools.classfile.Record_attribute;
  88 import com.sun.tools.classfile.Record_attribute.ComponentInfo;
  89 import com.sun.tools.classfile.RuntimeAnnotations_attribute;
  90 import com.sun.tools.classfile.RuntimeTypeAnnotations_attribute;
  91 import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
  92 import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
  93 import com.sun.tools.classfile.RuntimeVisibleTypeAnnotations_attribute;
  94 import com.sun.tools.classfile.TypeAnnotation;
  95 
  96 import com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper;
  97 import com.sun.tools.javac.code.Attribute.TypeCompound;
  98 import com.sun.tools.javac.code.Symbol;
  99 import com.sun.tools.javac.code.Symbol.VarSymbol;
 100 import com.sun.tools.javac.util.JCDiagnostic;
 101 
 102 import org.testng.annotations.Test;
 103 import tools.javac.combo.CompilationTestCase;
 104 
 105 import static java.lang.annotation.ElementType.*;
 106 import static org.testng.Assert.assertEquals;
 107 
 108 /** Records are the first feature which sports automatic injection of (declarative and type) annotations : from a
 109  *  given record component to one or more record members, if applicable.
 110  *  This implies that the record's implementation can be stressed with the presence of annotation processors. Which is
 111  *  something the implementator could easily skip. For this reason this test is executed twice, once without the
 112  *  presence of any annotation processor and one with a simple annotation processor (which does not annotation processing
 113  *  at all) just to force at least a round of annotation processing.
 114  *
 115  *  Tests needing special compilation options need to store current options, set its customs options by invoking method
 116  *  `setCompileOptions` and then reset the previous compilation options for other tests. To see an example of this check
 117  *  method: testAnnos()
 118  */
 119 
 120 @Test
 121 public class RecordCompilationTests extends CompilationTestCase {
 122     // @@@ When records become a permanent feature, we don't need these any more
 123     private static String[] PREVIEW_OPTIONS = {
 124             "--enable-preview",
 125             "-source", Integer.toString(Runtime.version().feature())
 126     };
 127 
 128     private static String[] PREVIEW_OPTIONS_WITH_AP = {
 129             "--enable-preview",
 130             "-source", Integer.toString(Runtime.version().feature()),
 131             "-processor", SimplestAP.class.getName()
 132     };
 133 
 134     private static final List<String> BAD_COMPONENT_NAMES = List.of(
 135             "clone", "finalize", "getClass", "hashCode",
 136             "notify", "notifyAll", "toString", "wait");
 137 
 138     /* simplest annotation processor just to force a round of annotation processing for all tests
 139      */
 140     @SupportedAnnotationTypes("*")
 141     public static class SimplestAP extends AbstractProcessor {
 142         @Override
 143         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
 144             return true;
 145         }
 146     }
 147 
 148     public RecordCompilationTests() {
 149         boolean useAP = System.getProperty("useAP") == null ? false : System.getProperty("useAP").equals("true");
 150         setDefaultFilename("R.java");
 151         setCompileOptions(useAP ? PREVIEW_OPTIONS_WITH_AP : PREVIEW_OPTIONS);
 152         System.out.println(useAP ? "running all tests using an annotation processor" : "running all tests without annotation processor");
 153     }
 154 
 155     public void testMalformedDeclarations() {
 156         assertFail("compiler.err.premature.eof", "record R()");
 157         assertFail("compiler.err.expected", "record R();");
 158         assertFail("compiler.err.illegal.start.of.type", "record R(,) { }");
 159         assertFail("compiler.err.illegal.start.of.type", "record R((int x)) { }");
 160         assertFail("compiler.err.record.header.expected", "record R { }");
 161         assertFail("compiler.err.expected", "record R(foo) { }");
 162         assertFail("compiler.err.expected", "record R(int int) { }");
 163         assertFail("compiler.err.mod.not.allowed.here", "abstract record R(String foo) { }");
 164         //assertFail("compiler.err.illegal.combination.of.modifiers", "non-sealed record R(String foo) { }");
 165         assertFail("compiler.err.repeated.modifier", "public public record R(String foo) { }");
 166         assertFail("compiler.err.repeated.modifier", "private private record R(String foo) { }");
 167         assertFail("compiler.err.already.defined", "record R(int x, int x) {}");
 168         for (String s : List.of("var", "record"))
 169             assertFail("compiler.err.restricted.type.not.allowed.here", "record R(# x) { }", s);
 170         for (String s : List.of("public", "protected", "private", "static", "final", "transient", "volatile",
 171                 "abstract", "synchronized", "native", "strictfp")) // missing: sealed and non-sealed
 172             assertFail("compiler.err.record.cant.declare.field.modifiers", "record R(# String foo) { }", s);
 173         assertFail("compiler.err.varargs.must.be.last", "record R(int... x, int... y) {}");
 174         assertFail("compiler.err.instance.initializer.not.allowed.in.records", "record R(int i) { {} }");
 175     }
 176 
 177     public void testGoodDeclarations() {
 178         assertOK("public record R() { }");
 179         assertOK("record R() { }");
 180         assertOK("record R() implements java.io.Serializable, Runnable { public void run() { } }");
 181         assertOK("record R(int x) { }");
 182         assertOK("record R(int x, int y) { }");
 183         assertOK("record R(int... xs) { }");
 184         assertOK("record R(String... ss) { }");
 185         assertOK("@Deprecated record R(int x, int y) { }");
 186         assertOK("record R(@Deprecated int x, int y) { }");
 187         assertOK("record R<T>(T x, T y) { }");
 188     }
 189 
 190     public void testGoodMemberDeclarations() {
 191         String template = "public record R(int x) {\n"
 192                 + "    public R(int x) { this.x = x; }\n"
 193                 + "    public int x() { return x; }\n"
 194                 + "    public boolean equals(Object o) { return true; }\n"
 195                 + "    public int hashCode() { return 0; }\n"
 196                 + "    public String toString() { return null; }\n"
 197                 + "}";
 198         assertOK(template);
 199     }
 200 
 201     public void testBadComponentNames() {
 202         for (String s : BAD_COMPONENT_NAMES)
 203             assertFail("compiler.err.illegal.record.component.name", "record R(int #) { } ", s);
 204     }
 205 
 206     public void testRestrictedIdentifiers() {
 207         for (String s : List.of("interface record { void m(); }",
 208                 "@interface record { }",
 209                 "class record { }",
 210                 "record record(int x) { }",
 211                 "enum record { A, B }",
 212                 "class R<record> { }")) {
 213             assertFail(
 214                     "compiler.err.restricted.type.not.allowed",
 215                     diagWrapper -> {
 216                         JCDiagnostic diagnostic = ((DiagnosticSourceUnwrapper)diagWrapper).d;
 217                         Object[] args = diagnostic.getArgs();
 218                         Assert.check(args.length == 2);
 219                         Assert.check(args[1].toString().equals("JDK14"));
 220                     },
 221                     s);
 222         }
 223     }
 224 
 225     public void testValidMembers() {
 226         for (String s : List.of("record X(int j) { }",
 227                 "interface I { }",
 228                 "static { }",
 229                 "enum E { A, B }",
 230                 "class C { }"
 231         )) {
 232             assertOK("record R(int i) { # }", s);
 233         }
 234     }
 235 
 236     public void testCyclic() {
 237         // Cyclic records are OK, but cyclic inline records would not be
 238         assertOK("record R(R r) { }");
 239     }
 240 
 241     public void testBadExtends() {
 242         assertFail("compiler.err.expected", "record R(int x) extends Object { }");
 243         assertFail("compiler.err.expected", "record R(int x) {}\n"
 244                 + "record R2(int x) extends R { }");
 245         assertFail("compiler.err.cant.inherit.from.final", "record R(int x) {}\n"
 246                 + "class C extends R { }");
 247     }
 248 
 249     public void testNoExtendRecord() {
 250         assertFail("compiler.err.invalid.supertype.record",
 251                    """
 252                    class R extends Record {
 253                        public String toString() { return null; }
 254                        public int hashCode() { return 0; }
 255                        public boolean equals(Object o) { return false; }
 256                    }
 257                    """
 258         );
 259     }
 260 
 261     public void testFieldDeclarations() {
 262         // static fields are OK
 263         assertOK("public record R(int x) {\n" +
 264                 "    static int I = 1;\n" +
 265                 "    static final String S = \"Hello World!\";\n" +
 266                 "    static private Object O = null;\n" +
 267                 "    static protected Object O2 = null;\n" +
 268                 "}");
 269 
 270         // instance fields are not
 271         assertFail("compiler.err.record.cannot.declare.instance.fields",
 272                 "public record R(int x) {\n" +
 273                         "    private final int y = 0;" +
 274                         "}");
 275 
 276         // mutable instance fields definitely not
 277         assertFail("compiler.err.record.cannot.declare.instance.fields",
 278                 "public record R(int x) {\n" +
 279                         "    private int y = 0;" +
 280                         "}");
 281 
 282         // redeclaring components also not
 283         assertFail("compiler.err.record.cannot.declare.instance.fields",
 284                 "public record R(int x) {\n" +
 285                         "    private final int x;" +
 286                         "}");
 287     }
 288 
 289     public void testAccessorRedeclaration() {
 290         assertOK("public record R(int x) {\n" +
 291                 "    public int x() { return x; };" +
 292                 "}");
 293 
 294         assertOK("public record R(int... x) {\n" +
 295                 "    public int[] x() { return x; };" +
 296                 "}");
 297 
 298         assertOK("public record R(int x) {\n" +
 299                 "    public final int x() { return 0; };" +
 300                 "}");
 301 
 302         assertOK("public record R(int x) {\n" +
 303                 "    public final int x() { return 0; };" +
 304                 "}");
 305 
 306         assertFail("compiler.err.invalid.accessor.method.in.record",
 307                 "public record R(int x) {\n" +
 308                         "    final int x() { return 0; };" +
 309                         "}");
 310 
 311         assertFail("compiler.err.invalid.accessor.method.in.record",
 312                 "public record R(int x) {\n" +
 313                         "    int x() { return 0; };" +
 314                         "}");
 315 
 316         assertFail("compiler.err.invalid.accessor.method.in.record",
 317                 "public record R(int x) {\n" +
 318                         "    private int x() { return 0; };" +
 319                         "}");
 320 
 321         assertFail("compiler.err.invalid.accessor.method.in.record",
 322                    "public record R(int x) {\n" +
 323                    "    public int x() throws Exception { return 0; };" +
 324                    "}");
 325 
 326         for (String s : List.of("List", "List<?>", "Object", "ArrayList<String>", "int"))
 327             assertFail("compiler.err.invalid.accessor.method.in.record",
 328                     "import java.util.*;\n" +
 329                             "public record R(List<String> x) {\n" +
 330                             "    public # x() { return null; };" +
 331                             "}", s);
 332 
 333         assertFail("compiler.err.invalid.accessor.method.in.record",
 334                 "public record R(int x) {\n" +
 335                         "    public <T> int x() { return x; };" +
 336                         "}");
 337 
 338         assertFail("compiler.err.invalid.accessor.method.in.record",
 339                 "public record R(int x) {\n" +
 340                         "    static private final j = 0;" +
 341                         "    static public int x() { return j; };" +
 342                         "}");
 343     }
 344 
 345     public void testConstructorRedeclaration() {
 346         for (String goodCtor : List.of(
 347                 "public R(int x) { this(x, 0); }",
 348                 "public R(int x, int y) { this.x = x; this.y = y; }",
 349                 "public R { }"))
 350             assertOK("record R(int x, int y) { # }", goodCtor);
 351 
 352         assertOK("import java.util.*; record R(String x, String y) {  public R { Objects.requireNonNull(x); Objects.requireNonNull(y); } }");
 353 
 354         // Not OK to redeclare canonical without DA
 355         assertFail("compiler.err.var.might.not.have.been.initialized", "record R(int x, int y) { # }",
 356                    "public R(int x, int y) { this.x = x; }");
 357 
 358         // Not OK to rearrange or change names
 359         for (String s : List.of("public R(int y, int x) { this.x = x; this.y = y; }",
 360                                 "public R(int _x, int _y) { this.x = _x; this.y = _y; }"))
 361             assertFail("compiler.err.invalid.canonical.constructor.in.record", "record R(int x, int y) { # }", s);
 362 
 363         // ctor args must match types
 364         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 365                 "import java.util.*;\n" +
 366                         "record R(List<String> list) { # }",
 367                 "R(List list) { this.list = list; }");
 368 
 369         // canonical ctor should not throw checked exceptions
 370         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 371                    "record R() { # }",
 372                    "public R() throws Exception { }");
 373 
 374         // same for compact
 375         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 376                 "record R() { # }",
 377                 "public R throws Exception { }");
 378 
 379         // not even unchecked exceptions
 380         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 381                 "record R() { # }",
 382                  "public R() throws IllegalArgumentException { }");
 383 
 384         // ditto
 385         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 386                 "record R() { # }",
 387                 "public R throws IllegalArgumentException { }");
 388 
 389         // If types match, names must match
 390         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 391                    "record R(int x, int y) { public R(int y, int x) { this.x = this.y = 0; }}");
 392 
 393         // first invocation should be one to the canonical
 394         assertFail("compiler.err.first.statement.must.be.call.to.another.constructor",
 395                 "record R(int x, int y) { public R(int y, int x, int z) { this.x = this.y = 0; } }");
 396 
 397         assertOK("record R(int x, int y) { " +
 398                  "    public R(int x, int y, int z) { this(x, y); } " +
 399                  "}");
 400 
 401         assertOK("record R(int x) { " +
 402                 "    public R(int x, int y) { this(x, y, 0); } " +
 403                 "    public R(int x, int y, int z) { this(x); } " +
 404                 "}");
 405 
 406         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 407                 "record R<T>(T a) { # }",
 408                 "public <T> R {}");
 409 
 410         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 411                 "record R(int i) { # }",
 412                 "public <T> R(int i) { this.i = i; }");
 413 
 414         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 415                 "record R<T>(T a) { # }",
 416                 "public <T> R(T a) { this.a = a; }");
 417 
 418         assertFail("compiler.err.invalid.canonical.constructor.in.record",
 419                 "record R(int a) { # }",
 420                 "public R(int a) { super(); this.a = a; }");
 421     }
 422 
 423     public void testAnnotationCriteria() {
 424         String imports = "import java.lang.annotation.*;\n";
 425         String template = "@Target({ # }) @interface A {}\n";
 426         EnumMap<ElementType, String> annotations = new EnumMap<>(ElementType.class);
 427         for (ElementType e : values())
 428             annotations.put(e, template.replace("#", "ElementType." + e.name()));
 429         EnumSet<ElementType> goodSet = EnumSet.of(RECORD_COMPONENT, FIELD, METHOD, PARAMETER, TYPE_USE);
 430         EnumSet<ElementType> badSet = EnumSet.of(CONSTRUCTOR, PACKAGE, TYPE, LOCAL_VARIABLE, ANNOTATION_TYPE, TYPE_PARAMETER, MODULE);
 431 
 432         assertEquals(goodSet.size() + badSet.size(), values().length);
 433         String A_GOOD = template.replace("#",
 434                                          goodSet.stream().map(ElementType::name).map(s -> "ElementType." + s).collect(Collectors.joining(",")));
 435         String A_BAD = template.replace("#",
 436                                         badSet.stream().map(ElementType::name).map(s -> "ElementType." + s).collect(Collectors.joining(",")));
 437         String A_ALL = template.replace("#",
 438                                         Stream.of(ElementType.values()).map(ElementType::name).map(s -> "ElementType." + s).collect(Collectors.joining(",")));
 439         String A_NONE = "@interface A {}";
 440 
 441         for (ElementType e : goodSet)
 442             assertOK(imports + annotations.get(e) + "record R(@A int x) { }");
 443         assertOK(imports + A_GOOD + "record R(@A int x) { }");
 444         assertOK(imports + A_ALL + "record R(@A int x) { }");
 445         assertOK(imports + A_NONE);
 446 
 447         for (ElementType e : badSet) {
 448             assertFail("compiler.err.annotation.type.not.applicable", imports + annotations.get(e) + "record R(@A int x) { }");
 449         }
 450 
 451         assertFail("compiler.err.annotation.type.not.applicable", imports + A_BAD + "record R(@A int x) { }");
 452 
 453         // TODO: OK to redeclare with or without same annos
 454     }
 455 
 456     public void testNestedRecords() {
 457         String template = "class R { \n" +
 458                           "    # record RR(int a) { }\n" +
 459                           "}";
 460 
 461         for (String s : List.of("", "static", "final",
 462                                 "private", "public", "protected",
 463                                 "private static", "public static", "private static final"))
 464             assertOK(template, s);
 465 
 466         for (String s : List.of("class C { }",
 467                                 "static class C { }",
 468                                 "enum X { A; }",
 469                                 "interface I { }",
 470                                 "record RR(int y) { }"))
 471             assertOK("record R(int x) { # }", s);
 472     }
 473 
 474     public void testDuplicatedMember() {
 475         String template
 476                 = "    record R(int i) {\n" +
 477                   "        public int i() { return i; }\n" +
 478                   "        public int i() { return i; }\n" +
 479                   "    }";
 480         assertFail("compiler.err.already.defined", template);
 481     }
 482 
 483     public void testStaticLocalTypes() {
 484         // local records can also be final
 485         assertOK("class R { \n" +
 486                 "    void m() { \n" +
 487                 "        final record RR(int x) { };\n" +
 488                 "    }\n" +
 489                 "}");
 490 
 491         // Can't capture locals
 492         assertFail("compiler.err.non-static.cant.be.ref",
 493                 "class R { \n" +
 494                         "    void m(int y) { \n" +
 495                         "        record RR(int x) { public int x() { return y; }};\n" +
 496                         "    }\n" +
 497                         "}");
 498 
 499         assertFail("compiler.err.non-static.cant.be.ref",
 500                 "class R { \n" +
 501                         "    void m() {\n" +
 502                         "        int y;\n" +
 503                         "        record RR(int x) { public int x() { return y; }};\n" +
 504                         "    }\n" +
 505                         "}");
 506 
 507         assertFail("compiler.err.non-static.cant.be.ref",
 508                 "class C {\n" +
 509                 "    public static void m() {\n" +
 510                 "        String hello = \"hello\";\n" +
 511                 "        interface I {\n" +
 512                 "            public default void test1() {\n" +
 513                 "                class X {\n" +
 514                 "                    public void test2() {\n" +
 515                 "                        System.err.println(hello);\n" +
 516                 "                    }\n" +
 517                 "                }\n" +
 518                 "            }\n" +
 519                 "        }\n" +
 520                 "    }\n" +
 521                 "}");
 522 
 523         assertFail("compiler.err.non-static.cant.be.ref",
 524                 "class C {\n" +
 525                 "    public static void m() {\n" +
 526                 "        String hello = \"hello\";\n" +
 527                 "        record R(int i) {\n" +
 528                 "            public void test1() {\n" +
 529                 "                class X {\n" +
 530                 "                    public void test2() {\n" +
 531                 "                        System.err.println(hello);\n" +
 532                 "                    }\n" +
 533                 "                }\n" +
 534                 "            }\n" +
 535                 "        }\n" +
 536                 "    }\n" +
 537                 "}");
 538 
 539         assertFail("compiler.err.non-static.cant.be.ref",
 540                 "class C {\n" +
 541                 "    public static void m() {\n" +
 542                 "        String hello = \"hello\";\n" +
 543                 "        enum E {\n" +
 544                 "            A;\n" +
 545                 "            public void test1() {\n" +
 546                 "                class X {\n" +
 547                 "                    public void test2() {\n" +
 548                 "                        System.err.println(hello);\n" +
 549                 "                    }\n" +
 550                 "                }\n" +
 551                 "            }\n" +
 552                 "        }\n" +
 553                 "    }\n" +
 554                 "}");
 555 
 556         assertFail("compiler.err.non-static.cant.be.ref",
 557                 "class C {\n" +
 558                 "    public static void m(String param) {\n" +
 559                 "        interface I {\n" +
 560                 "            public default void test1() {\n" +
 561                 "                class X {\n" +
 562                 "                    public void test2() {\n" +
 563                 "                        System.err.println(param);\n" +
 564                 "                    }\n" +
 565                 "                }\n" +
 566                 "            }\n" +
 567                 "        }\n" +
 568                 "    }\n" +
 569                 "}");
 570 
 571         assertFail("compiler.err.non-static.cant.be.ref",
 572                 "class C {\n" +
 573                 "    public static void m(String param) {\n" +
 574                 "        record R(int i) {\n" +
 575                 "            public void test1() {\n" +
 576                 "                class X {\n" +
 577                 "                    public void test2() {\n" +
 578                 "                        System.err.println(param);\n" +
 579                 "                    }\n" +
 580                 "                }\n" +
 581                 "            }\n" +
 582                 "        }\n" +
 583                 "    }\n" +
 584                 "}");
 585 
 586         assertFail("compiler.err.non-static.cant.be.ref",
 587                 "class C {\n" +
 588                 "    public static void m(String param) {\n" +
 589                 "        enum E {\n" +
 590                 "            A;\n" +
 591                 "            public void test1() {\n" +
 592                 "                class X {\n" +
 593                 "                    public void test2() {\n" +
 594                 "                        System.err.println(param);\n" +
 595                 "                    }\n" +
 596                 "                }\n" +
 597                 "            }\n" +
 598                 "        }\n" +
 599                 "    }\n" +
 600                 "}");
 601 
 602         assertFail("compiler.err.non-static.cant.be.ref",
 603                 "class C {\n" +
 604                 "    String instanceField = \"instance\";\n" +
 605                 "    public static void m() {\n" +
 606                 "        interface I {\n" +
 607                 "            public default void test1() {\n" +
 608                 "                class X {\n" +
 609                 "                    public void test2() {\n" +
 610                 "                        System.err.println(instanceField);\n" +
 611                 "                    }\n" +
 612                 "                }\n" +
 613                 "            }\n" +
 614                 "        }\n" +
 615                 "    }\n" +
 616                 "}");
 617 
 618         assertFail("compiler.err.non-static.cant.be.ref",
 619                 "class C {\n" +
 620                 "    String instanceField = \"instance\";\n" +
 621                 "    public static void m(String param) {\n" +
 622                 "        record R(int i) {\n" +
 623                 "            public void test1() {\n" +
 624                 "                class X {\n" +
 625                 "                    public void test2() {\n" +
 626                 "                        System.err.println(instanceField);\n" +
 627                 "                    }\n" +
 628                 "                }\n" +
 629                 "            }\n" +
 630                 "        }\n" +
 631                 "    }\n" +
 632                 "}");
 633 
 634         assertFail("compiler.err.non-static.cant.be.ref",
 635                 "class C {\n" +
 636                 "    String instanceField = \"instance\";\n" +
 637                 "    public static void m(String param) {\n" +
 638                 "        enum E {\n" +
 639                 "            A;\n" +
 640                 "            public void test1() {\n" +
 641                 "                class X {\n" +
 642                 "                    public void test2() {\n" +
 643                 "                        System.err.println(instanceField);\n" +
 644                 "                    }\n" +
 645                 "                }\n" +
 646                 "            }\n" +
 647                 "        }\n" +
 648                 "    }\n" +
 649                 "}");
 650 
 651         // instance fields
 652         assertFail("compiler.err.non-static.cant.be.ref",
 653                 "class R { \n" +
 654                         "    int z = 0;\n" +
 655                         "    void m() { \n" +
 656                         "        record RR(int x) { public int x() { return z; }};\n" +
 657                         "    }\n" +
 658                         "}");
 659 
 660         // or type variables
 661         assertFail("compiler.err.non-static.cant.be.ref",
 662                 "class R<T> { \n" +
 663                         "    void m() { \n" +
 664                         "        record RR(T t) {};\n" +
 665                         "    }\n" +
 666                         "}");
 667 
 668         assertFail("compiler.err.non-static.cant.be.ref",
 669                 "class R {\n" +
 670                 "    static <U> U make(U u) { //method is static\n" +
 671                 "        interface Checker {\n" +
 672                 "            void check(U u);\n" +
 673                 "        }\n" +
 674                 "        return null;\n" +
 675                 "    }\n" +
 676                 "}");
 677 
 678         assertFail("compiler.err.non-static.cant.be.ref",
 679                 "class LocalEnum {\n" +
 680                 "    static <U> U getAndSet(U u) { //method is static\n" +
 681                 "        enum X {\n" +
 682                 "            A;\n" +
 683                 "            U u;\n" +
 684                 "        }\n" +
 685                 "        return null;\n" +
 686                 "    }\n" +
 687                 "}\n");
 688 
 689         assertFail("compiler.err.non-static.cant.be.ref",
 690                 "class R {\n" +
 691                 "    static <U> U make(U u) { //method is static\n" +
 692                 "        record Checker() {\n" +
 693                 "            void check(U u);\n" +
 694                 "        }\n" +
 695                 "        return null;\n" +
 696                 "    }\n" +
 697                 "}");
 698 
 699         assertFail("compiler.err.non-static.cant.be.ref",
 700                 "class R {\n" +
 701                 "    <U> U make(U u) { // enclosing method is not static\n" +
 702                 "        interface Checker {\n" +
 703                 "            void check(U u);\n" +
 704                 "        }\n" +
 705                 "        return null;\n" +
 706                 "    }\n" +
 707                 "}");
 708 
 709         assertFail("compiler.err.non-static.cant.be.ref",
 710                 "class LocalEnum {\n" +
 711                 "    <U> U getAndSet(U u) { // enclosing method is not static\n" +
 712                 "        enum X {\n" +
 713                 "            A;\n" +
 714                 "            U u;\n" +
 715                 "        }\n" +
 716                 "        return null;\n" +
 717                 "    }\n" +
 718                 "}\n");
 719 
 720         assertFail("compiler.err.non-static.cant.be.ref",
 721                 "class R {\n" +
 722                 "    <U> U make(U u) { // enclosing method is not static\n" +
 723                 "        record Checker() {\n" +
 724                 "            void check(U u);\n" +
 725                 "        }\n" +
 726                 "        return null;\n" +
 727                 "    }\n" +
 728                 "}");
 729 
 730         assertFail("compiler.err.non-static.cant.be.ref",
 731                 "class C {\n" +
 732                 "    public static <T> void main(String[] args) {\n" +
 733                 "        interface I {\n" +
 734                 "            public default void test1() {\n" +
 735                 "                class X {\n" +
 736                 "                    public void test2() {\n" +
 737                 "                        T t = null;\n" +
 738                 "                    }\n" +
 739                 "                }\n" +
 740                 "            }\n" +
 741                 "        }\n" +
 742                 "    }\n" +
 743                 "}");
 744 
 745         assertFail("compiler.err.non-static.cant.be.ref",
 746                 "class C {\n" +
 747                 "    public static <T> void main(String[] args) {\n" +
 748                 "        record R(int i) {\n" +
 749                 "            public void test1() {\n" +
 750                 "                class X {\n" +
 751                 "                    public void test2() {\n" +
 752                 "                        T t = null;\n" +
 753                 "                    }\n" +
 754                 "                }\n" +
 755                 "            }\n" +
 756                 "        }\n" +
 757                 "    }\n" +
 758                 "}");
 759 
 760         assertFail("compiler.err.non-static.cant.be.ref",
 761                 "class C {\n" +
 762                 "    public static <T> void main(String[] args) {\n" +
 763                 "        enum E {\n" +
 764                 "            A;\n" +
 765                 "            public void test1() {\n" +
 766                 "                class X {\n" +
 767                 "                    public void test2() {\n" +
 768                 "                        T t = null;\n" +
 769                 "                    }\n" +
 770                 "                }\n" +
 771                 "            }\n" +
 772                 "        }\n" +
 773                 "    }\n" +
 774                 "}");
 775 
 776         // but static fields are OK
 777         assertOK("class R { \n" +
 778                 "    static int z = 0;\n" +
 779                 "    void m() { \n" +
 780                 "        record RR(int x) { public int x() { return z; }};\n" +
 781                 "    }\n" +
 782                 "}");
 783         // Can't self-shadow
 784         assertFail("compiler.err.already.defined",
 785                 """
 786                 class R {
 787                     void m() {
 788                         record R(int x) { };
 789                     }
 790                 }
 791                 """
 792         );
 793         // can't be explicitly static
 794         assertFail("compiler.err.illegal.start.of.expr",
 795                 """
 796                 class R {
 797                     void m() {
 798                         static record RR(int x) { };
 799                     }
 800                 }
 801                 """
 802         );
 803 
 804         // positive cases
 805         assertOK(
 806                 """
 807                 import java.security.*;
 808                 class Test {
 809                     static Test newInstance(Object provider) {
 810                         return new Test() {
 811                             private final PrivilegedExceptionAction<KeyStore> action = new PrivilegedExceptionAction<KeyStore>() {
 812                                 public KeyStore run() throws Exception {
 813                                     if (provider == null) {}
 814                                     return null;
 815                                 }
 816                             };
 817                         };
 818                     }
 819                 }
 820                 """
 821         );
 822 
 823         assertOK(
 824                 """
 825                 import java.security.*;
 826                 class Test {
 827                     static Test newInstance(Object provider) {
 828                         return new Test() {
 829                             int m(PrivilegedExceptionAction<KeyStore> a) { return 0; }
 830                             {
 831                                 m(
 832                                     new PrivilegedExceptionAction<KeyStore>() {
 833                                         public KeyStore run() throws Exception {
 834                                             if (provider == null) {}
 835                                             return null;
 836                                         }
 837                                     }
 838                                 );
 839                             }
 840                         };
 841                     }
 842                 }
 843                 """
 844         );
 845     }
 846 
 847     public void testReturnInCanonical_Compact() {
 848         assertFail("compiler.err.invalid.canonical.constructor.in.record", "record R(int x) { # }",
 849                 "public R { return; }");
 850         assertFail("compiler.err.invalid.canonical.constructor.in.record", "record R(int x) { # }",
 851                 "public R { if (i < 0) { return; }}");
 852         assertOK("record R(int x) { public R(int x) { this.x = x; return; } }");
 853         assertOK("record R(int x) { public R { Runnable r = () -> { return; };} }");
 854     }
 855 
 856     public void testArgumentsAreNotFinalInCompact() {
 857         assertOK(
 858                 """
 859                 record R(int x) {
 860                     public R {
 861                         x++;
 862                     }
 863                 }
 864                 """);
 865     }
 866 
 867     public void testNoNativeMethods() {
 868         assertFail("compiler.err.mod.not.allowed.here", "record R(int x) { # }",
 869                 "public native R {}");
 870         assertFail("compiler.err.mod.not.allowed.here", "record R(int x) { # }",
 871                 "public native void m();");
 872     }
 873 
 874     public void testRecordsInsideInner() {
 875         assertFail("compiler.err.static.declaration.not.allowed.in.inner.classes",
 876                 """
 877                 class Outer {
 878                     class Inner {
 879                         record R(int a) {}
 880                     }
 881                 }
 882                 """
 883         );
 884         assertFail("compiler.err.static.declaration.not.allowed.in.inner.classes",
 885                 """
 886                 class Outer {
 887                     public void test() {
 888                         class Inner extends Outer {
 889                             record R(int i) {}
 890                         }
 891                     }
 892                 }
 893                 """);
 894         assertFail("compiler.err.static.declaration.not.allowed.in.inner.classes",
 895                 """
 896                 class Outer {
 897                     Runnable run = new Runnable() {
 898                         record TestRecord(int i) {}
 899                         public void run() {}
 900                     };
 901                 }
 902                 """);
 903         assertFail("compiler.err.static.declaration.not.allowed.in.inner.classes",
 904                 """
 905                 class Outer {
 906                     void m() {
 907                         record A() {
 908                             record B() { }
 909                         }
 910                     }
 911                 }
 912                 """);
 913     }
 914 
 915     public void testReceiverParameter() {
 916         assertFail("compiler.err.receiver.parameter.not.applicable.constructor.toplevel.class",
 917                 """
 918                 record R(int i) {
 919                     public R(R this, int i) {
 920                         this.i = i;
 921                     }
 922                 }
 923                 """);
 924         assertFail("compiler.err.non-static.cant.be.ref",
 925                 """
 926                 class Outer {
 927                     record R(int i) {
 928                         public R(Outer Outer.this, int i) {
 929                             this.i = i;
 930                         }
 931                     }
 932                 }
 933                 """);
 934         assertOK(
 935                 """
 936                 record R(int i) {
 937                     void m(R this) {}
 938                     public int i(R this) { return i; }
 939                 }
 940                 """);
 941     }
 942 
 943     public void testOnlyOneFieldRef() throws Exception {
 944         int numberOfFieldRefs = 0;
 945         File dir = assertOK(true, "record R(int recordComponent) {}");
 946         for (final File fileEntry : dir.listFiles()) {
 947             if (fileEntry.getName().equals("R.class")) {
 948                 ClassFile classFile = ClassFile.read(fileEntry);
 949                 for (CPInfo cpInfo : classFile.constant_pool.entries()) {
 950                     if (cpInfo instanceof ConstantPool.CONSTANT_Fieldref_info) {
 951                         numberOfFieldRefs++;
 952                         ConstantPool.CONSTANT_NameAndType_info nameAndType =
 953                                 (ConstantPool.CONSTANT_NameAndType_info)classFile.constant_pool
 954                                         .get(((ConstantPool.CONSTANT_Fieldref_info)cpInfo).name_and_type_index);
 955                         Assert.check(nameAndType.getName().equals("recordComponent"));
 956                     }
 957                 }
 958             }
 959         }
 960         Assert.check(numberOfFieldRefs == 1);
 961     }
 962 
 963     /*  check that fields are initialized in a canonical constructor in the same declaration order as the corresponding
 964      *  record component
 965      */
 966     public void testCheckInitializationOrderInCompactConstructor() throws Exception {
 967         int putField1 = -1;
 968         int putField2 = -1;
 969         File dir = assertOK(true, "record R(int i, String s) { R {} }");
 970         for (final File fileEntry : dir.listFiles()) {
 971             if (fileEntry.getName().equals("R.class")) {
 972                 ClassFile classFile = ClassFile.read(fileEntry);
 973                 for (Method method : classFile.methods) {
 974                     if (method.getName(classFile.constant_pool).equals("<init>")) {
 975                         Code_attribute code_attribute = (Code_attribute) method.attributes.get("Code");
 976                         for (Instruction instruction : code_attribute.getInstructions()) {
 977                             if (instruction.getMnemonic().equals("putfield")) {
 978                                 if (putField1 != -1 && putField2 != -1) {
 979                                     throw new AssertionError("was expecting only two putfield instructions in this method");
 980                                 }
 981                                 if (putField1 == -1) {
 982                                     putField1 = instruction.getShort(1);
 983                                 } else if (putField2 == -1) {
 984                                     putField2 = instruction.getShort(1);
 985                                 }
 986                             }
 987                         }
 988                         // now we need to check that we are assigning to `i` first and to `s` afterwards
 989                         CONSTANT_Fieldref_info fieldref_info1 = (CONSTANT_Fieldref_info)classFile.constant_pool.get(putField1);
 990                         if (!fieldref_info1.getNameAndTypeInfo().getName().equals("i")) {
 991                             throw new AssertionError("was expecting variable name 'i'");
 992                         }
 993 
 994                         CONSTANT_Fieldref_info fieldref_info2 = (CONSTANT_Fieldref_info)classFile.constant_pool.get(putField2);
 995                         if (!fieldref_info2.getNameAndTypeInfo().getName().equals("s")) {
 996                             throw new AssertionError("was expecting variable name 's'");
 997                         }
 998                     }
 999                 }
1000             }
1001         }
1002     }
1003 
1004     public void testAcceptRecordId() {
1005         String[] previousOptions = getCompileOptions();
1006         String[] testOptions = {/* no options */};
1007         setCompileOptions(testOptions);
1008         assertOKWithWarning("compiler.warn.restricted.type.not.allowed.preview",
1009                 "class R {\n" +
1010                 "    record RR(int i) {\n" +
1011                 "        return null;\n" +
1012                 "    }\n" +
1013                 "    class record {}\n" +
1014                 "}");
1015         setCompileOptions(previousOptions);
1016     }
1017 
1018     public void testAnnos() throws Exception {
1019         String[] previousOptions = getCompileOptions();
1020         String srcTemplate =
1021                 """
1022                     import java.lang.annotation.*;
1023                     @Target({#TARGET})
1024                     @Retention(RetentionPolicy.RUNTIME)
1025                     @interface Anno { }
1026 
1027                     record R(@Anno String s) {}
1028                 """;
1029 
1030         // testing several combinations, adding even more combinations won't add too much value
1031         List<String> annoApplicableTargets = List.of(
1032                 "ElementType.FIELD",
1033                 "ElementType.METHOD",
1034                 "ElementType.PARAMETER",
1035                 "ElementType.RECORD_COMPONENT",
1036                 "ElementType.TYPE_USE",
1037                 "ElementType.TYPE_USE,ElementType.FIELD",
1038                 "ElementType.TYPE_USE,ElementType.METHOD",
1039                 "ElementType.TYPE_USE,ElementType.PARAMETER",
1040                 "ElementType.TYPE_USE,ElementType.RECORD_COMPONENT",
1041                 "ElementType.TYPE_USE,ElementType.FIELD,ElementType.METHOD",
1042                 "ElementType.TYPE_USE,ElementType.FIELD,ElementType.PARAMETER",
1043                 "ElementType.TYPE_USE,ElementType.FIELD,ElementType.RECORD_COMPONENT",
1044                 "ElementType.FIELD,ElementType.TYPE_USE",
1045                 "ElementType.METHOD,ElementType.TYPE_USE",
1046                 "ElementType.PARAMETER,ElementType.TYPE_USE",
1047                 "ElementType.RECORD_COMPONENT,ElementType.TYPE_USE",
1048                 "ElementType.FIELD,ElementType.METHOD,ElementType.TYPE_USE",
1049                 "ElementType.FIELD,ElementType.PARAMETER,ElementType.TYPE_USE",
1050                 "ElementType.FIELD,ElementType.RECORD_COMPONENT,ElementType.TYPE_USE"
1051         );
1052 
1053         String[] generalOptions = {
1054                 "--enable-preview",
1055                 "-source", Integer.toString(Runtime.version().feature()),
1056                 "-processor", Processor.class.getName(),
1057                 "-Atargets="
1058         };
1059 
1060         for (String target : annoApplicableTargets) {
1061             String code = srcTemplate.replaceFirst("#TARGET", target);
1062             String[] testOptions = generalOptions.clone();
1063             testOptions[testOptions.length - 1] = testOptions[testOptions.length - 1] + target;
1064             setCompileOptions(testOptions);
1065 
1066             File dir = assertOK(true, code);
1067 
1068             ClassFile classFile = ClassFile.read(findClassFileOrFail(dir, "R.class"));
1069 
1070             // field first
1071             Assert.check(classFile.fields.length == 1);
1072             Field field = classFile.fields[0];
1073             /* if FIELD is one of the targets then there must be a declaration annotation applied to the field, apart from
1074              * the type annotation
1075              */
1076             if (target.contains("FIELD")) {
1077                 checkAnno(classFile,
1078                         (RuntimeAnnotations_attribute)findAttributeOrFail(
1079                                 field.attributes,
1080                                 RuntimeVisibleAnnotations_attribute.class),
1081                         "Anno");
1082             } else {
1083                 assertAttributeNotPresent(field.attributes, RuntimeVisibleAnnotations_attribute.class);
1084             }
1085 
1086             // lets check now for the type annotation
1087             if (target.contains("TYPE_USE")) {
1088                 checkTypeAnno(
1089                         classFile,
1090                         (RuntimeVisibleTypeAnnotations_attribute)findAttributeOrFail(field.attributes, RuntimeVisibleTypeAnnotations_attribute.class),
1091                         "FIELD",
1092                         "Anno");
1093             } else {
1094                 assertAttributeNotPresent(field.attributes, RuntimeVisibleTypeAnnotations_attribute.class);
1095             }
1096 
1097             // checking for the annotation on the corresponding parameter of the canonical constructor
1098             Method init = findMethodOrFail(classFile, "<init>");
1099             /* if PARAMETER is one of the targets then there must be a declaration annotation applied to the parameter, apart from
1100              * the type annotation
1101              */
1102             if (target.contains("PARAMETER")) {
1103                 checkParameterAnno(classFile,
1104                         (RuntimeVisibleParameterAnnotations_attribute)findAttributeOrFail(
1105                                 init.attributes,
1106                                 RuntimeVisibleParameterAnnotations_attribute.class),
1107                         "Anno");
1108             } else {
1109                 assertAttributeNotPresent(init.attributes, RuntimeVisibleAnnotations_attribute.class);
1110             }
1111             // let's check now for the type annotation
1112             if (target.contains("TYPE_USE")) {
1113                 checkTypeAnno(
1114                         classFile,
1115                         (RuntimeVisibleTypeAnnotations_attribute) findAttributeOrFail(init.attributes, RuntimeVisibleTypeAnnotations_attribute.class),
1116                         "METHOD_FORMAL_PARAMETER", "Anno");
1117             } else {
1118                 assertAttributeNotPresent(init.attributes, RuntimeVisibleTypeAnnotations_attribute.class);
1119             }
1120 
1121             // checking for the annotation in the accessor
1122             Method accessor = findMethodOrFail(classFile, "s");
1123             /* if METHOD is one of the targets then there must be a declaration annotation applied to the accessor, apart from
1124              * the type annotation
1125              */
1126             if (target.contains("METHOD")) {
1127                 checkAnno(classFile,
1128                         (RuntimeAnnotations_attribute)findAttributeOrFail(
1129                                 accessor.attributes,
1130                                 RuntimeVisibleAnnotations_attribute.class),
1131                         "Anno");
1132             } else {
1133                 assertAttributeNotPresent(accessor.attributes, RuntimeVisibleAnnotations_attribute.class);
1134             }
1135             // let's check now for the type annotation
1136             if (target.contains("TYPE_USE")) {
1137                 checkTypeAnno(
1138                         classFile,
1139                         (RuntimeVisibleTypeAnnotations_attribute)findAttributeOrFail(accessor.attributes, RuntimeVisibleTypeAnnotations_attribute.class),
1140                         "METHOD_RETURN", "Anno");
1141             } else {
1142                 assertAttributeNotPresent(accessor.attributes, RuntimeVisibleTypeAnnotations_attribute.class);
1143             }
1144 
1145             // checking for the annotation in the Record attribute
1146             Record_attribute record = (Record_attribute)findAttributeOrFail(classFile.attributes, Record_attribute.class);
1147             Assert.check(record.component_count == 1);
1148             /* if RECORD_COMPONENT is one of the targets then there must be a declaration annotation applied to the
1149              * field, apart from the type annotation
1150              */
1151             if (target.contains("RECORD_COMPONENT")) {
1152                 checkAnno(classFile,
1153                         (RuntimeAnnotations_attribute)findAttributeOrFail(
1154                                 record.component_info_arr[0].attributes,
1155                                 RuntimeVisibleAnnotations_attribute.class),
1156                         "Anno");
1157             } else {
1158                 assertAttributeNotPresent(record.component_info_arr[0].attributes, RuntimeVisibleAnnotations_attribute.class);
1159             }
1160             // lets check now for the type annotation
1161             if (target.contains("TYPE_USE")) {
1162                 checkTypeAnno(
1163                         classFile,
1164                         (RuntimeVisibleTypeAnnotations_attribute)findAttributeOrFail(
1165                                 record.component_info_arr[0].attributes,
1166                                 RuntimeVisibleTypeAnnotations_attribute.class),
1167                         "FIELD", "Anno");
1168             } else {
1169                 assertAttributeNotPresent(record.component_info_arr[0].attributes, RuntimeVisibleTypeAnnotations_attribute.class);
1170             }
1171         }
1172 
1173         // let's reset the default compiler options for other tests
1174         setCompileOptions(previousOptions);
1175     }
1176 
1177     private void checkTypeAnno(ClassFile classFile,
1178                                RuntimeTypeAnnotations_attribute rtAnnos,
1179                                String positionType,
1180                                String annoName) throws Exception {
1181         // containing only one type annotation
1182         Assert.check(rtAnnos.annotations.length == 1);
1183         TypeAnnotation tAnno = (TypeAnnotation)rtAnnos.annotations[0];
1184         Assert.check(tAnno.position.type.toString().equals(positionType));
1185         String annotationName = classFile.constant_pool.getUTF8Value(tAnno.annotation.type_index).toString().substring(1);
1186         Assert.check(annotationName.startsWith(annoName));
1187     }
1188 
1189     private void checkAnno(ClassFile classFile,
1190                            RuntimeAnnotations_attribute rAnnos,
1191                            String annoName) throws Exception {
1192         // containing only one type annotation
1193         Assert.check(rAnnos.annotations.length == 1);
1194         Annotation anno = (Annotation)rAnnos.annotations[0];
1195         String annotationName = classFile.constant_pool.getUTF8Value(anno.type_index).toString().substring(1);
1196         Assert.check(annotationName.startsWith(annoName));
1197     }
1198 
1199     // special case for parameter annotations
1200     private void checkParameterAnno(ClassFile classFile,
1201                            RuntimeVisibleParameterAnnotations_attribute rAnnos,
1202                            String annoName) throws Exception {
1203         // containing only one type annotation
1204         Assert.check(rAnnos.parameter_annotations.length == 1);
1205         Assert.check(rAnnos.parameter_annotations[0].length == 1);
1206         Annotation anno = (Annotation)rAnnos.parameter_annotations[0][0];
1207         String annotationName = classFile.constant_pool.getUTF8Value(anno.type_index).toString().substring(1);
1208         Assert.check(annotationName.startsWith(annoName));
1209     }
1210 
1211     private File findClassFileOrFail(File dir, String name) {
1212         for (final File fileEntry : dir.listFiles()) {
1213             if (fileEntry.getName().equals("R.class")) {
1214                 return fileEntry;
1215             }
1216         }
1217         throw new AssertionError("file not found");
1218     }
1219 
1220     private Method findMethodOrFail(ClassFile classFile, String name) throws Exception {
1221         for (Method method : classFile.methods) {
1222             if (method.getName(classFile.constant_pool).equals(name)) {
1223                 return method;
1224             }
1225         }
1226         throw new AssertionError("method not found");
1227     }
1228 
1229     private Attribute findAttributeOrFail(Attributes attributes, Class<? extends Attribute> attrClass) {
1230         for (Attribute attribute : attributes) {
1231             if (attribute.getClass() == attrClass) {
1232                 return attribute;
1233             }
1234         }
1235         throw new AssertionError("attribute not found");
1236     }
1237 
1238     private void assertAttributeNotPresent(Attributes attributes, Class<? extends Attribute> attrClass) {
1239         for (Attribute attribute : attributes) {
1240             if (attribute.getClass() == attrClass) {
1241                 throw new AssertionError("attribute not expected");
1242             }
1243         }
1244     }
1245 
1246     @SupportedAnnotationTypes("*")
1247     public static final class Processor extends JavacTestingAbstractProcessor {
1248 
1249         String targets;
1250         int numberOfTypeAnnotations;
1251 
1252         @Override
1253         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
1254             targets = processingEnv.getOptions().get("targets");
1255             for (TypeElement te : annotations) {
1256                 if (te.toString().equals("Anno")) {
1257                     checkElements(te, roundEnv, targets);
1258                     if (targets.contains("TYPE_USE")) {
1259                         Element element = processingEnv.getElementUtils().getTypeElement("R");
1260                         numberOfTypeAnnotations = 0;
1261                         checkTypeAnnotations(element);
1262                         Assert.check(numberOfTypeAnnotations == 4);
1263                     }
1264                 }
1265             }
1266             return true;
1267         }
1268 
1269         void checkElements(TypeElement te, RoundEnvironment renv, String targets) {
1270             Set<? extends Element> annoElements = renv.getElementsAnnotatedWith(te);
1271             Set<String> targetSet = new HashSet<>(Arrays.asList(targets.split(",")));
1272             // we will check for type annotation in another method
1273             targetSet.remove("ElementType.TYPE_USE");
1274             for (Element e : annoElements) {
1275                 Symbol s = (Symbol) e;
1276                 switch (s.getKind()) {
1277                     case FIELD:
1278                         Assert.check(targetSet.contains("ElementType.FIELD"));
1279                         targetSet.remove("ElementType.FIELD");
1280                         break;
1281                     case METHOD:
1282                         Assert.check(targetSet.contains("ElementType.METHOD"));
1283                         targetSet.remove("ElementType.METHOD");
1284                         break;
1285                     case PARAMETER:
1286                         Assert.check(targetSet.contains("ElementType.PARAMETER"));
1287                         targetSet.remove("ElementType.PARAMETER");
1288                         break;
1289                     case RECORD_COMPONENT:
1290                         Assert.check(targetSet.contains("ElementType.RECORD_COMPONENT"));
1291                         targetSet.remove("ElementType.RECORD_COMPONENT");
1292                         break;
1293                     default:
1294                         throw new AssertionError("unexpected element kind");
1295                 }
1296             }
1297             Assert.check(targetSet.isEmpty(), targetSet.toString());
1298         }
1299 
1300         private void checkTypeAnnotations(Element rootElement) {
1301             new ElementScanner<Void, Void>() {
1302                 @Override public Void visitVariable(VariableElement e, Void p) {
1303                     Symbol s = (Symbol) e;
1304                     if (s.getKind() == ElementKind.FIELD ||
1305                             s.getKind() == ElementKind.PARAMETER &&
1306                             s.name.toString().equals("s")) {
1307                         int currentTAs = numberOfTypeAnnotations;
1308                         verifyTypeAnnotations(e.asType().getAnnotationMirrors());
1309                         Assert.check(currentTAs + 1 == numberOfTypeAnnotations);
1310                     }
1311                     return null;
1312                 }
1313                 @Override
1314                 public Void visitExecutable(ExecutableElement e, Void p) {
1315                     Symbol s = (Symbol) e;
1316                     if (s.getKind() == ElementKind.METHOD &&
1317                                     s.name.toString().equals("s")) {
1318                         int currentTAs = numberOfTypeAnnotations;
1319                         verifyTypeAnnotations(e.getReturnType().getAnnotationMirrors());
1320                         Assert.check(currentTAs + 1 == numberOfTypeAnnotations);
1321                     }
1322                     scan(e.getParameters(), p);
1323                     return null;
1324                 }
1325                 @Override public Void visitRecordComponent(RecordComponentElement e, Void p) {
1326                     int currentTAs = numberOfTypeAnnotations;
1327                     verifyTypeAnnotations(e.asType().getAnnotationMirrors());
1328                     Assert.check(currentTAs + 1 == numberOfTypeAnnotations);
1329                     return null;
1330                 }
1331             }.scan(rootElement, null);
1332         }
1333 
1334         private void verifyTypeAnnotations(Iterable<? extends AnnotationMirror> annotations) {
1335             for (AnnotationMirror mirror : annotations) {
1336                 Assert.check(mirror.toString().startsWith("@Anno"));
1337                 if (mirror instanceof TypeCompound) {
1338                     numberOfTypeAnnotations++;
1339                 }
1340             }
1341         }
1342     }
1343 
1344     public void testMethodsInheritedFromRecordArePublicAndFinal() throws Exception {
1345         int numberOfFieldRefs = 0;
1346         File dir = assertOK(true, "record R() {}");
1347         for (final File fileEntry : dir.listFiles()) {
1348             if (fileEntry.getName().equals("R.class")) {
1349                 ClassFile classFile = ClassFile.read(fileEntry);
1350                 for (Method method : classFile.methods)
1351                     switch (method.getName(classFile.constant_pool)) {
1352                         case "toString", "equals", "hashCode" ->
1353                             Assert.check(method.access_flags.is(AccessFlags.ACC_PUBLIC) && method.access_flags.is(AccessFlags.ACC_FINAL));
1354                         default -> { /* do nothing */ }
1355                     }
1356             }
1357         }
1358     }
1359 
1360     private static final List<String> ACCESSIBILITY = List.of(
1361             "public", "protected", "", "private");
1362 
1363     public void testCanonicalAccessibility() throws Exception {
1364         // accessibility of canonical can't be stronger than that of the record type
1365         for (String a1 : ACCESSIBILITY) {
1366             for (String a2 : ACCESSIBILITY) {
1367                 if (protection(a2) > protection(a1)) {
1368                     assertFail("compiler.err.invalid.canonical.constructor.in.record", "class R {# record RR() { # RR {} } }", a1, a2);
1369                 } else {
1370                     assertOK("class R {# record RR() { # RR {} } }", a1, a2);
1371                 }
1372             }
1373         }
1374 
1375         // now lets check that when compiler the compiler generates the canonical, it has the same accessibility
1376         // as the record type
1377         for (String a : ACCESSIBILITY) {
1378             File dir = assertOK(true, "class R {# record RR() {} }", a);
1379             for (final File fileEntry : dir.listFiles()) {
1380                 if (fileEntry.getName().equals("R$RR.class")) {
1381                     ClassFile classFile = ClassFile.read(fileEntry);
1382                     for (Method method : classFile.methods)
1383                         if (method.getName(classFile.constant_pool).equals("<init>")) {
1384                             Assert.check(method.access_flags.flags == accessFlag(a),
1385                                     "was expecting access flag " + accessFlag(a) + " but found " + method.access_flags.flags);
1386                         }
1387                 }
1388             }
1389         }
1390     }
1391 
1392     private int protection(String access) {
1393         switch (access) {
1394             case "private": return 3;
1395             case "protected": return 1;
1396             case "public": return 0;
1397             case "": return 2;
1398             default:
1399                 throw new AssertionError();
1400         }
1401     }
1402 
1403     private int accessFlag(String access) {
1404         switch (access) {
1405             case "private": return AccessFlags.ACC_PRIVATE;
1406             case "protected": return AccessFlags.ACC_PROTECTED;
1407             case "public": return AccessFlags.ACC_PUBLIC;
1408             case "": return 0;
1409             default:
1410                 throw new AssertionError();
1411         }
1412     }
1413 
1414     public void testSameArity() {
1415         for (String source : List.of(
1416                 """
1417                 record R(int... args) {
1418                     public R(int... args) {
1419                         this.args = args;
1420                     }
1421                 }
1422                 """,
1423                 """
1424                 record R(int[] args) {
1425                     public R(int[] args) {
1426                         this.args = args;
1427                     }
1428                 }
1429                 """,
1430                 """
1431                 record R(@A int... ints) {}
1432 
1433                 @java.lang.annotation.Target({
1434                         java.lang.annotation.ElementType.TYPE_USE,
1435                         java.lang.annotation.ElementType.RECORD_COMPONENT})
1436                 @interface A {}
1437                 """,
1438                 """
1439                 record R(@A int... ints) {
1440                     R(@A int... ints) {
1441                         this.ints = ints;
1442                     }
1443                 }
1444 
1445                 @java.lang.annotation.Target({
1446                         java.lang.annotation.ElementType.TYPE_USE,
1447                         java.lang.annotation.ElementType.RECORD_COMPONENT})
1448                 @interface A {}
1449                 """
1450         )) {
1451             assertOK(source);
1452         }
1453 
1454         for (String source : List.of(
1455                 """
1456                 record R(int... args) {
1457                     public R(int[] args) {
1458                         this.args = args;
1459                     }
1460                 }
1461                 """,
1462                 """
1463                 record R(int... args) {
1464                     public R(int[] args) {
1465                         this.args = args;
1466                     }
1467                 }
1468                 """,
1469                 """
1470                 record R(String... args) {
1471                     public R(String[] args) {
1472                         this.args = args;
1473                     }
1474                 }
1475                 """,
1476                 """
1477                 record R(String... args) {
1478                     public R(String[] args) {
1479                         this.args = args;
1480                     }
1481                 }
1482                 """
1483         )) {
1484             assertFail("compiler.err.invalid.canonical.constructor.in.record", source);
1485         }
1486     }
1487 
1488     public void testSafeVararsAnno() {
1489         assertFail("compiler.err.annotation.type.not.applicable",
1490                 """
1491                 @SafeVarargs
1492                 record R<T>(T... t) {}
1493                 """,
1494                 """
1495                 @SafeVarargs
1496                 record R<T>(T... t) {
1497                     R(T... t) {
1498                         this.t = t;
1499                     }
1500                 }
1501                 """
1502         );
1503 
1504         assertOK(
1505                 """
1506                 record R<T>(T... t) {
1507                     @SafeVarargs
1508                     R(T... t) {
1509                         this.t = t;
1510                     }
1511                 }
1512                 """
1513         );
1514 
1515         appendCompileOptions("-Xlint:unchecked");
1516         assertOKWithWarning("compiler.warn.unchecked.varargs.non.reifiable.type",
1517                 """
1518                 record R<T>(T... t) {
1519                     R(T... t) {
1520                         this.t = t;
1521                     }
1522                 }
1523                 """
1524         );
1525         removeLastCompileOptions(1);
1526 
1527         assertOK(
1528                 """
1529                 @SuppressWarnings("unchecked")
1530                 record R<T>(T... t) {
1531                     R(T... t) {
1532                         this.t = t;
1533                     }
1534                 }
1535                 """
1536         );
1537 
1538         assertOK(
1539                 """
1540                 record R<T>(T... t) {
1541                     @SuppressWarnings("unchecked")
1542                     R(T... t) {
1543                         this.t = t;
1544                     }
1545                 }
1546                 """
1547         );
1548     }
1549 
1550     public void testOverrideAtAccessor() {
1551         assertOK(
1552                 """
1553                 record R(int i) {
1554                     @Override
1555                     public int i() { return i; }
1556                 }
1557                 """,
1558                 """
1559                 record R(int i, int j) {
1560                     @Override
1561                     public int i() { return i; }
1562                     public int j() { return j; }
1563                 }
1564                 """,
1565                 """
1566                 interface I { int i(); }
1567                 record R(int i) implements I {
1568                     @Override
1569                     public int i() { return i; }
1570                 }
1571                 """,
1572                 """
1573                 interface I { int i(); }
1574                 record R(int i) implements I {
1575                     public int i() { return i; }
1576                 }
1577                 """,
1578                 """
1579                 interface I { default int i() { return 0; } }
1580                 record R(int i) implements I {
1581                     @Override
1582                     public int i() { return i; }
1583                 }
1584                 """
1585         );
1586     }
1587 
1588     public void testNoAssigmentInsideCompactRecord() {
1589         assertFail("compiler.err.cant.assign.val.to.final.var",
1590                 """
1591                 record R(int i) {
1592                     R {
1593                         this.i = i;
1594                     }
1595                 }
1596                 """
1597         );
1598         assertFail("compiler.err.cant.assign.val.to.final.var",
1599                 """
1600                 record R(int i) {
1601                     R {
1602                         (this).i = i;
1603                     }
1604                 }
1605                 """
1606         );
1607     }
1608 
1609     public void testNoNPEStaticAnnotatedFields() {
1610         assertOK(
1611                 """
1612                 import java.lang.annotation.Native;
1613                 record R() {
1614                     @Native public static final int i = 0;
1615                 }
1616                 """
1617         );
1618         assertOK(
1619                 """
1620                 import java.lang.annotation.Native;
1621                 class Outer {
1622                     record R() {
1623                         @Native public static final int i = 0;
1624                     }
1625                 }
1626                 """
1627         );
1628         assertOK(
1629                 """
1630                 import java.lang.annotation.Native;
1631                 class Outer {
1632                     void m() {
1633                         record R () {
1634                             @Native public static final int i = 0;
1635                         }
1636                     }
1637                 }
1638                 """
1639         );
1640     }
1641 
1642     public void testDoNotAllowCStyleArraySyntaxForRecComponents() {
1643         assertFail("compiler.err.record.component.and.old.array.syntax",
1644                 """
1645                 record R(int i[]) {}
1646                 """
1647         );
1648         assertFail("compiler.err.record.component.and.old.array.syntax",
1649                 """
1650                 record R(String s[]) {}
1651                 """
1652         );
1653         assertFail("compiler.err.record.component.and.old.array.syntax",
1654                 """
1655                 record R<T>(T t[]) {}
1656                 """
1657         );
1658     }
1659 }