1 /* 2 * Copyright (c) 2010, 2013, 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 27 * @summary Project Coin: Annotation to reduce varargs warnings 28 * temporarily workaround combo tests are causing time out in several platforms 29 * @author mcimadamore 30 * @library ../../lib 31 * @build JavacTestingAbstractThreadedTest 32 * @run main/othervm Warn5 33 */ 34 35 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) 36 // see JDK-8006746 37 38 import java.net.URI; 39 import java.util.Arrays; 40 import java.util.EnumSet; 41 import javax.tools.Diagnostic; 42 import javax.tools.JavaCompiler; 43 import javax.tools.JavaFileObject; 44 import javax.tools.SimpleJavaFileObject; 45 import javax.tools.ToolProvider; 46 import com.sun.source.util.JavacTask; 47 48 public class Warn5 49 extends JavacTestingAbstractThreadedTest 50 implements Runnable { 51 52 enum XlintOption { 53 NONE("none"), 54 ALL("all"); 55 56 String opt; 57 58 XlintOption(String opt) { 59 this.opt = opt; 60 } 61 62 String getXlintOption() { 63 return "-Xlint:" + opt; 64 } 65 } 66 67 enum TrustMe { 68 DONT_TRUST(""), 69 TRUST("@java.lang.SafeVarargs"); 70 71 String anno; 72 73 TrustMe(String anno) { 74 this.anno = anno; 75 } 76 } 77 78 enum SuppressLevel { 79 NONE, 80 VARARGS; 81 82 String getSuppressAnno() { 83 return this == VARARGS ? 84 "@SuppressWarnings(\"varargs\")" : 85 ""; 86 } 87 } 88 89 enum ModifierKind { 90 NONE(""), 91 FINAL("final"), 92 STATIC("static"), 93 PRIVATE("private"); 94 95 String mod; 96 97 ModifierKind(String mod) { 98 this.mod = mod; 99 } 100 } 101 102 enum MethodKind { 103 METHOD("void m"), 104 CONSTRUCTOR("Test"); 105 106 String name; 107 108 MethodKind(String name) { 109 this.name = name; 110 } 111 } 112 113 enum SourceLevel { 114 JDK_6("6"), 115 JDK_7("7"), 116 JDK_9("9"); 117 118 String sourceKey; 119 120 SourceLevel(String sourceKey) { 121 this.sourceKey = sourceKey; 122 } 123 } 124 125 enum SignatureKind { 126 VARARGS_X("#K <X>#N(X... x)", false, true), 127 VARARGS_STRING("#K #N(String... x)", true, true), 128 ARRAY_X("#K <X>#N(X[] x)", false, false), 129 ARRAY_STRING("#K #N(String[] x)", true, false); 130 131 String stub; 132 boolean isReifiableArg; 133 boolean isVarargs; 134 135 SignatureKind(String stub, boolean isReifiableArg, boolean isVarargs) { 136 this.stub = stub; 137 this.isReifiableArg = isReifiableArg; 138 this.isVarargs = isVarargs; 139 } 140 141 String getSignature(ModifierKind modKind, MethodKind methKind) { 142 return methKind != MethodKind.CONSTRUCTOR ? 143 stub.replace("#K", modKind.mod).replace("#N", methKind.name) : 144 stub.replace("#K", "").replace("#N", methKind.name); 145 } 146 } 147 148 enum BodyKind { 149 ASSIGN("Object o = x;", true), 150 CAST("Object o = (Object)x;", true), 151 METH("test(x);", true), 152 PRINT("System.out.println(x.toString());", false), 153 ARRAY_ASSIGN("Object[] o = x;", true), 154 ARRAY_CAST("Object[] o = (Object[])x;", true), 155 ARRAY_METH("testArr(x);", true); 156 157 String body; 158 boolean hasAliasing; 159 160 BodyKind(String body, boolean hasAliasing) { 161 this.body = body; 162 this.hasAliasing = hasAliasing; 163 } 164 } 165 166 enum WarningKind { 167 UNSAFE_BODY, 168 UNSAFE_DECL, 169 MALFORMED_SAFEVARARGS, 170 REDUNDANT_SAFEVARARGS; 171 } 172 173 public static void main(String... args) throws Exception { 174 for (SourceLevel sourceLevel : SourceLevel.values()) { 175 for (XlintOption xlint : XlintOption.values()) { 176 for (TrustMe trustMe : TrustMe.values()) { 177 for (SuppressLevel suppressLevel : SuppressLevel.values()) { 178 for (ModifierKind modKind : ModifierKind.values()) { 179 for (MethodKind methKind : MethodKind.values()) { 180 for (SignatureKind sig : SignatureKind.values()) { 181 for (BodyKind body : BodyKind.values()) { 182 pool.execute(new Warn5(sourceLevel, 183 xlint, trustMe, suppressLevel, 184 modKind, methKind, sig, body)); 185 } 186 } 187 } 188 } 189 } 190 } 191 } 192 } 193 194 checkAfterExec(false); 195 } 196 197 final SourceLevel sourceLevel; 198 final XlintOption xlint; 199 final TrustMe trustMe; 200 final SuppressLevel suppressLevel; 201 final ModifierKind modKind; 202 final MethodKind methKind; 203 final SignatureKind sig; 204 final BodyKind body; 205 final JavaSource source; 206 final DiagnosticChecker dc; 207 208 public Warn5(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, 209 SuppressLevel suppressLevel, ModifierKind modKind, 210 MethodKind methKind, SignatureKind sig, BodyKind body) { 211 this.sourceLevel = sourceLevel; 212 this.xlint = xlint; 213 this.trustMe = trustMe; 214 this.suppressLevel = suppressLevel; 215 this.modKind = modKind; 216 this.methKind = methKind; 217 this.sig = sig; 218 this.body = body; 219 this.source = new JavaSource(); 220 this.dc = new DiagnosticChecker(); 221 } 222 223 @Override 224 public void run() { 225 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 226 JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), dc, 227 Arrays.asList(xlint.getXlintOption(), 228 "-source", sourceLevel.sourceKey), 229 null, Arrays.asList(source)); 230 try { 231 ct.analyze(); 232 } catch (Throwable t) { 233 processException(t); 234 } 235 check(); 236 } 237 238 void check() { 239 240 EnumSet<WarningKind> expectedWarnings = 241 EnumSet.noneOf(WarningKind.class); 242 243 if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 && 244 trustMe == TrustMe.TRUST && 245 suppressLevel != SuppressLevel.VARARGS && 246 xlint != XlintOption.NONE && 247 sig.isVarargs && 248 !sig.isReifiableArg && 249 body.hasAliasing && 250 (methKind == MethodKind.CONSTRUCTOR || 251 (methKind == MethodKind.METHOD && 252 modKind == ModifierKind.FINAL || modKind == ModifierKind.STATIC || 253 (modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_9) >= 0)))) { 254 expectedWarnings.add(WarningKind.UNSAFE_BODY); 255 } 256 257 if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 && 258 trustMe == TrustMe.DONT_TRUST && 259 sig.isVarargs && 260 !sig.isReifiableArg && 261 xlint == XlintOption.ALL) { 262 expectedWarnings.add(WarningKind.UNSAFE_DECL); 263 } 264 265 if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 && 266 trustMe == TrustMe.TRUST && 267 (!sig.isVarargs || 268 ((modKind == ModifierKind.NONE || 269 modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_9) < 0 ) && 270 methKind == MethodKind.METHOD))) { 271 expectedWarnings.add(WarningKind.MALFORMED_SAFEVARARGS); 272 } 273 274 if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 && 275 trustMe == TrustMe.TRUST && 276 xlint != XlintOption.NONE && 277 suppressLevel != SuppressLevel.VARARGS && 278 (modKind == ModifierKind.FINAL || modKind == ModifierKind.STATIC || 279 (modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_9) >= 0) || 280 methKind == MethodKind.CONSTRUCTOR) && 281 sig.isVarargs && 282 sig.isReifiableArg) { 283 expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS); 284 } 285 286 if (!expectedWarnings.containsAll(dc.warnings) || 287 !dc.warnings.containsAll(expectedWarnings)) { 288 throw new Error("invalid diagnostics for source:\n" + 289 source.getCharContent(true) + 290 "\nOptions: " + xlint.getXlintOption() + 291 "\nSource Level: " + sourceLevel + 292 "\nExpected warnings: " + expectedWarnings + 293 "\nFound warnings: " + dc.warnings); 294 } 295 } 296 297 class JavaSource extends SimpleJavaFileObject { 298 299 String template = "import com.sun.tools.javac.api.*;\n" + 300 "import java.util.List;\n" + 301 "class Test {\n" + 302 " static void test(Object o) {}\n" + 303 " static void testArr(Object[] o) {}\n" + 304 " #T \n #S #M { #B }\n" + 305 "}\n"; 306 307 String source; 308 309 public JavaSource() { 310 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 311 source = template.replace("#T", trustMe.anno). 312 replace("#S", suppressLevel.getSuppressAnno()). 313 replace("#M", sig.getSignature(modKind, methKind)). 314 replace("#B", body.body); 315 } 316 317 @Override 318 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 319 return source; 320 } 321 } 322 323 class DiagnosticChecker 324 implements javax.tools.DiagnosticListener<JavaFileObject> { 325 326 EnumSet<WarningKind> warnings = EnumSet.noneOf(WarningKind.class); 327 328 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 329 if (diagnostic.getKind() == Diagnostic.Kind.WARNING) { 330 if (diagnostic.getCode(). 331 contains("unsafe.use.varargs.param")) { 332 setWarning(WarningKind.UNSAFE_BODY); 333 } else if (diagnostic.getCode(). 334 contains("redundant.trustme")) { 335 setWarning(WarningKind.REDUNDANT_SAFEVARARGS); 336 } 337 } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING && 338 diagnostic.getCode(). 339 contains("varargs.non.reifiable.type")) { 340 setWarning(WarningKind.UNSAFE_DECL); 341 } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR && 342 diagnostic.getCode().contains("invalid.trustme")) { 343 setWarning(WarningKind.MALFORMED_SAFEVARARGS); 344 } 345 } 346 347 void setWarning(WarningKind wk) { 348 if (!warnings.add(wk)) { 349 throw new AssertionError("Duplicate warning of kind " + 350 wk + " in source:\n" + source); 351 } 352 } 353 354 boolean hasWarning(WarningKind wk) { 355 return warnings.contains(wk); 356 } 357 } 358 359 }