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