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 8246774 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 * @run main LocalStaticDeclarations 34 */ 35 36 import javax.lang.model.element.Element; 37 import javax.tools.Diagnostic; 38 import javax.tools.JavaFileObject; 39 40 import com.sun.tools.javac.util.Assert; 41 42 import com.sun.tools.javac.api.ClientCodeWrapper; 43 import com.sun.tools.javac.util.JCDiagnostic; 44 import com.sun.tools.javac.util.List; 45 import combo.ComboInstance; 46 import combo.ComboParameter; 47 import combo.ComboTask; 48 import combo.ComboTask.Result; 49 import combo.ComboTestHelper; 50 51 /** this test checks two thinks: 52 * 1 - that static declarations are allowed inside inner classes 53 * 2 - and in addtion that non-static variables can't be captured 54 * by static contexts 55 */ 56 57 public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclarations> { 58 59 static final String sourceTemplate = 60 """ 61 import java.lang.annotation.*; 62 class Test { 63 int INSTANCE_FIELD = 0; 64 static int STATIC_FIELD = 0; 65 // instance initializer 66 { 67 int LOCAL_VARIABLE = 0; 68 #{CONTAINER} 69 } 70 Test() { 71 int LOCAL_VARIABLE = 0; 72 #{CONTAINER} 73 } 74 void m() { 75 int LOCAL_VARIABLE = 0; 76 #{CONTAINER} 77 } 78 static void foo() { 79 int LOCAL_VARIABLE = 0; 80 #{CONTAINER} 81 } 82 } 83 """; 84 85 enum Container implements ComboParameter { 86 NO_CONTAINER("#{STATIC_LOCAL}"), 87 INTERFACE("interface CI { #{STATIC_LOCAL} }"), 88 ANONYMOUS( 89 """ 90 new Object() { 91 // instance initializer 92 { 93 #{STATIC_LOCAL} 94 } 95 96 void m() { 97 #{STATIC_LOCAL} 98 } 99 }; 100 """ 101 ), 102 RECORD("record CR() { #{STATIC_LOCAL} }"), 103 CLASS("class CC { #{STATIC_LOCAL} }"), 104 ENUM("enum CE { CE1; #{STATIC_LOCAL} }"), 105 LAMBDA("Runnable run = () -> { #{STATIC_LOCAL} };"); 106 107 String container; 108 109 Container(String container) { 110 this.container = container; 111 } 112 113 public String expand(String optParameter) { 114 return container; 115 } 116 } 117 118 enum StaticLocalDecl implements ComboParameter { 119 ENUM("enum E { E1; #{MEMBER} }"), 120 RECORD("record R() { #{MEMBER} }"), 121 INTERFACE("interface I { #{MEMBER} }"); 122 123 String localDecl; 124 125 StaticLocalDecl(String localDecl) { 126 this.localDecl = localDecl; 127 } 128 129 public String expand(String optParameter) { 130 return localDecl; 131 } 132 } 133 134 enum Member implements ComboParameter { 135 METHOD("int foo() { return #{EXPR}; }"), 136 DEFAULT_METHOD("default int foo() { return #{EXPR}; }"); 137 138 String member; 139 140 Member(String member) { 141 this.member = member; 142 } 143 144 public String expand(String optParameter) { 145 return member; 146 } 147 } 148 149 enum Expression implements ComboParameter { 150 LITERAL("1"), 151 STATIC_FIELD("STATIC_FIELD"), 152 LOCAL_VARIABLE("LOCAL_VARIABLE"), 153 INSTANCE_FIELD("INSTANCE_FIELD"); 154 155 String expr; 156 157 Expression(String expr) { 158 this.expr = expr; 159 } 160 161 public String expand(String optParameter) { 162 return expr; 163 } 164 } 165 166 public static void main(String... args) throws Exception { 167 new combo.ComboTestHelper<LocalStaticDeclarations>() 168 .withFilter(LocalStaticDeclarations::notTriviallyIncorrect) 169 .withDimension("CONTAINER", (x, t) -> { x.container = t; }, Container.values()) 170 .withDimension("STATIC_LOCAL", (x, t) -> { x.decl = t; }, StaticLocalDecl.values()) 171 .withDimension("MEMBER", (x, t) -> { x.member = t; }, Member.values()) 172 .withDimension("EXPR", (x, expr) -> x.expr = expr, Expression.values()) 173 .run(LocalStaticDeclarations::new); 174 } 175 176 Container container; 177 StaticLocalDecl decl; 178 Member member; 179 Expression expr; 180 181 @Override 182 public void doWork() throws Throwable { 183 newCompilationTask() 184 .withSourceFromTemplate("Test", sourceTemplate) 185 .generate(this::check); 186 } 187 188 boolean notTriviallyIncorrect() { 189 return decl == StaticLocalDecl.INTERFACE && member == Member.DEFAULT_METHOD || 190 decl != StaticLocalDecl.INTERFACE && member == Member.METHOD; 191 } 192 193 void check(ComboTask.Result<Iterable<? extends JavaFileObject>> result) { 194 if (shouldFail()) { 195 Assert.check(result.hasErrors(), "unexpected compilation\n" + result.compilationInfo()); 196 if (!expectedDiagFound(result)) { 197 fail("test failing with unexpected error message\n" + result.compilationInfo()); 198 } 199 } else { 200 Assert.check(!result.hasErrors(), result.compilationInfo()); 201 } 202 } 203 204 boolean shouldFail() { 205 return (expr == Expression.LOCAL_VARIABLE || expr == Expression.INSTANCE_FIELD); 206 } 207 208 boolean acceptableExpr() { 209 return (expr == Expression.LITERAL || expr == Expression.STATIC_FIELD); 210 } 211 212 boolean expectedDiagFound(ComboTask.Result<Iterable<? extends JavaFileObject>> result) { 213 if (expr == Expression.LOCAL_VARIABLE || expr == Expression.INSTANCE_FIELD) { 214 return result.containsKey("compiler.err.non-static.cant.be.ref"); 215 } 216 return false; 217 } 218 }