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 6945418 6993978 8006694 27 * @summary Project Coin: Simplified Varargs Method Invocation 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 Warn4 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.Set; 41 import java.util.HashSet; 42 import javax.tools.Diagnostic; 43 import javax.tools.JavaCompiler; 44 import javax.tools.JavaFileObject; 45 import javax.tools.SimpleJavaFileObject; 46 import javax.tools.ToolProvider; 47 import com.sun.source.util.JavacTask; 48 49 public class Warn4 50 extends JavacTestingAbstractThreadedTest 51 implements Runnable { 52 53 final static Warning[] error = null; 54 final static Warning[] none = new Warning[] {}; 55 final static Warning[] vararg = new Warning[] { Warning.VARARGS }; 56 final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED }; 57 final static Warning[] both = 58 new Warning[] { Warning.VARARGS, Warning.UNCHECKED }; 59 60 enum Warning { 61 UNCHECKED("generic.array.creation"), 62 VARARGS("varargs.non.reifiable.type"); 63 64 String key; 65 66 Warning(String key) { 67 this.key = key; 68 } 69 70 boolean isSuppressed(TrustMe trustMe, SourceLevel source, 71 SuppressLevel suppressLevelClient, 72 SuppressLevel suppressLevelDecl, 73 ModifierKind modKind) { 74 switch(this) { 75 case VARARGS: 76 return source == SourceLevel.JDK_6 || 77 suppressLevelDecl == SuppressLevel.UNCHECKED || 78 trustMe == TrustMe.TRUST; 79 case UNCHECKED: 80 return suppressLevelClient == SuppressLevel.UNCHECKED || 81 (trustMe == TrustMe.TRUST && modKind != 82 ModifierKind.NONE && source == SourceLevel.JDK_7); 83 } 84 85 SuppressLevel supLev = this == VARARGS ? 86 suppressLevelDecl : 87 suppressLevelClient; 88 return supLev == SuppressLevel.UNCHECKED || 89 (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE); 90 } 91 } 92 93 enum SourceLevel { 94 JDK_6("6"), 95 JDK_7("7"); 96 97 String sourceKey; 98 99 SourceLevel(String sourceKey) { 100 this.sourceKey = sourceKey; 101 } 102 } 103 104 enum TrustMe { 105 DONT_TRUST(""), 106 TRUST("@java.lang.SafeVarargs"); 107 108 String anno; 109 110 TrustMe(String anno) { 111 this.anno = anno; 112 } 113 } 114 115 enum ModifierKind { 116 NONE(" "), 117 FINAL("final "), 118 STATIC("static "); 119 120 String mod; 121 122 ModifierKind(String mod) { 123 this.mod = mod; 124 } 125 } 126 127 enum SuppressLevel { 128 NONE(""), 129 UNCHECKED("unchecked"); 130 131 String lint; 132 133 SuppressLevel(String lint) { 134 this.lint = lint; 135 } 136 137 String getSuppressAnno() { 138 return "@SuppressWarnings(\"" + lint + "\")"; 139 } 140 } 141 142 enum Signature { 143 UNBOUND("void #name(List<?>#arity arg) { #body }", 144 new Warning[][] {none, none, none, none, error}), 145 INVARIANT_TVAR("<Z> void #name(List<Z>#arity arg) { #body }", 146 new Warning[][] {both, both, error, both, error}), 147 TVAR("<Z> void #name(Z#arity arg) { #body }", 148 new Warning[][] {both, both, both, both, vararg}), 149 INVARIANT("void #name(List<String>#arity arg) { #body }", 150 new Warning[][] {error, error, error, both, error}), 151 UNPARAMETERIZED("void #name(String#arity arg) { #body }", 152 new Warning[][] {error, error, error, error, none}); 153 154 String template; 155 Warning[][] warnings; 156 157 Signature(String template, Warning[][] warnings) { 158 this.template = template; 159 this.warnings = warnings; 160 } 161 162 boolean isApplicableTo(Signature other) { 163 return warnings[other.ordinal()] != null; 164 } 165 166 boolean giveUnchecked(Signature other) { 167 return warnings[other.ordinal()] == unchecked || 168 warnings[other.ordinal()] == both; 169 } 170 171 boolean giveVarargs(Signature other) { 172 return warnings[other.ordinal()] == vararg || 173 warnings[other.ordinal()] == both; 174 } 175 } 176 177 public static void main(String... args) throws Exception { 178 for (SourceLevel sourceLevel : SourceLevel.values()) { 179 for (TrustMe trustMe : TrustMe.values()) { 180 for (SuppressLevel suppressLevelClient : SuppressLevel.values()) { 181 for (SuppressLevel suppressLevelDecl : SuppressLevel.values()) { 182 for (ModifierKind modKind : ModifierKind.values()) { 183 for (Signature vararg_meth : Signature.values()) { 184 for (Signature client_meth : Signature.values()) { 185 if (vararg_meth.isApplicableTo(client_meth)) { 186 pool.execute(new Warn4(sourceLevel, 187 trustMe, 188 suppressLevelClient, 189 suppressLevelDecl, 190 modKind, 191 vararg_meth, 192 client_meth)); 193 } 194 } 195 } 196 } 197 } 198 } 199 } 200 } 201 202 checkAfterExec(); 203 } 204 205 SourceLevel sourceLevel; 206 TrustMe trustMe; 207 SuppressLevel suppressLevelClient; 208 SuppressLevel suppressLevelDecl; 209 ModifierKind modKind; 210 Signature vararg_meth; 211 Signature client_meth; 212 DiagnosticChecker diagChecker; 213 214 public Warn4(SourceLevel sourceLevel, TrustMe trustMe, 215 SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl, 216 ModifierKind modKind, Signature vararg_meth, Signature client_meth) { 217 this.sourceLevel = sourceLevel; 218 this.trustMe = trustMe; 219 this.suppressLevelClient = suppressLevelClient; 220 this.suppressLevelDecl = suppressLevelDecl; 221 this.modKind = modKind; 222 this.vararg_meth = vararg_meth; 223 this.client_meth = client_meth; 224 this.diagChecker = new DiagnosticChecker(); 225 } 226 227 @Override 228 public void run() { 229 int id = checkCount.incrementAndGet(); 230 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 231 JavaSource source = new JavaSource(id); 232 JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker, 233 Arrays.asList("-Xlint:unchecked", "-source", sourceLevel.sourceKey), 234 null, Arrays.asList(source)); 235 ct.call(); //to get mandatory notes 236 check(source, new boolean[] {vararg_meth.giveUnchecked(client_meth), 237 vararg_meth.giveVarargs(client_meth)}); 238 } 239 240 void check(JavaSource source, boolean[] warnArr) { 241 boolean badOutput = false; 242 for (Warning wkind : Warning.values()) { 243 boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel, 244 suppressLevelClient, suppressLevelDecl, modKind); 245 badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) != 246 diagChecker.warnings.contains(wkind); 247 } 248 if (badOutput) { 249 throw new Error("invalid diagnostics for source:\n" + 250 source.getCharContent(true) + 251 "\nExpected unchecked warning: " + warnArr[0] + 252 "\nExpected unsafe vararg warning: " + warnArr[1] + 253 "\nWarnings: " + diagChecker.warnings + 254 "\nSource level: " + sourceLevel); 255 } 256 } 257 258 class JavaSource extends SimpleJavaFileObject { 259 260 String source; 261 262 public JavaSource(int id) { 263 super(URI.create(String.format("myfo:/Test%d.java", id)), 264 JavaFileObject.Kind.SOURCE); 265 String meth1 = vararg_meth.template.replace("#arity", "..."); 266 meth1 = meth1.replace("#name", "m"); 267 meth1 = meth1.replace("#body", ""); 268 meth1 = trustMe.anno + "\n" + suppressLevelDecl.getSuppressAnno() + 269 modKind.mod + meth1; 270 String meth2 = client_meth.template.replace("#arity", ""); 271 meth2 = meth2.replace("#name", "test"); 272 meth2 = meth2.replace("#body", "m(arg);"); 273 meth2 = suppressLevelClient.getSuppressAnno() + meth2; 274 source = String.format("import java.util.List;\n" + 275 "class Test%s {\n %s \n %s \n } \n", id, meth1, meth2); 276 } 277 278 @Override 279 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 280 return source; 281 } 282 } 283 284 static class DiagnosticChecker 285 implements javax.tools.DiagnosticListener<JavaFileObject> { 286 287 Set<Warning> warnings = new HashSet<>(); 288 289 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 290 if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING || 291 diagnostic.getKind() == Diagnostic.Kind.WARNING) { 292 if (diagnostic.getCode().contains(Warning.VARARGS.key)) { 293 warnings.add(Warning.VARARGS); 294 } else if(diagnostic.getCode().contains(Warning.UNCHECKED.key)) { 295 warnings.add(Warning.UNCHECKED); 296 } 297 } 298 } 299 } 300 301 }