Wed, 06 Apr 2011 20:33:44 -0700
7033660: Update copyright year to 2011 on any files changed in 2011
Reviewed-by: dholmes
1 /*
2 * Copyright (c) 2010, 2011, 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 */
24 /**
25 * @test
26 * @bug 6945418 6993978
27 * @summary Project Coin: Simplified Varargs Method Invocation
28 * @author mcimadamore
29 * @run main Warn4
30 */
31 import com.sun.source.util.JavacTask;
32 import com.sun.tools.javac.api.JavacTool;
33 import java.net.URI;
34 import java.util.Arrays;
35 import java.util.Set;
36 import java.util.HashSet;
37 import javax.tools.Diagnostic;
38 import javax.tools.JavaCompiler;
39 import javax.tools.JavaFileObject;
40 import javax.tools.SimpleJavaFileObject;
41 import javax.tools.StandardJavaFileManager;
42 import javax.tools.ToolProvider;
44 public class Warn4 {
46 final static Warning[] error = null;
47 final static Warning[] none = new Warning[] {};
48 final static Warning[] vararg = new Warning[] { Warning.VARARGS };
49 final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED };
50 final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED };
52 enum Warning {
53 UNCHECKED("generic.array.creation"),
54 VARARGS("varargs.non.reifiable.type");
56 String key;
58 Warning(String key) {
59 this.key = key;
60 }
62 boolean isSuppressed(TrustMe trustMe, SourceLevel source, SuppressLevel suppressLevelClient,
63 SuppressLevel suppressLevelDecl, ModifierKind modKind) {
64 switch(this) {
65 case VARARGS:
66 return source == SourceLevel.JDK_6 ||
67 suppressLevelDecl == SuppressLevel.UNCHECKED ||
68 trustMe == TrustMe.TRUST;
69 case UNCHECKED:
70 return suppressLevelClient == SuppressLevel.UNCHECKED ||
71 (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE && source == SourceLevel.JDK_7);
72 }
74 SuppressLevel supLev = this == VARARGS ?
75 suppressLevelDecl :
76 suppressLevelClient;
77 return supLev == SuppressLevel.UNCHECKED ||
78 (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE);
79 }
80 }
82 enum SourceLevel {
83 JDK_6("6"),
84 JDK_7("7");
86 String sourceKey;
88 SourceLevel(String sourceKey) {
89 this.sourceKey = sourceKey;
90 }
91 }
93 enum TrustMe {
94 DONT_TRUST(""),
95 TRUST("@java.lang.SafeVarargs");
97 String anno;
99 TrustMe(String anno) {
100 this.anno = anno;
101 }
102 }
104 enum ModifierKind {
105 NONE(" "),
106 FINAL("final "),
107 STATIC("static ");
109 String mod;
111 ModifierKind(String mod) {
112 this.mod = mod;
113 }
114 }
116 enum SuppressLevel {
117 NONE(""),
118 UNCHECKED("unchecked");
120 String lint;
122 SuppressLevel(String lint) {
123 this.lint = lint;
124 }
126 String getSuppressAnno() {
127 return "@SuppressWarnings(\"" + lint + "\")";
128 }
129 }
131 enum Signature {
132 UNBOUND("void #name(List<?>#arity arg) { #body }",
133 new Warning[][] {none, none, none, none, error}),
134 INVARIANT_TVAR("<Z> void #name(List<Z>#arity arg) { #body }",
135 new Warning[][] {both, both, error, both, error}),
136 TVAR("<Z> void #name(Z#arity arg) { #body }",
137 new Warning[][] {both, both, both, both, vararg}),
138 INVARIANT("void #name(List<String>#arity arg) { #body }",
139 new Warning[][] {error, error, error, both, error}),
140 UNPARAMETERIZED("void #name(String#arity arg) { #body }",
141 new Warning[][] {error, error, error, error, none});
143 String template;
144 Warning[][] warnings;
146 Signature(String template, Warning[][] warnings) {
147 this.template = template;
148 this.warnings = warnings;
149 }
151 boolean isApplicableTo(Signature other) {
152 return warnings[other.ordinal()] != null;
153 }
155 boolean giveUnchecked(Signature other) {
156 return warnings[other.ordinal()] == unchecked ||
157 warnings[other.ordinal()] == both;
158 }
160 boolean giveVarargs(Signature other) {
161 return warnings[other.ordinal()] == vararg ||
162 warnings[other.ordinal()] == both;
163 }
164 }
166 public static void main(String... args) throws Exception {
167 for (SourceLevel sourceLevel : SourceLevel.values()) {
168 for (TrustMe trustMe : TrustMe.values()) {
169 for (SuppressLevel suppressLevelClient : SuppressLevel.values()) {
170 for (SuppressLevel suppressLevelDecl : SuppressLevel.values()) {
171 for (ModifierKind modKind : ModifierKind.values()) {
172 for (Signature vararg_meth : Signature.values()) {
173 for (Signature client_meth : Signature.values()) {
174 if (vararg_meth.isApplicableTo(client_meth)) {
175 test(sourceLevel,
176 trustMe,
177 suppressLevelClient,
178 suppressLevelDecl,
179 modKind,
180 vararg_meth,
181 client_meth);
182 }
183 }
184 }
185 }
186 }
187 }
188 }
189 }
190 }
192 // Create a single file manager and reuse it for each compile to save time.
193 static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
195 static void test(SourceLevel sourceLevel, TrustMe trustMe, SuppressLevel suppressLevelClient,
196 SuppressLevel suppressLevelDecl, ModifierKind modKind, Signature vararg_meth, Signature client_meth) throws Exception {
197 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
198 JavaSource source = new JavaSource(trustMe, suppressLevelClient, suppressLevelDecl, modKind, vararg_meth, client_meth);
199 DiagnosticChecker dc = new DiagnosticChecker();
200 JavacTask ct = (JavacTask)tool.getTask(null, fm, dc,
201 Arrays.asList("-Xlint:unchecked", "-source", sourceLevel.sourceKey),
202 null, Arrays.asList(source));
203 ct.generate(); //to get mandatory notes
204 check(dc.warnings, sourceLevel,
205 new boolean[] {vararg_meth.giveUnchecked(client_meth),
206 vararg_meth.giveVarargs(client_meth)},
207 source, trustMe, suppressLevelClient, suppressLevelDecl, modKind);
208 }
210 static void check(Set<Warning> warnings, SourceLevel sourceLevel, boolean[] warnArr, JavaSource source,
211 TrustMe trustMe, SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl, ModifierKind modKind) {
212 boolean badOutput = false;
213 for (Warning wkind : Warning.values()) {
214 boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel,
215 suppressLevelClient, suppressLevelDecl, modKind);
216 System.out.println("SUPPRESSED = " + isSuppressed);
217 badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) != warnings.contains(wkind);
218 }
219 if (badOutput) {
220 throw new Error("invalid diagnostics for source:\n" +
221 source.getCharContent(true) +
222 "\nExpected unchecked warning: " + warnArr[0] +
223 "\nExpected unsafe vararg warning: " + warnArr[1] +
224 "\nWarnings: " + warnings +
225 "\nSource level: " + sourceLevel);
226 }
227 }
229 static class JavaSource extends SimpleJavaFileObject {
231 String source;
233 public JavaSource(TrustMe trustMe, SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl,
234 ModifierKind modKind, Signature vararg_meth, Signature client_meth) {
235 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
236 String meth1 = vararg_meth.template.replace("#arity", "...");
237 meth1 = meth1.replace("#name", "m");
238 meth1 = meth1.replace("#body", "");
239 meth1 = trustMe.anno + "\n" + suppressLevelDecl.getSuppressAnno() + modKind.mod + meth1;
240 String meth2 = client_meth.template.replace("#arity", "");
241 meth2 = meth2.replace("#name", "test");
242 meth2 = meth2.replace("#body", "m(arg);");
243 meth2 = suppressLevelClient.getSuppressAnno() + meth2;
244 source = "import java.util.List;\n" +
245 "class Test {\n" + meth1 +
246 "\n" + meth2 + "\n}\n";
247 }
249 @Override
250 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
251 return source;
252 }
253 }
255 static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
257 Set<Warning> warnings = new HashSet<>();
259 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
260 if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING ||
261 diagnostic.getKind() == Diagnostic.Kind.WARNING) {
262 if (diagnostic.getCode().contains(Warning.VARARGS.key)) {
263 warnings.add(Warning.VARARGS);
264 } else if(diagnostic.getCode().contains(Warning.UNCHECKED.key)) {
265 warnings.add(Warning.UNCHECKED);
266 }
267 }
268 }
269 }
270 }