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 6945418 6993978 8006694 7196160 8129962 27 * @summary Project Coin: Simplified Varargs Method Invocation 28 * temporarily workaround combo tests are causing time out in several platforms 29 * @enablePreview 30 * @library /tools/javac/lib 31 * @modules jdk.compiler/com.sun.tools.javac.api 32 * jdk.compiler/com.sun.tools.javac.file 33 * jdk.compiler/com.sun.tools.javac.util 34 * @build combo.ComboTestHelper 35 * @run main Warn4 36 */ 37 38 import java.io.IOException; 39 import java.util.Set; 40 import java.util.HashSet; 41 import javax.tools.Diagnostic; 42 import javax.tools.Diagnostic.Kind; 43 import javax.tools.JavaFileObject; 44 45 import combo.ComboInstance; 46 import combo.ComboParameter; 47 import combo.ComboTask.Result; 48 import combo.ComboTestHelper; 49 50 public class Warn4 extends ComboInstance<Warn4> { 51 52 final static Warning[] error = null; 53 final static Warning[] none = new Warning[] {}; 54 final static Warning[] vararg = new Warning[] { Warning.VARARGS }; 55 final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED }; 56 final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED }; 57 58 enum Warning { 59 UNCHECKED("generic.array.creation"), 60 VARARGS("varargs.non.reifiable.type"); 61 62 String key; 63 64 Warning(String key) { 65 this.key = key; 66 } 67 68 boolean isSuppressed(TrustMe trustMe, SourceLevel source, 69 SuppressLevel suppressLevelClient, 70 SuppressLevel suppressLevelDecl, 71 ModifierKind modKind) { 72 switch(this) { 73 case VARARGS: 74 return suppressLevelDecl == SuppressLevel.UNCHECKED || 75 trustMe == TrustMe.TRUST; 76 case UNCHECKED: 77 return suppressLevelClient == SuppressLevel.UNCHECKED || 78 (trustMe == TrustMe.TRUST && 79 (((modKind == ModifierKind.FINAL || modKind == ModifierKind.STATIC) ) || 80 (modKind == ModifierKind.PRIVATE && source.compareTo( SourceLevel.JDK_9) >= 0 ))); 81 } 82 83 SuppressLevel supLev = this == VARARGS ? 84 suppressLevelDecl : 85 suppressLevelClient; 86 return supLev == SuppressLevel.UNCHECKED || 87 (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE); 88 } 89 } 90 91 enum SourceLevel { 92 JDK_9("9"), 93 LATEST(Integer.toString(javax.lang.model.SourceVersion.latest().runtimeVersion().feature())); 94 95 String sourceKey; 96 97 SourceLevel(String sourceKey) { 98 this.sourceKey = sourceKey; 99 } 100 } 101 102 enum TrustMe implements ComboParameter { 103 DONT_TRUST(""), 104 TRUST("@java.lang.SafeVarargs"); 105 106 String anno; 107 108 TrustMe(String anno) { 109 this.anno = anno; 110 } 111 112 @Override 113 public String expand(String optParameter) { 114 return anno; 115 } 116 } 117 118 enum ModifierKind implements ComboParameter { 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 @Override 131 public String expand(String optParameter) { 132 return mod; 133 } 134 } 135 136 enum SuppressLevel implements ComboParameter { 137 NONE(""), 138 UNCHECKED("unchecked"); 139 140 String lint; 141 142 SuppressLevel(String lint) { 143 this.lint = lint; 144 } 145 146 @Override 147 public String expand(String optParameter) { 148 return "@SuppressWarnings(\"" + lint + "\")"; 149 } 150 } 151 152 enum Signature implements ComboParameter { 153 UNBOUND("void #NAME(List<?>#ARITY arg) { #BODY }", 154 new Warning[][] {none, none, none, none, error}), 155 INVARIANT_TVAR("<Z> void #NAME(List<Z>#ARITY arg) { #BODY }", 156 new Warning[][] {both, both, error, both, error}), 157 TVAR("<Z> void #NAME(Z#ARITY arg) { #BODY }", 158 new Warning[][] {both, both, both, both, vararg}), 159 INVARIANT("void #NAME(List<String>#ARITY arg) { #BODY }", 160 new Warning[][] {error, error, error, both, error}), 161 UNPARAMETERIZED("void #NAME(String#ARITY arg) { #BODY }", 162 new Warning[][] {error, error, error, error, none}); 163 164 String template; 165 Warning[][] warnings; 166 167 Signature(String template, Warning[][] warnings) { 168 this.template = template; 169 this.warnings = warnings; 170 } 171 172 boolean isApplicableTo(Signature other) { 173 return warnings[other.ordinal()] != null; 174 } 175 176 boolean giveUnchecked(Signature other) { 177 return warnings[other.ordinal()] == unchecked || 178 warnings[other.ordinal()] == both; 179 } 180 181 boolean giveVarargs(Signature other) { 182 return warnings[other.ordinal()] == vararg || 183 warnings[other.ordinal()] == both; 184 } 185 186 @Override 187 public String expand(String optParameter) { 188 if (optParameter.equals("CLIENT")) { 189 return template.replaceAll("#ARITY", "") 190 .replaceAll("#NAME", "test") 191 .replaceAll("#BODY", "m(arg)"); 192 } else { 193 return template.replaceAll("#ARITY", "...") 194 .replaceAll("#NAME", "m") 195 .replaceAll("#BODY", ""); 196 } 197 } 198 } 199 200 public static void main(String... args) { 201 new ComboTestHelper<Warn4>() 202 .withFilter(Warn4::badTestFilter) 203 .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values()) 204 .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values()) 205 .withArrayDimension("SUPPRESS", (x, suppress, idx) -> x.suppress[idx] = suppress, 2, SuppressLevel.values()) 206 .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values()) 207 .withArrayDimension("MTH", (x, sig, idx) -> x.sigs[idx] = sig, 2, Signature.values()) 208 .run(Warn4::new); 209 } 210 211 SourceLevel sourceLevel; 212 TrustMe trustMe; 213 SuppressLevel[] suppress = new SuppressLevel[2]; 214 ModifierKind modKind; 215 Signature[] sigs = new Signature[2]; 216 217 boolean badTestFilter() { 218 return sigs[0].isApplicableTo(sigs[1]); 219 } 220 221 final String template = """ 222 import java.util.List; 223 class Test { 224 #{TRUSTME} #{SUPPRESS[0]} #{MOD} #{MTH[0].VARARG} 225 #{SUPPRESS[1]} #{MTH[1].CLIENT} 226 } 227 """; 228 229 @Override 230 public void doWork() throws IOException { 231 newCompilationTask() 232 .withOption("-Xlint:unchecked") 233 .withOption("--release") 234 .withOption(sourceLevel.sourceKey) 235 .withSourceFromTemplate(template) 236 .analyze(this::check); 237 } 238 239 void check(Result<?> res) { 240 boolean[] warnArr = new boolean[] {sigs[0].giveUnchecked(sigs[1]), 241 sigs[0].giveVarargs(sigs[1])}; 242 243 Set<Warning> warnings = new HashSet<>(); 244 for (Diagnostic<? extends JavaFileObject> d : res.diagnosticsForKind(Kind.MANDATORY_WARNING)) { 245 if (d.getCode().contains(Warning.VARARGS.key)) { 246 warnings.add(Warning.VARARGS); 247 } else if(d.getCode().contains(Warning.UNCHECKED.key)) { 248 warnings.add(Warning.UNCHECKED); 249 } 250 } 251 252 boolean badOutput = false; 253 for (Warning wkind : Warning.values()) { 254 boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel, 255 suppress[1], suppress[0], modKind); 256 badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) != 257 warnings.contains(wkind); 258 } 259 if (badOutput) { 260 fail("invalid diagnostics for source:\n" + 261 res.compilationInfo() + 262 "\nExpected unchecked warning: " + warnArr[0] + 263 "\nExpected unsafe vararg warning: " + warnArr[1] + 264 "\nWarnings: " + warnings + 265 "\nSource level: " + sourceLevel); 266 } 267 } 268 }