21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 |
23 |
24 /** |
24 /** |
25 * @test |
25 * @test |
26 * @bug 6945418 6993978 8006694 7196160 |
26 * @bug 6945418 6993978 8006694 7196160 8129962 |
27 * @summary Project Coin: Simplified Varargs Method Invocation |
27 * @summary Project Coin: Simplified Varargs Method Invocation |
28 * temporarily workaround combo tests are causing time out in several platforms |
28 * temporarily workaround combo tests are causing time out in several platforms |
29 * @author mcimadamore |
29 * @library /tools/javac/lib |
30 * @library ../../lib |
30 * @modules jdk.compiler/com.sun.tools.javac.api |
31 * @modules jdk.compiler |
31 * jdk.compiler/com.sun.tools.javac.code |
32 * @build JavacTestingAbstractThreadedTest |
32 * jdk.compiler/com.sun.tools.javac.comp |
33 * @run main/othervm Warn4 |
33 * jdk.compiler/com.sun.tools.javac.main |
|
34 * jdk.compiler/com.sun.tools.javac.tree |
|
35 * jdk.compiler/com.sun.tools.javac.util |
|
36 * @build combo.ComboTestHelper |
|
37 * @run main Warn4 |
34 */ |
38 */ |
35 |
39 |
36 // use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) |
40 import java.io.IOException; |
37 // see JDK-8006746 |
|
38 |
|
39 import java.net.URI; |
|
40 import java.util.Arrays; |
|
41 import java.util.Set; |
41 import java.util.Set; |
42 import java.util.HashSet; |
42 import java.util.HashSet; |
43 import javax.tools.Diagnostic; |
43 import javax.tools.Diagnostic; |
44 import javax.tools.JavaCompiler; |
44 import javax.tools.Diagnostic.Kind; |
45 import javax.tools.JavaFileObject; |
45 import javax.tools.JavaFileObject; |
46 import javax.tools.SimpleJavaFileObject; |
46 |
47 import javax.tools.ToolProvider; |
47 import combo.ComboInstance; |
48 import com.sun.source.util.JavacTask; |
48 import combo.ComboParameter; |
49 |
49 import combo.ComboTask.Result; |
50 public class Warn4 |
50 import combo.ComboTestHelper; |
51 extends JavacTestingAbstractThreadedTest |
51 |
52 implements Runnable { |
52 public class Warn4 extends ComboInstance<Warn4> { |
53 |
53 |
54 final static Warning[] error = null; |
54 final static Warning[] error = null; |
55 final static Warning[] none = new Warning[] {}; |
55 final static Warning[] none = new Warning[] {}; |
56 final static Warning[] vararg = new Warning[] { Warning.VARARGS }; |
56 final static Warning[] vararg = new Warning[] { Warning.VARARGS }; |
57 final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED }; |
57 final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED }; |
58 final static Warning[] both = |
58 final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED }; |
59 new Warning[] { Warning.VARARGS, Warning.UNCHECKED }; |
|
60 |
59 |
61 enum Warning { |
60 enum Warning { |
62 UNCHECKED("generic.array.creation"), |
61 UNCHECKED("generic.array.creation"), |
63 VARARGS("varargs.non.reifiable.type"); |
62 VARARGS("varargs.non.reifiable.type"); |
64 |
63 |
103 SourceLevel(String sourceKey) { |
102 SourceLevel(String sourceKey) { |
104 this.sourceKey = sourceKey; |
103 this.sourceKey = sourceKey; |
105 } |
104 } |
106 } |
105 } |
107 |
106 |
108 enum TrustMe { |
107 enum TrustMe implements ComboParameter { |
109 DONT_TRUST(""), |
108 DONT_TRUST(""), |
110 TRUST("@java.lang.SafeVarargs"); |
109 TRUST("@java.lang.SafeVarargs"); |
111 |
110 |
112 String anno; |
111 String anno; |
113 |
112 |
114 TrustMe(String anno) { |
113 TrustMe(String anno) { |
115 this.anno = anno; |
114 this.anno = anno; |
116 } |
115 } |
117 } |
116 |
118 |
117 @Override |
119 enum ModifierKind { |
118 public String expand(String optParameter) { |
|
119 return anno; |
|
120 } |
|
121 } |
|
122 |
|
123 enum ModifierKind implements ComboParameter { |
120 NONE(" "), |
124 NONE(" "), |
121 FINAL("final "), |
125 FINAL("final "), |
122 STATIC("static "), |
126 STATIC("static "), |
123 PRIVATE("private "); |
127 PRIVATE("private "); |
124 |
128 |
125 String mod; |
129 String mod; |
126 |
130 |
127 ModifierKind(String mod) { |
131 ModifierKind(String mod) { |
128 this.mod = mod; |
132 this.mod = mod; |
129 } |
133 } |
130 } |
134 |
131 |
135 @Override |
132 enum SuppressLevel { |
136 public String expand(String optParameter) { |
|
137 return mod; |
|
138 } |
|
139 } |
|
140 |
|
141 enum SuppressLevel implements ComboParameter { |
133 NONE(""), |
142 NONE(""), |
134 UNCHECKED("unchecked"); |
143 UNCHECKED("unchecked"); |
135 |
144 |
136 String lint; |
145 String lint; |
137 |
146 |
138 SuppressLevel(String lint) { |
147 SuppressLevel(String lint) { |
139 this.lint = lint; |
148 this.lint = lint; |
140 } |
149 } |
141 |
150 |
142 String getSuppressAnno() { |
151 @Override |
|
152 public String expand(String optParameter) { |
143 return "@SuppressWarnings(\"" + lint + "\")"; |
153 return "@SuppressWarnings(\"" + lint + "\")"; |
144 } |
154 } |
145 } |
155 } |
146 |
156 |
147 enum Signature { |
157 enum Signature implements ComboParameter { |
148 UNBOUND("void #name(List<?>#arity arg) { #body }", |
158 UNBOUND("void #NAME(List<?>#ARITY arg) { #BODY }", |
149 new Warning[][] {none, none, none, none, error}), |
159 new Warning[][] {none, none, none, none, error}), |
150 INVARIANT_TVAR("<Z> void #name(List<Z>#arity arg) { #body }", |
160 INVARIANT_TVAR("<Z> void #NAME(List<Z>#ARITY arg) { #BODY }", |
151 new Warning[][] {both, both, error, both, error}), |
161 new Warning[][] {both, both, error, both, error}), |
152 TVAR("<Z> void #name(Z#arity arg) { #body }", |
162 TVAR("<Z> void #NAME(Z#ARITY arg) { #BODY }", |
153 new Warning[][] {both, both, both, both, vararg}), |
163 new Warning[][] {both, both, both, both, vararg}), |
154 INVARIANT("void #name(List<String>#arity arg) { #body }", |
164 INVARIANT("void #NAME(List<String>#ARITY arg) { #BODY }", |
155 new Warning[][] {error, error, error, both, error}), |
165 new Warning[][] {error, error, error, both, error}), |
156 UNPARAMETERIZED("void #name(String#arity arg) { #body }", |
166 UNPARAMETERIZED("void #NAME(String#ARITY arg) { #BODY }", |
157 new Warning[][] {error, error, error, error, none}); |
167 new Warning[][] {error, error, error, error, none}); |
158 |
168 |
159 String template; |
169 String template; |
160 Warning[][] warnings; |
170 Warning[][] warnings; |
161 |
171 |
175 |
185 |
176 boolean giveVarargs(Signature other) { |
186 boolean giveVarargs(Signature other) { |
177 return warnings[other.ordinal()] == vararg || |
187 return warnings[other.ordinal()] == vararg || |
178 warnings[other.ordinal()] == both; |
188 warnings[other.ordinal()] == both; |
179 } |
189 } |
180 } |
190 |
181 |
191 @Override |
182 public static void main(String... args) throws Exception { |
192 public String expand(String optParameter) { |
183 for (SourceLevel sourceLevel : SourceLevel.values()) { |
193 if (optParameter.equals("CLIENT")) { |
184 for (TrustMe trustMe : TrustMe.values()) { |
194 return template.replaceAll("#ARITY", "") |
185 for (SuppressLevel suppressLevelClient : SuppressLevel.values()) { |
195 .replaceAll("#NAME", "test") |
186 for (SuppressLevel suppressLevelDecl : SuppressLevel.values()) { |
196 .replaceAll("#BODY", "m(arg)"); |
187 for (ModifierKind modKind : ModifierKind.values()) { |
197 } else { |
188 for (Signature vararg_meth : Signature.values()) { |
198 return template.replaceAll("#ARITY", "...") |
189 for (Signature client_meth : Signature.values()) { |
199 .replaceAll("#NAME", "m") |
190 if (vararg_meth.isApplicableTo(client_meth)) { |
200 .replaceAll("#BODY", ""); |
191 pool.execute(new Warn4(sourceLevel, |
|
192 trustMe, |
|
193 suppressLevelClient, |
|
194 suppressLevelDecl, |
|
195 modKind, |
|
196 vararg_meth, |
|
197 client_meth)); |
|
198 } |
|
199 } |
|
200 } |
|
201 } |
|
202 } |
|
203 } |
|
204 } |
201 } |
205 } |
202 } |
206 |
203 } |
207 checkAfterExec(); |
204 |
|
205 public static void main(String... args) { |
|
206 new ComboTestHelper<Warn4>() |
|
207 .withFilter(Warn4::badTestFilter) |
|
208 .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values()) |
|
209 .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values()) |
|
210 .withArrayDimension("SUPPRESS", (x, suppress, idx) -> x.suppress[idx] = suppress, 2, SuppressLevel.values()) |
|
211 .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values()) |
|
212 .withArrayDimension("MTH", (x, sig, idx) -> x.sigs[idx] = sig, 2, Signature.values()) |
|
213 .run(Warn4::new); |
208 } |
214 } |
209 |
215 |
210 SourceLevel sourceLevel; |
216 SourceLevel sourceLevel; |
211 TrustMe trustMe; |
217 TrustMe trustMe; |
212 SuppressLevel suppressLevelClient; |
218 SuppressLevel[] suppress = new SuppressLevel[2]; |
213 SuppressLevel suppressLevelDecl; |
|
214 ModifierKind modKind; |
219 ModifierKind modKind; |
215 Signature vararg_meth; |
220 Signature[] sigs = new Signature[2]; |
216 Signature client_meth; |
221 |
217 DiagnosticChecker diagChecker; |
222 boolean badTestFilter() { |
218 |
223 return sigs[0].isApplicableTo(sigs[1]); |
219 public Warn4(SourceLevel sourceLevel, TrustMe trustMe, |
224 } |
220 SuppressLevel suppressLevelClient, SuppressLevel suppressLevelDecl, |
225 |
221 ModifierKind modKind, Signature vararg_meth, Signature client_meth) { |
226 final String template = "import java.util.List;\n" + |
222 this.sourceLevel = sourceLevel; |
227 "class Test {\n" + |
223 this.trustMe = trustMe; |
228 " #{TRUSTME} #{SUPPRESS[0]} #{MOD} #{MTH[0].VARARG}\n" + |
224 this.suppressLevelClient = suppressLevelClient; |
229 " #{SUPPRESS[1]} #{MTH[1].CLIENT}\n" + |
225 this.suppressLevelDecl = suppressLevelDecl; |
230 "}"; |
226 this.modKind = modKind; |
|
227 this.vararg_meth = vararg_meth; |
|
228 this.client_meth = client_meth; |
|
229 this.diagChecker = new DiagnosticChecker(); |
|
230 } |
|
231 |
231 |
232 @Override |
232 @Override |
233 public void run() { |
233 public void doWork() throws IOException { |
234 int id = checkCount.incrementAndGet(); |
234 check(newCompilationTask() |
235 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); |
235 .withOption("-Xlint:unchecked") |
236 JavaSource source = new JavaSource(id); |
236 .withOption("-source") |
237 JavacTask ct = (JavacTask)tool.getTask(null, fm.get(), diagChecker, |
237 .withOption(sourceLevel.sourceKey) |
238 Arrays.asList("-Xlint:unchecked", "-source", sourceLevel.sourceKey), |
238 .withSourceFromTemplate(template) |
239 null, Arrays.asList(source)); |
239 .analyze()); |
240 ct.call(); //to get mandatory notes |
240 } |
241 check(source, new boolean[] {vararg_meth.giveUnchecked(client_meth), |
241 |
242 vararg_meth.giveVarargs(client_meth)}); |
242 void check(Result<?> res) { |
243 } |
243 boolean[] warnArr = new boolean[] {sigs[0].giveUnchecked(sigs[1]), |
244 |
244 sigs[0].giveVarargs(sigs[1])}; |
245 void check(JavaSource source, boolean[] warnArr) { |
245 |
|
246 Set<Warning> warnings = new HashSet<>(); |
|
247 for (Diagnostic<? extends JavaFileObject> d : res.diagnosticsForKind(Kind.MANDATORY_WARNING)) { |
|
248 if (d.getCode().contains(Warning.VARARGS.key)) { |
|
249 warnings.add(Warning.VARARGS); |
|
250 } else if(d.getCode().contains(Warning.UNCHECKED.key)) { |
|
251 warnings.add(Warning.UNCHECKED); |
|
252 } |
|
253 } |
|
254 |
246 boolean badOutput = false; |
255 boolean badOutput = false; |
247 for (Warning wkind : Warning.values()) { |
256 for (Warning wkind : Warning.values()) { |
248 boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel, |
257 boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel, |
249 suppressLevelClient, suppressLevelDecl, modKind); |
258 suppress[1], suppress[0], modKind); |
250 badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) != |
259 badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) != |
251 diagChecker.warnings.contains(wkind); |
260 warnings.contains(wkind); |
252 } |
261 } |
253 if (badOutput) { |
262 if (badOutput) { |
254 throw new Error("invalid diagnostics for source:\n" + |
263 fail("invalid diagnostics for source:\n" + |
255 source.getCharContent(true) + |
264 res.compilationInfo() + |
256 "\nExpected unchecked warning: " + warnArr[0] + |
265 "\nExpected unchecked warning: " + warnArr[0] + |
257 "\nExpected unsafe vararg warning: " + warnArr[1] + |
266 "\nExpected unsafe vararg warning: " + warnArr[1] + |
258 "\nWarnings: " + diagChecker.warnings + |
267 "\nWarnings: " + warnings + |
259 "\nSource level: " + sourceLevel); |
268 "\nSource level: " + sourceLevel); |
260 } |
269 } |
261 } |
270 } |
262 |
|
263 class JavaSource extends SimpleJavaFileObject { |
|
264 |
|
265 String source; |
|
266 |
|
267 public JavaSource(int id) { |
|
268 super(URI.create(String.format("myfo:/Test%d.java", id)), |
|
269 JavaFileObject.Kind.SOURCE); |
|
270 String meth1 = vararg_meth.template.replace("#arity", "..."); |
|
271 meth1 = meth1.replace("#name", "m"); |
|
272 meth1 = meth1.replace("#body", ""); |
|
273 meth1 = trustMe.anno + "\n" + suppressLevelDecl.getSuppressAnno() + |
|
274 modKind.mod + meth1; |
|
275 String meth2 = client_meth.template.replace("#arity", ""); |
|
276 meth2 = meth2.replace("#name", "test"); |
|
277 meth2 = meth2.replace("#body", "m(arg);"); |
|
278 meth2 = suppressLevelClient.getSuppressAnno() + meth2; |
|
279 source = String.format("import java.util.List;\n" + |
|
280 "class Test%s {\n %s \n %s \n } \n", id, meth1, meth2); |
|
281 } |
|
282 |
|
283 @Override |
|
284 public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
|
285 return source; |
|
286 } |
|
287 } |
|
288 |
|
289 static class DiagnosticChecker |
|
290 implements javax.tools.DiagnosticListener<JavaFileObject> { |
|
291 |
|
292 Set<Warning> warnings = new HashSet<>(); |
|
293 |
|
294 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { |
|
295 if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING || |
|
296 diagnostic.getKind() == Diagnostic.Kind.WARNING) { |
|
297 if (diagnostic.getCode().contains(Warning.VARARGS.key)) { |
|
298 warnings.add(Warning.VARARGS); |
|
299 } else if(diagnostic.getCode().contains(Warning.UNCHECKED.key)) { |
|
300 warnings.add(Warning.UNCHECKED); |
|
301 } |
|
302 } |
|
303 } |
|
304 } |
|
305 |
|
306 } |
271 } |