1 /*
2  * Copyright (c) 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 8242293
27  * @summary allow for local interfaces and enums plus nested records, interfaces and enums
28  * @library /tools/javac/lib
29  * @modules jdk.compiler/com.sun.tools.javac.api
30  *          jdk.compiler/com.sun.tools.javac.file
31  *          jdk.compiler/com.sun.tools.javac.util
32  * @build combo.ComboTestHelper
33  * @compile --enable-preview -source ${jdk.version} LocalStaticDeclarations.java
34  * @run main/othervm --enable-preview LocalStaticDeclarations
35  */
36 
37 import javax.lang.model.element.Element;
38 import javax.tools.Diagnostic;
39 import javax.tools.JavaFileObject;
40 
41 import com.sun.tools.javac.util.Assert;
42 
43 import com.sun.tools.javac.api.ClientCodeWrapper;
44 import com.sun.tools.javac.util.JCDiagnostic;
45 import com.sun.tools.javac.util.List;
46 import combo.ComboInstance;
47 import combo.ComboParameter;
48 import combo.ComboTask;
49 import combo.ComboTask.Result;
50 import combo.ComboTestHelper;
51 
52 public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclarations> {
53 
54     static final String sourceTemplate =
55             """
56             import java.lang.annotation.*;
57             class Test {
58                 int INSTANCE_FIELD = 0;
59                 static int STATIC_FIELD = 0;
60                 // instance initializer
61                 { int LOCAL_VARIABLE = 0;
62                     #{CONTAINER}
63                 }
64                 Test() {
65                     #{CONTAINER}
66                 }
67                 void m() {
68                     int LOCAL_VARIABLE = 0;
69                     #{CONTAINER}
70                 }
71                 static void foo() {
72                     int LOCAL_VARIABLE = 0;
73                     #{CONTAINER}
74                 }
75             }
76             """;
77 
78     enum Container implements ComboParameter {
79         NO_CONTAINER("#{STATIC_LOCAL}"),
80         INTERFACE("interface CI { #{STATIC_LOCAL} }"),
81         ANNOTATION("@interface CA { #{STATIC_LOCAL} }"),
82         ANONYMOUS(
83                 """
84                     new Object() {
85                         // instance initializer
86                         {
87                             #{STATIC_LOCAL}
88                         }
89 
90                         void m() {
91                             #{STATIC_LOCAL}
92                         }
93                     };
94                 """
95         ),
96         RECORD("record CR() { #{STATIC_LOCAL} }"),
97         CLASS("class CC { #{STATIC_LOCAL} }"),
98         ENUM("enum CE { #{STATIC_LOCAL} }"),
99         LAMBDA("Runnable run = () -> { #{STATIC_LOCAL} };");
100 
101         String container;
102 
Container(String container)103         Container(String container) {
104             this.container = container;
105         }
106 
expand(String optParameter)107         public String expand(String optParameter) {
108             return container;
109         }
110     }
111 
112     enum StaticLocalDecl implements ComboParameter {
113         ENUM("enum E { E1; #{MEMBER} }"),
114         RECORD("record R() { #{MEMBER} }"),
115         ANNOTATION("@interface A { #{MEMBER} }"),
116         INTERFACE("interface I { #{MEMBER} }");
117 
118         String localDecl;
119 
StaticLocalDecl(String localDecl)120         StaticLocalDecl(String localDecl) {
121             this.localDecl = localDecl;
122         }
123 
expand(String optParameter)124         public String expand(String optParameter) {
125             return localDecl;
126         }
127     }
128 
129     enum Member implements ComboParameter {
130         NONE(""),
131         METHOD("int foo() { return #{EXPR}; }"),
132         DEFAULT_METHOD("default int foo() { return #{EXPR}; }");
133 
134         String member;
135 
Member(String member)136         Member(String member) {
137             this.member = member;
138         }
139 
expand(String optParameter)140         public String expand(String optParameter) {
141             return member;
142         }
143     }
144 
145     enum Expression implements ComboParameter {
146          LITERAL("1"),
147          STATIC_FIELD("STATIC_FIELD"),
148          LOCAL_VARIABLE("LOCAL_VARIABLE"),
149          INSTANCE_FIELD("INSTANCE_FIELD");
150 
151          String expr;
152 
Expression(String expr)153          Expression(String expr) {
154              this.expr = expr;
155          }
156 
expand(String optParameter)157         public String expand(String optParameter) {
158             return expr;
159         }
160     }
161 
main(String... args)162     public static void main(String... args) throws Exception {
163         new combo.ComboTestHelper<LocalStaticDeclarations>()
164                 .withFilter(LocalStaticDeclarations::notTriviallyIncorrect)
165                 .withDimension("CONTAINER", (x, t) -> { x.container = t; }, Container.values())
166                 .withDimension("STATIC_LOCAL", (x, t) -> { x.decl = t; }, StaticLocalDecl.values())
167                 .withDimension("MEMBER", (x, t) -> { x.member = t; }, Member.values())
168                 .withDimension("EXPR", (x, expr) -> x.expr = expr, Expression.values())
169                 .run(LocalStaticDeclarations::new);
170     }
171 
172     Container container;
173     StaticLocalDecl decl;
174     Member member;
175     Expression expr;
176 
177     @Override
doWork()178     public void doWork() throws Throwable {
179         newCompilationTask()
180                 .withOptions(new String[]{"--enable-preview", "-source", Integer.toString(Runtime.version().feature())})
181                 .withSourceFromTemplate("Test", sourceTemplate)
182                 .generate(this::check);
183     }
184 
notTriviallyIncorrect()185     boolean notTriviallyIncorrect() {
186         return decl == StaticLocalDecl.INTERFACE && (member == Member.DEFAULT_METHOD || member == Member.NONE) ||
187                decl != StaticLocalDecl.INTERFACE && (member == Member.METHOD || member == Member.NONE) &&
188                ((decl != StaticLocalDecl.ANNOTATION) ||
189                (decl == StaticLocalDecl.ANNOTATION && member == Member.NONE));
190     }
191 
check(ComboTask.Result<Iterable<? extends JavaFileObject>> result)192     void check(ComboTask.Result<Iterable<? extends JavaFileObject>> result) {
193         if (shouldFail()) {
194             Assert.check(result.hasErrors(), result.compilationInfo());
195             if (!expectedDiagFound(result)) {
196                 fail("test failing with unexpected error message\n" + result.compilationInfo());
197             }
198         } else {
199             Assert.check(!result.hasErrors(), result.compilationInfo());
200         }
201     }
202 
shouldFail()203     boolean shouldFail() {
204         return ((container != Container.NO_CONTAINER &&
205                 container != Container.LAMBDA &&
206                 container != Container.ANONYMOUS)) ||
207                 (member != Member.NONE && !acceptableExpr());
208     }
209 
acceptableExpr()210     boolean acceptableExpr() {
211         return (expr == Expression.LITERAL || expr == Expression.STATIC_FIELD);
212     }
213 
expectedDiagFound(ComboTask.Result<Iterable<? extends JavaFileObject>> result)214     boolean expectedDiagFound(ComboTask.Result<Iterable<? extends JavaFileObject>> result) {
215         if ((container == Container.NO_CONTAINER ||
216                 container == Container.LAMBDA ||
217                 container == Container.ANONYMOUS) &&
218                 !acceptableExpr()) {
219             return result.containsKey("compiler.err.non-static.cant.be.ref");
220         } else if (container == Container.ENUM) {
221             if (decl == StaticLocalDecl.ANNOTATION) {
222                 return result.containsKey("compiler.err.expected");
223             } else {
224                 return result.containsKey("compiler.err.enum.constant.expected" );
225             }
226         }
227         return result.containsKey("compiler.err.static.declaration.not.allowed.in.inner.classes" );
228     }
229 }
230