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