1 /* 2 * Copyright (c) 2010, 2022, 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 6993978 7097436 8006694 7196160 27 * @summary Project Coin: Annotation to reduce varargs warnings 28 * temporarily workaround combo tests are causing time out in several platforms 29 * @library /tools/javac/lib 30 * @modules jdk.compiler/com.sun.tools.javac.api 31 * jdk.compiler/com.sun.tools.javac.file 32 * jdk.compiler/com.sun.tools.javac.util 33 * @build combo.ComboTestHelper 34 * @run main/othervm Warn5 35 */ 36 37 import java.io.IOException; 38 import java.util.EnumSet; 39 import javax.tools.Diagnostic; 40 import javax.tools.Diagnostic.Kind; 41 import javax.tools.JavaFileObject; 42 43 import combo.ComboInstance; 44 import combo.ComboParameter; 45 import combo.ComboTask.Result; 46 import combo.ComboTestHelper; 47 48 49 public class Warn5 extends ComboInstance<Warn5> { 50 51 enum XlintOption { 52 NONE("none"), 53 ALL("all"); 54 55 String opt; 56 57 XlintOption(String opt) { 58 this.opt = opt; 59 } 60 61 String getXlintOption() { 62 return "-Xlint:" + opt; 63 } 64 } 65 66 enum TrustMe implements ComboParameter { 67 DONT_TRUST(""), 68 TRUST("@java.lang.SafeVarargs"); 69 70 String anno; 71 72 TrustMe(String anno) { 73 this.anno = anno; 74 } 75 76 @Override 77 public String expand(String optParameter) { 78 return anno; 79 } 80 } 81 82 enum SuppressLevel implements ComboParameter { 83 NONE, 84 VARARGS; 85 86 @Override 87 public String expand(String optParameter) { 88 return this == VARARGS ? 89 "@SuppressWarnings(\"varargs\")" : 90 ""; 91 } 92 } 93 94 enum ModifierKind implements ComboParameter { 95 NONE(""), 96 FINAL("final"), 97 STATIC("static"), 98 PRIVATE("private"); 99 100 String mod; 101 102 ModifierKind(String mod) { 103 this.mod = mod; 104 } 105 106 @Override 107 public String expand(String optParameter) { 108 return mod; 109 } 110 } 111 112 enum MethodKind implements ComboParameter { 113 METHOD("void m"), 114 CONSTRUCTOR("Test"); 115 116 String name; 117 118 MethodKind(String name) { 119 this.name = name; 120 } 121 122 @Override 123 public String expand(String optParameter) { 124 return name; 125 } 126 } 127 128 // Handling of varargs warnings changed in JDK 9 compared to JDK 8 129 // and then remained consistent; test 8 and then current release. 130 enum SourceLevel { 131 JDK_8("8"), 132 LATEST(Integer.toString(javax.lang.model.SourceVersion.latest().runtimeVersion().feature())); 133 134 String sourceKey; 135 136 SourceLevel(String sourceKey) { 137 this.sourceKey = sourceKey; 138 } 139 } 140 141 enum SignatureKind implements ComboParameter { 142 VARARGS_X("<X>#{NAME}(X... x)", false, true), 143 VARARGS_STRING("#{NAME}(String... x)", true, true), 144 ARRAY_X("<X>#{NAME}(X[] x)", false, false), 145 ARRAY_STRING("#{NAME}(String[] x)", true, false); 146 147 String stub; 148 boolean isReifiableArg; 149 boolean isVarargs; 150 151 SignatureKind(String stub, boolean isReifiableArg, boolean isVarargs) { 152 this.stub = stub; 153 this.isReifiableArg = isReifiableArg; 154 this.isVarargs = isVarargs; 155 } 156 157 @Override 158 public String expand(String optParameter) { 159 return stub; 160 } 161 } 162 163 // javac does not currently perform analysis of the method body 164 // with respect to the validity of the @SafeVargs annotation. If 165 // that changes, the body tests should be expanded. 166 enum BodyKind implements ComboParameter { 167 // ASSIGN("Object o = x;", true), 168 // CAST("Object o = (Object)x;", true), 169 METH("test(x);", true), 170 PRINT("System.out.println(x.toString());", false), 171 // ARRAY_ASSIGN("Object[] o = x;", true), 172 ARRAY_CAST("Object[] o = (Object[])x;", true), 173 ARRAY_METH("testArr(x);", true); 174 175 String body; 176 boolean hasAliasing; 177 178 BodyKind(String body, boolean hasAliasing) { 179 this.body = body; 180 this.hasAliasing = hasAliasing; 181 } 182 183 @Override 184 public String expand(String optParameter) { 185 return body; 186 } 187 } 188 189 enum WarningKind { 190 UNSAFE_BODY("compiler.warn.varargs.unsafe.use.varargs.param"), 191 UNSAFE_DECL("compiler.warn.unchecked.varargs.non.reifiable.type"), 192 MALFORMED_SAFEVARARGS("compiler.err.varargs.invalid.trustme.anno"), 193 REDUNDANT_SAFEVARARGS("compiler.warn.varargs.redundant.trustme.anno"); 194 195 String code; 196 197 WarningKind(String code) { 198 this.code = code; 199 } 200 } 201 202 public static void main(String[] args) { 203 new ComboTestHelper<Warn5>() 204 .withFilter(Warn5::badTestFilter) 205 .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values()) 206 .withDimension("LINT", (x, lint) -> x.xlint = lint, XlintOption.values()) 207 .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values()) 208 .withDimension("SUPPRESS", (x, suppress) -> x.suppressLevel = suppress, SuppressLevel.values()) 209 .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values()) 210 .withDimension("NAME", (x, name) -> x.methKind = name, MethodKind.values()) 211 .withDimension("SIG", (x, sig) -> x.sig = sig, SignatureKind.values()) 212 .withDimension("BODY", (x, body) -> x.body = body, BodyKind.values()) 213 .run(Warn5::new); 214 } 215 216 SourceLevel sourceLevel; 217 XlintOption xlint; 218 TrustMe trustMe; 219 SuppressLevel suppressLevel; 220 ModifierKind modKind; 221 MethodKind methKind; 222 SignatureKind sig; 223 BodyKind body; 224 225 boolean badTestFilter() { 226 return (methKind != MethodKind.CONSTRUCTOR || modKind == ModifierKind.NONE); 227 } 228 229 String template = """ 230 import com.sun.tols.javac.api.*; 231 import java.util.List; 232 class Test { 233 static void test(Object o) {} 234 static void testArr(Object[] o) {} 235 #{TRUSTME} #{SUPPRESS} #{MOD} #{SIG} { #{BODY} } 236 } 237 """; 238 239 @Override 240 public void doWork() throws IOException { 241 newCompilationTask() 242 .withOption(xlint.getXlintOption()) 243 .withOption("--release") 244 .withOption(sourceLevel.sourceKey) 245 .withSourceFromTemplate(template) 246 .analyze(this::check); 247 } 248 249 void check(Result<?> res) { 250 251 EnumSet<WarningKind> foundWarnings = EnumSet.noneOf(WarningKind.class); 252 for (Diagnostic.Kind kind : new Kind[] { Kind.ERROR, Kind.MANDATORY_WARNING, Kind.WARNING}) { 253 for (Diagnostic<? extends JavaFileObject> diag : res.diagnosticsForKind(kind)) { 254 for (WarningKind wk : WarningKind.values()) { 255 if (wk.code.equals(diag.getCode())) { 256 foundWarnings.add(wk); 257 } 258 } 259 } 260 } 261 262 EnumSet<WarningKind> expectedWarnings = 263 EnumSet.noneOf(WarningKind.class); 264 265 if (trustMe == TrustMe.TRUST && 266 suppressLevel != SuppressLevel.VARARGS && 267 xlint != XlintOption.NONE && 268 sig.isVarargs && 269 !sig.isReifiableArg && 270 body.hasAliasing && 271 (methKind == MethodKind.CONSTRUCTOR || 272 (methKind == MethodKind.METHOD && 273 modKind == ModifierKind.FINAL || modKind == ModifierKind.STATIC || 274 (modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_8) > 0)))) { 275 expectedWarnings.add(WarningKind.UNSAFE_BODY); 276 } 277 278 if (trustMe == TrustMe.DONT_TRUST && 279 sig.isVarargs && 280 !sig.isReifiableArg && 281 xlint == XlintOption.ALL) { 282 expectedWarnings.add(WarningKind.UNSAFE_DECL); 283 } 284 285 if (trustMe == TrustMe.TRUST && 286 (!sig.isVarargs || 287 ((modKind == ModifierKind.NONE || 288 modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_8) <= 0 ) && 289 methKind == MethodKind.METHOD))) { 290 expectedWarnings.add(WarningKind.MALFORMED_SAFEVARARGS); 291 } 292 293 if (trustMe == TrustMe.TRUST && 294 xlint != XlintOption.NONE && 295 suppressLevel != SuppressLevel.VARARGS && 296 (modKind == ModifierKind.FINAL || modKind == ModifierKind.STATIC || 297 (modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_8) > 0) || 298 methKind == MethodKind.CONSTRUCTOR) && 299 sig.isVarargs && 300 sig.isReifiableArg) { 301 expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS); 302 } 303 304 if (!expectedWarnings.containsAll(foundWarnings) || 305 !foundWarnings.containsAll(expectedWarnings)) { 306 fail("invalid diagnostics for source:\n" + 307 res.compilationInfo() + 308 "\nOptions: " + xlint.getXlintOption() + 309 "\nSource Level: " + sourceLevel + 310 "\nExpected warnings: " + expectedWarnings + 311 "\nFound warnings: " + foundWarnings); 312 } 313 } 314 }