1 /*
   2  * Copyright (c) 2017, 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 check that records are always static
  27  * @library /tools/javac/lib
  28  * @modules jdk.compiler/com.sun.source.util
  29  *          jdk.compiler/com.sun.tools.javac.api
  30  *          jdk.compiler/com.sun.tools.javac.code
  31  *          jdk.compiler/com.sun.tools.javac.file
  32  *          jdk.compiler/com.sun.tools.javac.tree
  33  *          jdk.compiler/com.sun.tools.javac.util
  34  * @build DPrinter
  35  * @run main NestedRecordsMustBeStaticAndFinalTest
  36  */
  37 
  38 import java.io.*;
  39 import java.net.URI;
  40 import java.util.Arrays;
  41 
  42 import javax.tools.JavaCompiler;
  43 import javax.tools.JavaFileObject;
  44 import javax.tools.SimpleJavaFileObject;
  45 import javax.tools.ToolProvider;
  46 
  47 import com.sun.source.tree.CompilationUnitTree;
  48 import com.sun.source.util.JavacTask;
  49 import com.sun.source.util.Trees;
  50 import com.sun.tools.javac.api.JavacTrees;
  51 import com.sun.tools.javac.file.JavacFileManager;
  52 import com.sun.tools.javac.tree.JCTree;
  53 import com.sun.tools.javac.util.Assert;
  54 import com.sun.tools.javac.util.Context;
  55 
  56 public class NestedRecordsMustBeStaticAndFinalTest {
  57     public static void main(String... args) throws Exception {
  58         new NestedRecordsMustBeStaticAndFinalTest().run();
  59     }
  60 
  61     void run() throws Exception {
  62         Context context = new Context();
  63         JavacFileManager.preRegister(context);
  64         Trees trees = JavacTrees.instance(context);
  65         strOut = new StringWriter();
  66         PrintWriter pw = new PrintWriter(strOut);
  67         dprinter = new DPrinter(pw, trees);
  68         tool = ToolProvider.getSystemJavaCompiler();
  69         test("Foo.java", source1);
  70         test("Foo2.java", source11);
  71         test("Foo3.java", source111);
  72         test("Bar.java", source2);
  73         test("Bar2.java", source3);
  74         test("Baz.java", source4);
  75     }
  76 
  77     StringWriter strOut;
  78     DPrinter dprinter;
  79     JavaCompiler tool;
  80 
  81     void test(String fileName, String source) throws Exception {
  82         JavacTask ct = (JavacTask)tool.getTask(null, null, null, null, null, Arrays.asList(new JavaSource(fileName, source)));
  83         Iterable<? extends CompilationUnitTree> elements = ct.parse();
  84         Assert.check(elements.iterator().hasNext());
  85         dprinter.treeTypes(true).printTree("", (JCTree)elements.iterator().next());
  86         String output = strOut.toString();
  87         Assert.check(output.contains("flags: [static, final, record]"), "nested records should be static and final");
  88     }
  89 
  90     static final String source1 =
  91             "class Foo {\n" +
  92             "    record R (int x);\n" +
  93             "}";
  94 
  95     static final String source11 =
  96             "class Foo2 {\n" +
  97             "    class Inner {\n" +
  98             "        record R (int x);\n" +
  99             "    }\n" +
 100             "}";
 101     static final String source111 =
 102             "class Foo3 {\n" +
 103             "    Runnable r = new Runnable() {\n" +
 104             "        record R(int i);\n" +
 105             "        public void run() {}\n" +
 106             "    };" +
 107             "}";
 108     static final String source2 =
 109             "class Bar {\n" +
 110             "    void m() {\n" +
 111             "        record R (int x);\n" +
 112             "    }\n" +
 113             "}";
 114 
 115     static final String source3 =
 116             "class Bar2 {\n" +
 117             "    void m() {\n" +
 118             "        static record R (int x);\n" +
 119             "    }\n" +
 120             "}";
 121 
 122     static final String source4 =
 123             "class Baz {\n" +
 124             "    void m() {\n" +
 125             "        Runnable r = () -> {" +
 126             "            record R (int x);\n" +
 127             "        };\n" +
 128             "    }\n" +
 129             "}";
 130 
 131     static class JavaSource extends SimpleJavaFileObject {
 132 
 133         String source;
 134 
 135         public JavaSource(String fileName, String source) {
 136             super(URI.create("myfo:/" + fileName), JavaFileObject.Kind.SOURCE);
 137             this.source = source;
 138         }
 139 
 140         @Override
 141         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
 142             return source;
 143         }
 144     }
 145 }