|
1 /* |
|
2 * Copyright (c) 2016, 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 8145471 |
|
27 * @summary javac changes for enhanced deprecation |
|
28 * @library /tools/lib |
|
29 * @modules jdk.compiler/com.sun.tools.javac.api |
|
30 * @modules jdk.compiler/com.sun.tools.javac.main |
|
31 * @build toolbox.JavacTask toolbox.TestRunner toolbox.ToolBox |
|
32 * @run main Removal |
|
33 */ |
|
34 |
|
35 import java.io.IOException; |
|
36 import java.nio.file.Files; |
|
37 import java.nio.file.Path; |
|
38 import java.nio.file.Paths; |
|
39 import java.util.ArrayList; |
|
40 import java.util.Arrays; |
|
41 import java.util.EnumMap; |
|
42 import java.util.List; |
|
43 import java.util.Map; |
|
44 import java.util.stream.Collectors; |
|
45 |
|
46 import toolbox.JavacTask; |
|
47 import toolbox.Task.Expect; |
|
48 import toolbox.Task.OutputKind; |
|
49 import toolbox.TestRunner; |
|
50 import toolbox.ToolBox; |
|
51 |
|
52 /* |
|
53 * From JEP 277, JDK-8085614 |
|
54 * |
|
55 * use site | API declaration site |
|
56 * context | not dep. ord. dep. term. dep. |
|
57 * +---------------------------------- |
|
58 * not dep. | N W W |
|
59 * | |
|
60 * ord. dep. | N N (2) W (4) |
|
61 * | |
|
62 * term. dep. | N N (3) W (5) |
|
63 */ |
|
64 |
|
65 public class Removal extends TestRunner { |
|
66 public static void main(String... args) throws Exception { |
|
67 Removal r = new Removal(); |
|
68 r.runTests(m -> new Object[] { Paths.get(m.getName()) }); |
|
69 r.report(); |
|
70 } |
|
71 |
|
72 private final ToolBox tb = new ToolBox(); |
|
73 private final Path libSrc = Paths.get("lib").resolve("src"); |
|
74 private final Path libClasses = Paths.get("lib").resolve("classes"); |
|
75 int testCount = 0; |
|
76 |
|
77 /** |
|
78 * Options that may be used during compilation. |
|
79 */ |
|
80 enum Options { |
|
81 DEFAULT(), |
|
82 XLINT_DEPRECATED("-Xlint:deprecation"), |
|
83 XLINT_NO_REMOVAL("-Xlint:-removal"); |
|
84 |
|
85 Options(String... opts) { |
|
86 this.opts = Arrays.asList(opts); |
|
87 } |
|
88 |
|
89 final List<String> opts; |
|
90 } |
|
91 |
|
92 /** |
|
93 * The kind of deprecation. |
|
94 */ |
|
95 enum DeprKind { |
|
96 NONE("", null), |
|
97 DEPRECATED("@Deprecated ", "compiler.warn.has.been.deprecated"), |
|
98 REMOVAL("@Deprecated(forRemoval=true) ", "compiler.warn.has.been.deprecated.for.removal"); |
|
99 DeprKind(String anno, String warn) { |
|
100 this.anno = anno; |
|
101 this.warn = warn; |
|
102 } |
|
103 final String anno; |
|
104 final String warn; |
|
105 } |
|
106 |
|
107 final String[] lib = { |
|
108 "package lib; public class Class {\n" |
|
109 + " public static void method() { }\n" |
|
110 + " @Deprecated public static void depMethod() { }\n" |
|
111 + " @Deprecated(forRemoval=true) public static void remMethod() { }\n" |
|
112 + " public static int field;\n" |
|
113 + " @Deprecated public static int depField;\n" |
|
114 + " @Deprecated(forRemoval=true) public static int remField;\n" |
|
115 + "}", |
|
116 "package lib; @Deprecated public class DepClass { }", |
|
117 "package lib; @Deprecated(forRemoval=true) public class RemClass { }" |
|
118 }; |
|
119 |
|
120 /** |
|
121 * The kind of declaration to be referenced at the use site. |
|
122 */ |
|
123 enum RefKind { |
|
124 CLASS("lib.%s c;", "Class", "DepClass", "RemClass"), |
|
125 METHOD("{ lib.Class.%s(); }", "method", "depMethod", "remMethod"), |
|
126 FIELD("int i = lib.Class.%s;", "field", "depField", "remField"); |
|
127 |
|
128 RefKind(String template, String def, String dep, String rem) { |
|
129 fragments.put(DeprKind.NONE, String.format(template, def)); |
|
130 fragments.put(DeprKind.DEPRECATED, String.format(template, dep)); |
|
131 fragments.put(DeprKind.REMOVAL, String.format(template, rem)); |
|
132 } |
|
133 |
|
134 String getFragment(DeprKind k) { |
|
135 return fragments.get(k); |
|
136 } |
|
137 |
|
138 private final Map<DeprKind, String> fragments = new EnumMap<>(DeprKind.class); |
|
139 } |
|
140 |
|
141 /** |
|
142 * Get source code for a reference to a possibly-deprecated item declared in a library. |
|
143 * @param refKind the kind of element (class, method, field) being referenced |
|
144 * @param declDeprKind the kind of deprecation on the declaration of the item being referenced |
|
145 * @param useDeprKind the kind of deprecation enclosing the use site |
|
146 * @return |
|
147 */ |
|
148 static String getSource(RefKind refKind, DeprKind declDeprKind, DeprKind useDeprKind) { |
|
149 return "package p; " |
|
150 + useDeprKind.anno |
|
151 + "class Class { " |
|
152 + refKind.getFragment(declDeprKind) |
|
153 + " }"; |
|
154 } |
|
155 |
|
156 private static final String NO_OUTPUT = null; |
|
157 |
|
158 public Removal() throws IOException { |
|
159 super(System.err); |
|
160 initLib(); |
|
161 } |
|
162 |
|
163 void initLib() throws IOException { |
|
164 tb.writeJavaFiles(libSrc, lib); |
|
165 |
|
166 new JavacTask(tb) |
|
167 .outdir(Files.createDirectories(libClasses)) |
|
168 .files(tb.findJavaFiles(libSrc)) |
|
169 .run() |
|
170 .writeAll(); |
|
171 } |
|
172 |
|
173 void report() { |
|
174 out.println(testCount + " test cases"); |
|
175 } |
|
176 |
|
177 /* |
|
178 * Declaration site: not deprecated; use site: not deprecated |
|
179 * Options: default |
|
180 * Expect: no warnings |
|
181 */ |
|
182 @Test |
|
183 public void test_DeclNone_UseNone(Path base) throws IOException { |
|
184 for (RefKind rk : RefKind.values()) { |
|
185 test(base, |
|
186 getSource(rk, DeprKind.NONE, DeprKind.NONE), |
|
187 Options.DEFAULT, |
|
188 NO_OUTPUT); |
|
189 } |
|
190 } |
|
191 |
|
192 /* |
|
193 * Declaration site: not deprecated; use site: deprecated |
|
194 * Options: default |
|
195 * Expect: no warnings |
|
196 */ |
|
197 @Test |
|
198 public void test_DeclNone_UseDeprecated(Path base) throws IOException { |
|
199 for (RefKind rk : RefKind.values()) { |
|
200 test(base, |
|
201 getSource(rk, DeprKind.NONE, DeprKind.DEPRECATED), |
|
202 Options.DEFAULT, |
|
203 NO_OUTPUT); |
|
204 } |
|
205 } |
|
206 |
|
207 /* |
|
208 * Declaration site: not deprecated; use site: deprecated for removal |
|
209 * Options: default |
|
210 * Expect: no warnings |
|
211 */ |
|
212 @Test |
|
213 public void test_DeclNone_UseRemoval(Path base) throws IOException { |
|
214 for (RefKind rk : RefKind.values()) { |
|
215 test(base, |
|
216 getSource(rk, DeprKind.NONE, DeprKind.REMOVAL), |
|
217 Options.DEFAULT, |
|
218 NO_OUTPUT); |
|
219 } |
|
220 } |
|
221 |
|
222 /* |
|
223 * Declaration site: deprecated; use site: not deprecated |
|
224 * Options: default |
|
225 * Expect: deprecated note |
|
226 */ |
|
227 @Test |
|
228 public void test_DeclDeprecated_UseNone_Default(Path base) throws IOException { |
|
229 for (RefKind rk : RefKind.values()) { |
|
230 test(base, |
|
231 getSource(rk, DeprKind.DEPRECATED, DeprKind.NONE), |
|
232 Options.DEFAULT, |
|
233 "compiler.note.deprecated.filename: Class.java"); |
|
234 } |
|
235 } |
|
236 |
|
237 /* |
|
238 * Declaration site: deprecated; use site: not deprecated |
|
239 * Options: -Xlint:deprecation |
|
240 * Expect: deprecated warning |
|
241 */ |
|
242 @Test |
|
243 public void test_DeclDeprecated_UseNone_XlintDep(Path base) throws IOException { |
|
244 for (RefKind rk : RefKind.values()) { |
|
245 String error = "<unset>"; |
|
246 switch (rk) { |
|
247 case CLASS: |
|
248 error = "Class.java:1:29: compiler.warn.has.been.deprecated: lib.DepClass, lib"; |
|
249 break; |
|
250 |
|
251 case METHOD: |
|
252 error = "Class.java:1:37: compiler.warn.has.been.deprecated: depMethod(), lib.Class"; |
|
253 break; |
|
254 |
|
255 case FIELD: |
|
256 error = "Class.java:1:43: compiler.warn.has.been.deprecated: depField, lib.Class"; |
|
257 break; |
|
258 } |
|
259 |
|
260 test(base, |
|
261 getSource(rk, DeprKind.DEPRECATED, DeprKind.NONE), |
|
262 Options.XLINT_DEPRECATED, |
|
263 error); |
|
264 } |
|
265 } |
|
266 |
|
267 /* |
|
268 * Declaration site: deprecated; use site: deprecated |
|
269 * Options: default |
|
270 * Expect: no warnings |
|
271 */ |
|
272 @Test |
|
273 public void test_DeclDeprecated_UseDeprecated(Path base) throws IOException { |
|
274 for (RefKind rk : RefKind.values()) { |
|
275 test(base, |
|
276 getSource(rk, DeprKind.DEPRECATED, DeprKind.DEPRECATED), |
|
277 Options.DEFAULT, |
|
278 NO_OUTPUT); |
|
279 } |
|
280 } |
|
281 |
|
282 /* |
|
283 * Declaration site: deprecated; use site: deprecated for removal |
|
284 * Options: default |
|
285 * Expect: no warnings |
|
286 */ |
|
287 @Test |
|
288 public void test_DeclDeprecated_UseRemoval(Path base) throws IOException { |
|
289 for (RefKind rk : RefKind.values()) { |
|
290 test(base, |
|
291 getSource(rk, DeprKind.DEPRECATED, DeprKind.REMOVAL), |
|
292 Options.DEFAULT, |
|
293 NO_OUTPUT); |
|
294 } |
|
295 } |
|
296 |
|
297 /* |
|
298 * Declaration site: deprecated for removal; use site: not deprecated |
|
299 * Options: default |
|
300 * Expect: removal warning |
|
301 */ |
|
302 @Test |
|
303 public void test_DeclRemoval_UseNone_Default(Path base) throws IOException { |
|
304 for (RefKind rk : RefKind.values()) { |
|
305 String error = "<unset>"; |
|
306 switch (rk) { |
|
307 case CLASS: |
|
308 error = "Class.java:1:29: compiler.warn.has.been.deprecated.for.removal: lib.RemClass, lib"; |
|
309 break; |
|
310 |
|
311 case METHOD: |
|
312 error = "Class.java:1:37: compiler.warn.has.been.deprecated.for.removal: remMethod(), lib.Class"; |
|
313 break; |
|
314 |
|
315 case FIELD: |
|
316 error = "Class.java:1:43: compiler.warn.has.been.deprecated.for.removal: remField, lib.Class"; |
|
317 break; |
|
318 } |
|
319 |
|
320 test(base, |
|
321 getSource(rk, DeprKind.REMOVAL, DeprKind.NONE), |
|
322 Options.DEFAULT, |
|
323 error); |
|
324 } |
|
325 } |
|
326 |
|
327 /* |
|
328 * Declaration site: deprecated for removal; use site: not deprecated |
|
329 * Options: default, @SuppressWarnings("removal") |
|
330 * Expect: removal warning |
|
331 */ |
|
332 @Test |
|
333 public void test_DeclRemoval_UseNone_SuppressRemoval(Path base) throws IOException { |
|
334 for (RefKind rk : RefKind.values()) { |
|
335 String source = |
|
336 getSource(rk, DeprKind.REMOVAL, DeprKind.NONE) |
|
337 .replace("class Class", "@SuppressWarnings(\"removal\") class Class"); |
|
338 |
|
339 test(base, |
|
340 source, |
|
341 Options.DEFAULT, |
|
342 null); |
|
343 } |
|
344 } |
|
345 |
|
346 /* |
|
347 * Declaration site: deprecated for removal; use site: not deprecated |
|
348 * Options: -Xlint:-removal |
|
349 * Expect: removal note |
|
350 */ |
|
351 @Test |
|
352 public void test_DeclRemoval_UseNone_XlintNoRemoval(Path base) throws IOException { |
|
353 for (RefKind rk : RefKind.values()) { |
|
354 test(base, |
|
355 getSource(rk, DeprKind.REMOVAL, DeprKind.NONE), |
|
356 Options.XLINT_NO_REMOVAL, |
|
357 "compiler.note.removal.filename: Class.java"); |
|
358 } |
|
359 } |
|
360 |
|
361 /* |
|
362 * Declaration site: deprecated for removal; use site: deprecated |
|
363 * Options: default |
|
364 * Expect: removal warning |
|
365 */ |
|
366 @Test |
|
367 public void test_DeclRemoval_UseDeprecated_Default(Path base) throws IOException { |
|
368 for (RefKind rk : RefKind.values()) { |
|
369 String error = "<unset>"; |
|
370 switch (rk) { |
|
371 case CLASS: |
|
372 error = "Class.java:1:41: compiler.warn.has.been.deprecated.for.removal: lib.RemClass, lib"; |
|
373 break; |
|
374 |
|
375 case METHOD: |
|
376 error = "Class.java:1:49: compiler.warn.has.been.deprecated.for.removal: remMethod(), lib.Class"; |
|
377 break; |
|
378 |
|
379 case FIELD: |
|
380 error = "Class.java:1:55: compiler.warn.has.been.deprecated.for.removal: remField, lib.Class"; |
|
381 break; |
|
382 } |
|
383 |
|
384 test(base, |
|
385 getSource(rk, DeprKind.REMOVAL, DeprKind.DEPRECATED), |
|
386 Options.DEFAULT, |
|
387 error); |
|
388 } |
|
389 } |
|
390 |
|
391 /* |
|
392 * Declaration site: deprecated for removal; use site: deprecated |
|
393 * Options: -Xlint:-removal |
|
394 * Expect: removal note |
|
395 */ |
|
396 @Test |
|
397 public void test_DeclRemoval_UseDeprecated_XlintNoRemoval(Path base) throws IOException { |
|
398 for (RefKind rk : RefKind.values()) { |
|
399 test(base, |
|
400 getSource(rk, DeprKind.REMOVAL, DeprKind.DEPRECATED), |
|
401 Options.XLINT_NO_REMOVAL, |
|
402 "compiler.note.removal.filename: Class.java"); |
|
403 } |
|
404 } |
|
405 |
|
406 /* |
|
407 * Declaration site: deprecated for removal; use site: deprecated for removal |
|
408 * Options: default |
|
409 * Expect: removal warning |
|
410 */ |
|
411 @Test |
|
412 public void test_DeclRemoval_UseRemoval_Default(Path base) throws IOException { |
|
413 for (RefKind rk : RefKind.values()) { |
|
414 String error = "<unset>"; |
|
415 switch (rk) { |
|
416 case CLASS: |
|
417 error = "Class.java:1:58: compiler.warn.has.been.deprecated.for.removal: lib.RemClass, lib"; |
|
418 break; |
|
419 |
|
420 case METHOD: |
|
421 error = "Class.java:1:66: compiler.warn.has.been.deprecated.for.removal: remMethod(), lib.Class"; |
|
422 break; |
|
423 |
|
424 case FIELD: |
|
425 error = "Class.java:1:72: compiler.warn.has.been.deprecated.for.removal: remField, lib.Class"; |
|
426 break; |
|
427 } |
|
428 |
|
429 test(base, |
|
430 getSource(rk, DeprKind.REMOVAL, DeprKind.REMOVAL), |
|
431 Options.DEFAULT, |
|
432 error); |
|
433 } |
|
434 } |
|
435 |
|
436 /* |
|
437 * Declaration site: deprecated for removal; use site: deprecated for removal |
|
438 * Options: -Xlint:-removal |
|
439 * Expect: removal note |
|
440 */ |
|
441 @Test |
|
442 public void test_DeclRemoval_UseRemoval_XlintNoRemoval(Path base) throws IOException { |
|
443 for (RefKind rk : RefKind.values()) { |
|
444 test(base, |
|
445 getSource(rk, DeprKind.REMOVAL, DeprKind.REMOVAL), |
|
446 Options.XLINT_NO_REMOVAL, |
|
447 "compiler.note.removal.filename: Class.java"); |
|
448 } |
|
449 } |
|
450 |
|
451 /* |
|
452 * Additional special case: |
|
453 * there should not be any warnings for any reference in a type-import statement. |
|
454 */ |
|
455 @Test |
|
456 public void test_UseImports(Path base) throws IOException { |
|
457 String source = |
|
458 "import lib.Class;\n" |
|
459 + "import lib.DepClass;\n" |
|
460 + "import lib.RemClass;\n" |
|
461 + "class C { }"; |
|
462 for (Options o : Options.values()) { |
|
463 test(base, source, o, NO_OUTPUT); |
|
464 } |
|
465 } |
|
466 |
|
467 /** |
|
468 * Compile source code with given options, and check for expected output. |
|
469 * The compilation is done twice, first against the library in source form, |
|
470 * and then again, against the compiled library. |
|
471 * @param base base working directory |
|
472 * @param source the source code to be compiled |
|
473 * @param options the options for the compilation |
|
474 * @param expectText the expected output, or NO_OUTPUT, if none expected. |
|
475 * @throws IOException if an error occurs during the compilation |
|
476 */ |
|
477 private void test(Path base, String source, Options options, String expectText) throws IOException { |
|
478 test(base.resolve("lib-source"), libSrc, source, options, expectText); |
|
479 test(base.resolve("lib-classes"), libClasses, source, options, expectText); |
|
480 } |
|
481 |
|
482 /** |
|
483 * Compile source code with given options against a given version of the library, |
|
484 * and check for expected output. |
|
485 * @param base base working directory |
|
486 * @param lib the directory containing the library, in either source or compiled form |
|
487 * @param source the source code to be compiled |
|
488 * @param options the options for the compilation |
|
489 * @param expectText the expected output, or NO_OUTPUT, if none expected. |
|
490 * @throws IOException if an error occurs during the compilation |
|
491 */ |
|
492 private void test(Path base, Path lib, String source, Options options, String expectText) |
|
493 throws IOException { |
|
494 Expect expect = (expectText != null && expectText.contains("compiler.warn.")) ? Expect.FAIL : Expect.SUCCESS; |
|
495 test(base, lib, source, options.opts, expect, expectText); |
|
496 } |
|
497 |
|
498 /** |
|
499 * Compile source code with given options against a given version of the library, |
|
500 * and check for expected exit code and expected output. |
|
501 * @param base base working directory |
|
502 * @param lib the directory containing the library, in either source or compiled form |
|
503 * @param source the source code to be compiled |
|
504 * @param options the options for the compilation |
|
505 * @param expect the expected outcome of the compilation |
|
506 * @param expectText the expected output, or NO_OUTPUT, if none expected. |
|
507 * @throws IOException if an error occurs during the compilation |
|
508 */ |
|
509 private void test(Path base, Path lib, String source, List<String> options, |
|
510 Expect expect, String expectText) throws IOException { |
|
511 testCount++; |
|
512 |
|
513 Path src = base.resolve("src"); |
|
514 Path classes = Files.createDirectories(base.resolve("classes")); |
|
515 tb.writeJavaFiles(src, source); |
|
516 |
|
517 List<String> allOptions = new ArrayList<>(); |
|
518 allOptions.add("-XDrawDiagnostics"); |
|
519 allOptions.add("-Werror"); |
|
520 allOptions.addAll(options); |
|
521 |
|
522 out.println("Source: " + source); |
|
523 out.println("Classpath: " + lib); |
|
524 out.println("Options: " + options.stream().collect(Collectors.joining(" "))); |
|
525 |
|
526 String log = new JavacTask(tb) |
|
527 .outdir(classes) |
|
528 .classpath(lib) // use classpath for libSrc or libClasses |
|
529 .files(tb.findJavaFiles(src)) |
|
530 .options(allOptions.toArray(new String[0])) |
|
531 .run(expect) |
|
532 .writeAll() |
|
533 .getOutput(OutputKind.DIRECT); |
|
534 |
|
535 if (expectText == null) { |
|
536 if (!log.trim().isEmpty()) |
|
537 error("Unexpected text found: >>>" + log + "<<<"); |
|
538 } else { |
|
539 if (!log.contains(expectText)) |
|
540 error("expected text not found: >>>" + expectText + "<<<"); |
|
541 } |
|
542 } |
|
543 } |
|
544 |