Thu, 16 Feb 2017 13:16:54 -0800
Merge
1 /*
2 * Copyright (c) 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 7023233
27 * @summary False positive for -Xlint:try with nested try with resources blocks
28 */
30 import com.sun.source.util.JavacTask;
31 import com.sun.tools.javac.api.ClientCodeWrapper;
32 import com.sun.tools.javac.api.JavacTool;
33 import com.sun.tools.javac.util.JCDiagnostic;
34 import java.net.URI;
35 import java.util.Arrays;
36 import javax.tools.Diagnostic;
37 import javax.tools.JavaCompiler;
38 import javax.tools.JavaFileObject;
39 import javax.tools.SimpleJavaFileObject;
40 import javax.tools.StandardJavaFileManager;
41 import javax.tools.ToolProvider;
43 public class UnusedResourcesTest {
45 enum XlintOption {
46 NONE("none"),
47 TRY("try");
49 String opt;
51 XlintOption(String opt) {
52 this.opt = opt;
53 }
55 String getXlintOption() {
56 return "-Xlint:" + opt;
57 }
58 }
60 enum TwrStmt {
61 TWR1("res1"),
62 TWR2("res2"),
63 TWR3("res3");
65 final String resourceName;
67 private TwrStmt(String resourceName) {
68 this.resourceName = resourceName;
69 }
70 }
72 enum SuppressLevel {
73 NONE,
74 SUPPRESS;
76 String getSuppressAnno() {
77 return this == SUPPRESS ?
78 "@SuppressWarnings(\"try\")" :
79 "";
80 }
81 }
83 enum ResourceUsage {
84 NONE(null),
85 USE_R1(TwrStmt.TWR1),
86 USE_R2(TwrStmt.TWR2),
87 USE_R3(TwrStmt.TWR3);
89 TwrStmt stmt;
91 private ResourceUsage(TwrStmt stmt) {
92 this.stmt = stmt;
93 }
95 String usedResourceName() {
96 return stmt != null ? stmt.resourceName : null;
97 }
99 boolean isUsedIn(TwrStmt res, TwrStmt stmt) {
100 return this.stmt == res &&
101 stmt.ordinal() >= this.stmt.ordinal();
102 }
104 String getUsage(TwrStmt stmt) {
105 return this != NONE && stmt.ordinal() >= this.stmt.ordinal() ?
106 "use(" + usedResourceName() + ");" :
107 "";
108 }
109 }
111 static class JavaSource extends SimpleJavaFileObject {
113 String template = "class Resource implements AutoCloseable {\n" +
114 "public void close() {}\n" +
115 "}\n" +
116 "class Test {\n" +
117 "void use(Resource r) {}\n" +
118 "#S void test() {\n" +
119 "try (Resource #R1 = new Resource()) {\n" +
120 "#U1_R1\n" +
121 "#U1_R2\n" +
122 "#U1_R3\n" +
123 "try (Resource #R2 = new Resource()) {\n" +
124 "#U2_R1\n" +
125 "#U2_R2\n" +
126 "#U2_R3\n" +
127 "try (Resource #R3 = new Resource()) {\n" +
128 "#U3_R1\n" +
129 "#U3_R2\n" +
130 "#U3_R3\n" +
131 "}\n" +
132 "}\n" +
133 "}\n" +
134 "}\n" +
135 "}\n";
137 String source;
139 public JavaSource(SuppressLevel suppressLevel, ResourceUsage usage1,
140 ResourceUsage usage2, ResourceUsage usage3) {
141 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
142 source = template.replace("#S", suppressLevel.getSuppressAnno()).
143 replace("#R1", TwrStmt.TWR1.resourceName).
144 replace("#R2", TwrStmt.TWR2.resourceName).
145 replace("#R3", TwrStmt.TWR3.resourceName).
146 replace("#U1_R1", usage1.getUsage(TwrStmt.TWR1)).
147 replace("#U1_R2", usage2.getUsage(TwrStmt.TWR1)).
148 replace("#U1_R3", usage3.getUsage(TwrStmt.TWR1)).
149 replace("#U2_R1", usage1.getUsage(TwrStmt.TWR2)).
150 replace("#U2_R2", usage2.getUsage(TwrStmt.TWR2)).
151 replace("#U2_R3", usage3.getUsage(TwrStmt.TWR2)).
152 replace("#U3_R1", usage1.getUsage(TwrStmt.TWR3)).
153 replace("#U3_R2", usage2.getUsage(TwrStmt.TWR3)).
154 replace("#U3_R3", usage3.getUsage(TwrStmt.TWR3));
155 }
157 @Override
158 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
159 return source;
160 }
161 }
163 public static void main(String... args) throws Exception {
164 for (XlintOption xlint : XlintOption.values()) {
165 for (SuppressLevel suppressLevel : SuppressLevel.values()) {
166 for (ResourceUsage usage1 : ResourceUsage.values()) {
167 for (ResourceUsage usage2 : ResourceUsage.values()) {
168 for (ResourceUsage usage3 : ResourceUsage.values()) {
169 test(xlint,
170 suppressLevel,
171 usage1,
172 usage2,
173 usage3);
174 }
175 }
176 }
177 }
178 }
179 }
181 // Create a single file manager and reuse it for each compile to save time.
182 static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
184 static void test(XlintOption xlint, SuppressLevel suppressLevel, ResourceUsage usage1,
185 ResourceUsage usage2, ResourceUsage usage3) throws Exception {
186 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
187 JavaSource source = new JavaSource(suppressLevel, usage1, usage2, usage3);
188 DiagnosticChecker dc = new DiagnosticChecker();
189 JavacTask ct = (JavacTask)tool.getTask(null, fm, dc,
190 Arrays.asList(xlint.getXlintOption()), null, Arrays.asList(source));
191 ct.analyze();
192 check(source, xlint, suppressLevel, usage1, usage2, usage3, dc);
193 }
195 static void check(JavaSource source, XlintOption xlint, SuppressLevel suppressLevel,
196 ResourceUsage usage1, ResourceUsage usage2, ResourceUsage usage3, DiagnosticChecker dc) {
198 ResourceUsage[] usages = { usage1, usage2, usage3 };
199 boolean[] unusedFound = { dc.unused_r1, dc.unused_r2, dc.unused_r3 };
200 boolean[] usedResources = { false, false, false };
202 for (TwrStmt res : TwrStmt.values()) {
203 outer: for (TwrStmt stmt : TwrStmt.values()) {
204 for (ResourceUsage usage : usages) {
205 if (usage.isUsedIn(res, stmt)) {
206 usedResources[res.ordinal()] = true;
207 break outer;
208 }
209 }
210 }
211 }
213 for (TwrStmt stmt : TwrStmt.values()) {
214 boolean unused = !usedResources[stmt.ordinal()] &&
215 xlint == XlintOption.TRY &&
216 suppressLevel != SuppressLevel.SUPPRESS;
217 if (unused != unusedFound[stmt.ordinal()]) {
218 throw new Error("invalid diagnostics for source:\n" +
219 source.getCharContent(true) +
220 "\nOptions: " + xlint.getXlintOption() +
221 "\nFound unused res1: " + unusedFound[0] +
222 "\nFound unused res2: " + unusedFound[1] +
223 "\nFound unused res3: " + unusedFound[2] +
224 "\nExpected unused res1: " + !usedResources[0] +
225 "\nExpected unused res2: " + !usedResources[1] +
226 "\nExpected unused res3: " + !usedResources[2]);
227 }
228 }
229 }
231 static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
233 boolean unused_r1 = false;
234 boolean unused_r2 = false;
235 boolean unused_r3 = false;
237 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
238 if (diagnostic.getKind() == Diagnostic.Kind.WARNING &&
239 diagnostic.getCode().contains("try.resource.not.referenced")) {
240 String varName = unwrap(diagnostic).getArgs()[0].toString();
241 if (varName.equals(TwrStmt.TWR1.resourceName)) {
242 unused_r1 = true;
243 } else if (varName.equals(TwrStmt.TWR2.resourceName)) {
244 unused_r2 = true;
245 } else if (varName.equals(TwrStmt.TWR3.resourceName)) {
246 unused_r3 = true;
247 }
248 }
249 }
251 private JCDiagnostic unwrap(Diagnostic<? extends JavaFileObject> diagnostic) {
252 if (diagnostic instanceof JCDiagnostic)
253 return (JCDiagnostic) diagnostic;
254 if (diagnostic instanceof ClientCodeWrapper.DiagnosticSourceUnwrapper)
255 return ((ClientCodeWrapper.DiagnosticSourceUnwrapper)diagnostic).d;
256 throw new IllegalArgumentException();
257 }
258 }
259 }