Tue, 29 Mar 2011 16:41:18 +0100
7027157: Project Coin: javac warnings for AutoCloseable.close throwing InterruptedException
Summary: javac should warn about use/declaration of AutoCloseable subclasses that can throw InterruptedException
Reviewed-by: jjg
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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
27 package com.sun.tools.javac.api;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.OutputStream;
32 import java.io.Reader;
33 import java.io.Writer;
34 import java.net.URI;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
43 import javax.lang.model.element.NestingKind;
44 import javax.tools.Diagnostic;
45 import javax.tools.FileObject;
46 import javax.tools.JavaFileManager;
47 import javax.tools.JavaFileManager.Location;
48 import javax.tools.JavaFileObject;
50 import com.sun.source.util.TaskEvent;
51 import com.sun.source.util.TaskListener;
52 import com.sun.tools.javac.util.ClientCodeException;
53 import com.sun.tools.javac.util.Context;
54 import java.lang.annotation.ElementType;
55 import java.lang.annotation.Retention;
56 import java.lang.annotation.RetentionPolicy;
57 import java.lang.annotation.Target;
58 import javax.lang.model.element.Modifier;
59 import javax.tools.DiagnosticListener;
60 import javax.tools.JavaFileObject.Kind;
62 /**
63 * Wrap objects to enable unchecked exceptions to be caught and handled.
64 *
65 * For each method, exceptions are handled as follows:
66 * <ul>
67 * <li>Checked exceptions are left alone and propogate upwards in the
68 * obvious way, since they are an expected aspect of the method's
69 * specification.
70 * <li>Unchecked exceptions which have already been caught and wrapped in
71 * ClientCodeException are left alone to continue propogating upwards.
72 * <li>All other unchecked exceptions (i.e. subtypes of RuntimeException
73 * and Error) and caught, and rethrown as a ClientCodeException with
74 * its cause set to the original exception.
75 * </ul>
76 *
77 * The intent is that ClientCodeException can be caught at an appropriate point
78 * in the program and can be distinguished from any unanticipated unchecked
79 * exceptions arising in the main body of the code (i.e. bugs.) When the
80 * ClientCodeException has been caught, either a suitable message can be
81 * generated, or if appropriate, the original cause can be rethrown.
82 *
83 * <p><b>This is NOT part of any supported API.
84 * If you write code that depends on this, you do so at your own risk.
85 * This code and its internal interfaces are subject to change or
86 * deletion without notice.</b>
87 */
88 public class ClientCodeWrapper {
89 @Retention(RetentionPolicy.RUNTIME)
90 @Target(ElementType.TYPE)
91 public @interface Trusted { }
93 public static ClientCodeWrapper instance(Context context) {
94 ClientCodeWrapper instance = context.get(ClientCodeWrapper.class);
95 if (instance == null)
96 instance = new ClientCodeWrapper(context);
97 return instance;
98 }
100 /**
101 * A map to cache the results of whether or not a specific classes can
102 * be "trusted", and thus does not need to be wrapped.
103 */
104 Map<Class<?>, Boolean> trustedClasses;
106 protected ClientCodeWrapper(Context context) {
107 trustedClasses = new HashMap<Class<?>, Boolean>();
108 }
110 public JavaFileManager wrap(JavaFileManager fm) {
111 if (isTrusted(fm))
112 return fm;
113 return new WrappedJavaFileManager(fm);
114 }
116 public FileObject wrap(FileObject fo) {
117 if (isTrusted(fo))
118 return fo;
119 return new WrappedFileObject(fo);
120 }
122 FileObject unwrap(FileObject fo) {
123 if (fo instanceof WrappedFileObject)
124 return ((WrappedFileObject) fo).clientFileObject;
125 else
126 return fo;
127 }
129 public JavaFileObject wrap(JavaFileObject fo) {
130 if (isTrusted(fo))
131 return fo;
132 return new WrappedJavaFileObject(fo);
133 }
135 public Iterable<JavaFileObject> wrapJavaFileObjects(Iterable<? extends JavaFileObject> list) {
136 List<JavaFileObject> wrapped = new ArrayList<JavaFileObject>();
137 for (JavaFileObject fo : list)
138 wrapped.add(wrap(fo));
139 return Collections.unmodifiableList(wrapped);
140 }
142 JavaFileObject unwrap(JavaFileObject fo) {
143 if (fo instanceof WrappedJavaFileObject)
144 return ((JavaFileObject) ((WrappedJavaFileObject) fo).clientFileObject);
145 else
146 return fo;
147 }
149 <T> DiagnosticListener<T> wrap(DiagnosticListener<T> dl) {
150 if (isTrusted(dl))
151 return dl;
152 return new WrappedDiagnosticListener<T>(dl);
153 }
155 TaskListener wrap(TaskListener tl) {
156 if (isTrusted(tl))
157 return tl;
158 return new WrappedTaskListener(tl);
159 }
161 protected boolean isTrusted(Object o) {
162 Class<?> c = o.getClass();
163 Boolean trusted = trustedClasses.get(c);
164 if (trusted == null) {
165 trusted = c.getName().startsWith("com.sun.tools.javac.")
166 || c.isAnnotationPresent(Trusted.class);
167 trustedClasses.put(c, trusted);
168 }
169 return trusted;
170 }
172 // <editor-fold defaultstate="collapsed" desc="Wrapper classes">
174 // FIXME: all these classes should be converted to use multi-catch when
175 // that is available in the bootstrap compiler.
177 protected class WrappedJavaFileManager implements JavaFileManager {
178 protected JavaFileManager clientJavaFileManager;
179 WrappedJavaFileManager(JavaFileManager clientJavaFileManager) {
180 clientJavaFileManager.getClass(); // null check
181 this.clientJavaFileManager = clientJavaFileManager;
182 }
184 @Override
185 public ClassLoader getClassLoader(Location location) {
186 try {
187 return clientJavaFileManager.getClassLoader(location);
188 } catch (ClientCodeException e) {
189 throw e;
190 } catch (RuntimeException e) {
191 throw new ClientCodeException(e);
192 } catch (Error e) {
193 throw new ClientCodeException(e);
194 }
195 }
197 @Override
198 public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException {
199 try {
200 return wrapJavaFileObjects(clientJavaFileManager.list(location, packageName, kinds, recurse));
201 } catch (ClientCodeException e) {
202 throw e;
203 } catch (RuntimeException e) {
204 throw new ClientCodeException(e);
205 } catch (Error e) {
206 throw new ClientCodeException(e);
207 }
208 }
210 @Override
211 public String inferBinaryName(Location location, JavaFileObject file) {
212 try {
213 return clientJavaFileManager.inferBinaryName(location, unwrap(file));
214 } catch (ClientCodeException e) {
215 throw e;
216 } catch (RuntimeException e) {
217 throw new ClientCodeException(e);
218 } catch (Error e) {
219 throw new ClientCodeException(e);
220 }
221 }
223 @Override
224 public boolean isSameFile(FileObject a, FileObject b) {
225 try {
226 return clientJavaFileManager.isSameFile(unwrap(a), unwrap(b));
227 } catch (ClientCodeException e) {
228 throw e;
229 } catch (RuntimeException e) {
230 throw new ClientCodeException(e);
231 } catch (Error e) {
232 throw new ClientCodeException(e);
233 }
234 }
236 @Override
237 public boolean handleOption(String current, Iterator<String> remaining) {
238 try {
239 return clientJavaFileManager.handleOption(current, remaining);
240 } catch (ClientCodeException e) {
241 throw e;
242 } catch (RuntimeException e) {
243 throw new ClientCodeException(e);
244 } catch (Error e) {
245 throw new ClientCodeException(e);
246 }
247 }
249 @Override
250 public boolean hasLocation(Location location) {
251 try {
252 return clientJavaFileManager.hasLocation(location);
253 } catch (ClientCodeException e) {
254 throw e;
255 } catch (RuntimeException e) {
256 throw new ClientCodeException(e);
257 } catch (Error e) {
258 throw new ClientCodeException(e);
259 }
260 }
262 @Override
263 public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException {
264 try {
265 return wrap(clientJavaFileManager.getJavaFileForInput(location, className, kind));
266 } catch (ClientCodeException e) {
267 throw e;
268 } catch (RuntimeException e) {
269 throw new ClientCodeException(e);
270 } catch (Error e) {
271 throw new ClientCodeException(e);
272 }
273 }
275 @Override
276 public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
277 try {
278 return wrap(clientJavaFileManager.getJavaFileForOutput(location, className, kind, unwrap(sibling)));
279 } catch (ClientCodeException e) {
280 throw e;
281 } catch (RuntimeException e) {
282 throw new ClientCodeException(e);
283 } catch (Error e) {
284 throw new ClientCodeException(e);
285 }
286 }
288 @Override
289 public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
290 try {
291 return wrap(clientJavaFileManager.getFileForInput(location, packageName, relativeName));
292 } catch (ClientCodeException e) {
293 throw e;
294 } catch (RuntimeException e) {
295 throw new ClientCodeException(e);
296 } catch (Error e) {
297 throw new ClientCodeException(e);
298 }
299 }
301 @Override
302 public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
303 try {
304 return wrap(clientJavaFileManager.getFileForOutput(location, packageName, relativeName, unwrap(sibling)));
305 } catch (ClientCodeException e) {
306 throw e;
307 } catch (RuntimeException e) {
308 throw new ClientCodeException(e);
309 } catch (Error e) {
310 throw new ClientCodeException(e);
311 }
312 }
314 @Override
315 public void flush() throws IOException {
316 try {
317 clientJavaFileManager.flush();
318 } catch (ClientCodeException e) {
319 throw e;
320 } catch (RuntimeException e) {
321 throw new ClientCodeException(e);
322 } catch (Error e) {
323 throw new ClientCodeException(e);
324 }
325 }
327 @Override
328 public void close() throws IOException {
329 try {
330 clientJavaFileManager.close();
331 } catch (ClientCodeException e) {
332 throw e;
333 } catch (RuntimeException e) {
334 throw new ClientCodeException(e);
335 } catch (Error e) {
336 throw new ClientCodeException(e);
337 }
338 }
340 @Override
341 public int isSupportedOption(String option) {
342 try {
343 return clientJavaFileManager.isSupportedOption(option);
344 } catch (ClientCodeException e) {
345 throw e;
346 } catch (RuntimeException e) {
347 throw new ClientCodeException(e);
348 } catch (Error e) {
349 throw new ClientCodeException(e);
350 }
351 }
352 }
354 protected class WrappedFileObject implements FileObject {
355 protected FileObject clientFileObject;
356 WrappedFileObject(FileObject clientFileObject) {
357 clientFileObject.getClass(); // null check
358 this.clientFileObject = clientFileObject;
359 }
361 @Override
362 public URI toUri() {
363 try {
364 return clientFileObject.toUri();
365 } catch (ClientCodeException e) {
366 throw e;
367 } catch (RuntimeException e) {
368 throw new ClientCodeException(e);
369 } catch (Error e) {
370 throw new ClientCodeException(e);
371 }
372 }
374 @Override
375 public String getName() {
376 try {
377 return clientFileObject.getName();
378 } catch (ClientCodeException e) {
379 throw e;
380 } catch (RuntimeException e) {
381 throw new ClientCodeException(e);
382 } catch (Error e) {
383 throw new ClientCodeException(e);
384 }
385 }
387 @Override
388 public InputStream openInputStream() throws IOException {
389 try {
390 return clientFileObject.openInputStream();
391 } catch (ClientCodeException e) {
392 throw e;
393 } catch (RuntimeException e) {
394 throw new ClientCodeException(e);
395 } catch (Error e) {
396 throw new ClientCodeException(e);
397 }
398 }
400 @Override
401 public OutputStream openOutputStream() throws IOException {
402 try {
403 return clientFileObject.openOutputStream();
404 } catch (ClientCodeException e) {
405 throw e;
406 } catch (RuntimeException e) {
407 throw new ClientCodeException(e);
408 } catch (Error e) {
409 throw new ClientCodeException(e);
410 }
411 }
413 @Override
414 public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
415 try {
416 return clientFileObject.openReader(ignoreEncodingErrors);
417 } catch (ClientCodeException e) {
418 throw e;
419 } catch (RuntimeException e) {
420 throw new ClientCodeException(e);
421 } catch (Error e) {
422 throw new ClientCodeException(e);
423 }
424 }
426 @Override
427 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
428 try {
429 return clientFileObject.getCharContent(ignoreEncodingErrors);
430 } catch (ClientCodeException e) {
431 throw e;
432 } catch (RuntimeException e) {
433 throw new ClientCodeException(e);
434 } catch (Error e) {
435 throw new ClientCodeException(e);
436 }
437 }
439 @Override
440 public Writer openWriter() throws IOException {
441 try {
442 return clientFileObject.openWriter();
443 } catch (ClientCodeException e) {
444 throw e;
445 } catch (RuntimeException e) {
446 throw new ClientCodeException(e);
447 } catch (Error e) {
448 throw new ClientCodeException(e);
449 }
450 }
452 @Override
453 public long getLastModified() {
454 try {
455 return clientFileObject.getLastModified();
456 } catch (ClientCodeException e) {
457 throw e;
458 } catch (RuntimeException e) {
459 throw new ClientCodeException(e);
460 } catch (Error e) {
461 throw new ClientCodeException(e);
462 }
463 }
465 @Override
466 public boolean delete() {
467 try {
468 return clientFileObject.delete();
469 } catch (ClientCodeException e) {
470 throw e;
471 } catch (RuntimeException e) {
472 throw new ClientCodeException(e);
473 } catch (Error e) {
474 throw new ClientCodeException(e);
475 }
476 }
477 }
479 protected class WrappedJavaFileObject extends WrappedFileObject implements JavaFileObject {
480 WrappedJavaFileObject(JavaFileObject clientJavaFileObject) {
481 super(clientJavaFileObject);
482 }
484 @Override
485 public Kind getKind() {
486 try {
487 return ((JavaFileObject)clientFileObject).getKind();
488 } catch (ClientCodeException e) {
489 throw e;
490 } catch (RuntimeException e) {
491 throw new ClientCodeException(e);
492 } catch (Error e) {
493 throw new ClientCodeException(e);
494 }
495 }
497 @Override
498 public boolean isNameCompatible(String simpleName, Kind kind) {
499 try {
500 return ((JavaFileObject)clientFileObject).isNameCompatible(simpleName, kind);
501 } catch (ClientCodeException e) {
502 throw e;
503 } catch (RuntimeException e) {
504 throw new ClientCodeException(e);
505 } catch (Error e) {
506 throw new ClientCodeException(e);
507 }
508 }
510 @Override
511 public NestingKind getNestingKind() {
512 try {
513 return ((JavaFileObject)clientFileObject).getNestingKind();
514 } catch (ClientCodeException e) {
515 throw e;
516 } catch (RuntimeException e) {
517 throw new ClientCodeException(e);
518 } catch (Error e) {
519 throw new ClientCodeException(e);
520 }
521 }
523 @Override
524 public Modifier getAccessLevel() {
525 try {
526 return ((JavaFileObject)clientFileObject).getAccessLevel();
527 } catch (ClientCodeException e) {
528 throw e;
529 } catch (RuntimeException e) {
530 throw new ClientCodeException(e);
531 } catch (Error e) {
532 throw new ClientCodeException(e);
533 }
534 }
535 }
537 protected class WrappedDiagnosticListener<T> implements DiagnosticListener<T> {
538 protected DiagnosticListener<T> clientDiagnosticListener;
539 WrappedDiagnosticListener(DiagnosticListener<T> clientDiagnosticListener) {
540 clientDiagnosticListener.getClass(); // null check
541 this.clientDiagnosticListener = clientDiagnosticListener;
542 }
544 @Override
545 public void report(Diagnostic<? extends T> diagnostic) {
546 try {
547 clientDiagnosticListener.report(diagnostic);
548 } catch (ClientCodeException e) {
549 throw e;
550 } catch (RuntimeException e) {
551 throw new ClientCodeException(e);
552 } catch (Error e) {
553 throw new ClientCodeException(e);
554 }
555 }
556 }
558 protected class WrappedTaskListener implements TaskListener {
559 protected TaskListener clientTaskListener;
560 WrappedTaskListener(TaskListener clientTaskListener) {
561 clientTaskListener.getClass(); // null check
562 this.clientTaskListener = clientTaskListener;
563 }
565 @Override
566 public void started(TaskEvent ev) {
567 try {
568 clientTaskListener.started(ev);
569 } catch (ClientCodeException e) {
570 throw e;
571 } catch (RuntimeException e) {
572 throw new ClientCodeException(e);
573 } catch (Error e) {
574 throw new ClientCodeException(e);
575 }
576 }
578 @Override
579 public void finished(TaskEvent ev) {
580 try {
581 clientTaskListener.finished(ev);
582 } catch (ClientCodeException e) {
583 throw e;
584 } catch (RuntimeException e) {
585 throw new ClientCodeException(e);
586 } catch (Error e) {
587 throw new ClientCodeException(e);
588 }
589 }
590 }
592 // </editor-fold>
593 }