Warn4.java revision 580:f2fdd52e4e87
1/* 2 * Copyright (c) 2010, 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 27 * @summary Project Coin: Simplified Varargs Method Invocation 28 * @author mcimadamore 29 * @run main Warn4 30 */ 31import com.sun.source.util.JavacTask; 32import java.net.URI; 33import java.util.Arrays; 34import java.util.Set; 35import java.util.HashSet; 36import javax.tools.Diagnostic; 37import javax.tools.JavaCompiler; 38import javax.tools.JavaFileObject; 39import javax.tools.SimpleJavaFileObject; 40import javax.tools.ToolProvider; 41 42public class Warn4 { 43 44 final static Warning[] error = null; 45 final static Warning[] none = new Warning[] {}; 46 final static Warning[] vararg = new Warning[] { Warning.VARARGS }; 47 final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED }; 48 final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED }; 49 50 enum Warning { 51 UNCHECKED("unchecked"), 52 VARARGS("varargs"); 53 54 String category; 55 56 Warning(String category) { 57 this.category = category; 58 } 59 60 boolean isEnabled(XlintOption xlint, SuppressLevel suppressLevel) { 61 return Arrays.asList(xlint.enabledWarnings).contains(this); 62 } 63 64 boolean isSuppressed(SuppressLevel suppressLevel) { 65 return Arrays.asList(suppressLevel.suppressedWarnings).contains(VARARGS); 66 } 67 } 68 69 enum XlintOption { 70 NONE(), 71 UNCHECKED(Warning.UNCHECKED), 72 VARARGS(Warning.VARARGS), 73 ALL(Warning.UNCHECKED, Warning.VARARGS); 74 75 Warning[] enabledWarnings; 76 77 XlintOption(Warning... enabledWarnings) { 78 this.enabledWarnings = enabledWarnings; 79 } 80 81 String getXlintOption() { 82 StringBuilder buf = new StringBuilder(); 83 String sep = ""; 84 for (Warning w : enabledWarnings) { 85 buf.append(sep); 86 buf.append(w.category); 87 sep=","; 88 } 89 return "-Xlint:" + 90 (this == NONE ? "none" : buf.toString()); 91 } 92 } 93 94 enum SuppressLevel { 95 NONE(), 96 UNCHECKED(Warning.UNCHECKED), 97 VARARGS(Warning.VARARGS), 98 ALL(Warning.UNCHECKED, Warning.VARARGS); 99 100 Warning[] suppressedWarnings; 101 102 SuppressLevel(Warning... suppressedWarnings) { 103 this.suppressedWarnings = suppressedWarnings; 104 } 105 106 String getSuppressAnnotation() { 107 StringBuilder buf = new StringBuilder(); 108 String sep = ""; 109 for (Warning w : suppressedWarnings) { 110 buf.append(sep); 111 buf.append("\""); 112 buf.append(w.category); 113 buf.append("\""); 114 sep=","; 115 } 116 return this == NONE ? "" : 117 "@SuppressWarnings({" + buf.toString() + "})"; 118 } 119 } 120 121 enum Signature { 122 123 EXTENDS_TVAR("<Z> void #name(List<? extends Z>#arity arg) { #body }", 124 new Warning[][] {both, both, both, both, error, both, both, both, error}), 125 SUPER_TVAR("<Z> void #name(List<? super Z>#arity arg) { #body }", 126 new Warning[][] {error, both, error, both, error, error, both, both, error}), 127 UNBOUND("void #name(List<?>#arity arg) { #body }", 128 new Warning[][] {none, none, none, none, none, none, none, none, error}), 129 INVARIANT_TVAR("<Z> void #name(List<Z>#arity arg) { #body }", 130 new Warning[][] {both, both, both, both, error, both, both, both, error}), 131 TVAR("<Z> void #name(Z#arity arg) { #body }", 132 new Warning[][] {both, both, both, both, both, both, both, both, vararg}), 133 EXTENDS("void #name(List<? extends String>#arity arg) { #body }", 134 new Warning[][] {error, error, error, error, error, both, error, both, error}), 135 SUPER("void #name(List<? super String>#arity arg) { #body }", 136 new Warning[][] {error, error, error, error, error, error, both, both, error}), 137 INVARIANT("void #name(List<String>#arity arg) { #body }", 138 new Warning[][] {error, error, error, error, error, error, error, both, error}), 139 UNPARAMETERIZED("void #name(String#arity arg) { #body }", 140 new Warning[][] {error, error, error, error, error, error, error, error, none}); 141 142 String template; 143 Warning[][] warnings; 144 145 Signature(String template, Warning[][] warnings) { 146 this.template = template; 147 this.warnings = warnings; 148 } 149 150 boolean isApplicableTo(Signature other) { 151 return warnings[other.ordinal()] != null; 152 } 153 154 boolean giveUnchecked(Signature other) { 155 return warnings[other.ordinal()] == unchecked || 156 warnings[other.ordinal()] == both; 157 } 158 159 boolean giveVarargs(Signature other) { 160 return warnings[other.ordinal()] == vararg || 161 warnings[other.ordinal()] == both; 162 } 163 } 164 165 public static void main(String... args) throws Exception { 166 for (XlintOption xlint : XlintOption.values()) { 167 for (SuppressLevel suppressLevel : SuppressLevel.values()) { 168 for (Signature vararg_meth : Signature.values()) { 169 for (Signature client_meth : Signature.values()) { 170 if (vararg_meth.isApplicableTo(client_meth)) { 171 test(xlint, 172 suppressLevel, 173 vararg_meth, 174 client_meth); 175 } 176 } 177 } 178 } 179 } 180 } 181 182 static void test(XlintOption xlint, SuppressLevel suppressLevel, 183 Signature vararg_meth, Signature client_meth) throws Exception { 184 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 185 JavaSource source = new JavaSource(suppressLevel, vararg_meth, client_meth); 186 DiagnosticChecker dc = new DiagnosticChecker(); 187 JavacTask ct = (JavacTask)tool.getTask(null, null, dc, 188 Arrays.asList(xlint.getXlintOption()), null, Arrays.asList(source)); 189 ct.generate(); //to get mandatory notes 190 check(dc.warnings, 191 dc.notes, 192 new boolean[] {vararg_meth.giveUnchecked(client_meth), 193 vararg_meth.giveVarargs(client_meth)}, 194 source, xlint, suppressLevel); 195 } 196 197 static void check(Set<Warning> warnings, Set<Warning> notes, boolean[] warnArr, JavaSource source, XlintOption xlint, SuppressLevel suppressLevel) { 198 boolean badOutput = false; 199 for (Warning wkind : Warning.values()) { 200 badOutput |= (warnArr[wkind.ordinal()] && !wkind.isSuppressed(suppressLevel)) != 201 (wkind.isEnabled(xlint, suppressLevel) ? 202 warnings.contains(wkind) : 203 notes.contains(wkind)); 204 } 205 if (badOutput) { 206 throw new Error("invalid diagnostics for source:\n" + 207 source.getCharContent(true) + 208 "\nOptions: " + xlint.getXlintOption() + 209 "\nExpected unchecked warning: " + warnArr[0] + 210 "\nExpected unsafe vararg warning: " + warnArr[1] + 211 "\nWarnings: " + warnings + 212 "\nNotes: " + notes); 213 } 214 } 215 216 static class JavaSource extends SimpleJavaFileObject { 217 218 String source; 219 220 public JavaSource(SuppressLevel suppressLevel, Signature vararg_meth, Signature client_meth) { 221 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 222 String meth1 = vararg_meth.template.replace("#arity", "..."); 223 meth1 = meth1.replace("#name", "m"); 224 meth1 = meth1.replace("#body", ""); 225 meth1 = suppressLevel.getSuppressAnnotation() + meth1; 226 String meth2 = client_meth.template.replace("#arity", ""); 227 meth2 = meth2.replace("#name", "test"); 228 meth2 = meth2.replace("#body", "m(arg);"); 229 source = "import java.util.List;\n" + 230 "class Test {\n" + meth1 + 231 "\n" + meth2 + "\n}\n"; 232 } 233 234 @Override 235 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 236 return source; 237 } 238 } 239 240 static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { 241 242 Set<Warning> warnings = new HashSet<>(); 243 Set<Warning> notes = new HashSet<>(); 244 245 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 246 if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING || 247 diagnostic.getKind() == Diagnostic.Kind.WARNING) { 248 warnings.add(diagnostic.getCode().contains("varargs") ? 249 Warning.VARARGS : 250 Warning.UNCHECKED); 251 } 252 else if (diagnostic.getKind() == Diagnostic.Kind.NOTE) { 253 notes.add(diagnostic.getCode().contains("varargs") ? 254 Warning.VARARGS : 255 Warning.UNCHECKED); 256 } 257 } 258 } 259} 260