diff options
-rw-r--r-- | src/core/lombok/javac/CompilerMessageSuppressor.java | 286 | ||||
-rw-r--r-- | src/core/lombok/javac/JavacAST.java | 44 | ||||
-rw-r--r-- | src/core/lombok/javac/JavacResolution.java | 225 |
3 files changed, 295 insertions, 260 deletions
diff --git a/src/core/lombok/javac/CompilerMessageSuppressor.java b/src/core/lombok/javac/CompilerMessageSuppressor.java new file mode 100644 index 00000000..a17e0c62 --- /dev/null +++ b/src/core/lombok/javac/CompilerMessageSuppressor.java @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2011-2013 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.javac; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.util.LinkedList; +import java.util.Queue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileObject; + +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Log; + +/** + * During resolution, the resolver will emit resolution errors, but without appropriate file names and line numbers. If these resolution errors stick around + * then they will be generated AGAIN, this time with proper names and line numbers, at the end. Therefore, we want to suppress the logger. + */ +public final class CompilerMessageSuppressor { + private final Log log; + private static final Field errWriterField, warnWriterField, noticeWriterField, dumpOnErrorField, promptOnErrorField, diagnosticListenerField; + private static final Field deferDiagnosticsField, deferredDiagnosticsField, diagnosticHandlerField; + private static final ConcurrentMap<Class<?>, Field> handlerDeferredFields = new ConcurrentHashMap<Class<?>, Field>(); + private static final Field NULL_FIELD; + private PrintWriter errWriter, warnWriter, noticeWriter; + private Boolean dumpOnError, promptOnError; + private DiagnosticListener<?> contextDiagnosticListener, logDiagnosticListener; + private final Context context; + + // If this is true, the fields changed. Better to print weird error messages than to fail outright. + private static final boolean dontBother; + + private static final ThreadLocal<Queue<?>> queueCache = new ThreadLocal<Queue<?>>(); + + static { + errWriterField = getDeclaredField(Log.class, "errWriter"); + warnWriterField = getDeclaredField(Log.class, "warnWriter"); + noticeWriterField = getDeclaredField(Log.class, "noticeWriter"); + dumpOnErrorField = getDeclaredField(Log.class, "dumpOnError"); + promptOnErrorField = getDeclaredField(Log.class, "promptOnError"); + diagnosticListenerField = getDeclaredField(Log.class, "diagListener"); + + dontBother = + errWriterField == null || + warnWriterField == null || + noticeWriterField == null || + dumpOnErrorField == null || + promptOnErrorField == null || + diagnosticListenerField == null; + + + deferDiagnosticsField = getDeclaredField(Log.class, "deferDiagnostics"); + deferredDiagnosticsField = getDeclaredField(Log.class, "deferredDiagnostics"); + + // javac8 + diagnosticHandlerField = getDeclaredField(Log.class, "diagnosticHandler"); + + NULL_FIELD = getDeclaredField(JavacResolution.class, "NULL_FIELD"); + } + + static Field getDeclaredField(Class<?> c, String fieldName) { + try { + Field field = c.getDeclaredField(fieldName); + field.setAccessible(true); + return field; + } + catch (Throwable t) { + return null; + } + } + + public CompilerMessageSuppressor(Context context) { + this.log = Log.instance(context); + this.context = context; + } + + public boolean disableLoggers() { + contextDiagnosticListener = context.get(DiagnosticListener.class); + context.put(DiagnosticListener.class, (DiagnosticListener<?>) null); + if (dontBother) return false; + boolean dontBotherInstance = false; + + PrintWriter dummyWriter = new PrintWriter(new OutputStream() { + @Override public void write(int b) throws IOException { + // Do nothing on purpose + } + }); + + if (deferDiagnosticsField != null) try { + if (Boolean.TRUE.equals(deferDiagnosticsField.get(log))) { + queueCache.set((Queue<?>) deferredDiagnosticsField.get(log)); + Queue<?> empty = new LinkedList<Object>(); + deferredDiagnosticsField.set(log, empty); + } + } catch (Exception e) {} + + if (diagnosticHandlerField != null) try { + Object handler = diagnosticHandlerField.get(log); + Field field = getDeferredField(handler); + if (field != null) { + queueCache.set((Queue<?>) field.get(handler)); + Queue<?> empty = new LinkedList<Object>(); + field.set(handler, empty); + } + } catch (Exception e) {} + + if (!dontBotherInstance) try { + errWriter = (PrintWriter) errWriterField.get(log); + errWriterField.set(log, dummyWriter); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (!dontBotherInstance) try { + warnWriter = (PrintWriter) warnWriterField.get(log); + warnWriterField.set(log, dummyWriter); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (!dontBotherInstance) try { + noticeWriter = (PrintWriter) noticeWriterField.get(log); + noticeWriterField.set(log, dummyWriter); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (!dontBotherInstance) try { + dumpOnError = (Boolean) dumpOnErrorField.get(log); + dumpOnErrorField.set(log, false); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (!dontBotherInstance) try { + promptOnError = (Boolean) promptOnErrorField.get(log); + promptOnErrorField.set(log, false); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (!dontBotherInstance) try { + logDiagnosticListener = (DiagnosticListener<?>) diagnosticListenerField.get(log); + diagnosticListenerField.set(log, null); + } catch (Exception e) { + dontBotherInstance = true; + } + + if (dontBotherInstance) enableLoggers(); + return !dontBotherInstance; + } + + private static Field getDeferredField(Object handler) { + Class<? extends Object> key = handler.getClass(); + Field field = handlerDeferredFields.get(key); + if (field != null) { + return field == NULL_FIELD ? null : field; + } + Field value = getDeclaredField(key, "deferred"); + handlerDeferredFields.put(key, value == null ? NULL_FIELD : value); + return getDeferredField(handler); + } + + public void enableLoggers() { + if (contextDiagnosticListener != null) { + context.put(DiagnosticListener.class, contextDiagnosticListener); + contextDiagnosticListener = null; + } + + if (errWriter != null) try { + errWriterField.set(log, errWriter); + errWriter = null; + } catch (Exception e) {} + + if (warnWriter != null) try { + warnWriterField.set(log, warnWriter); + warnWriter = null; + } catch (Exception e) {} + + if (noticeWriter != null) try { + noticeWriterField.set(log, noticeWriter); + noticeWriter = null; + } catch (Exception e) {} + + if (dumpOnError != null) try { + dumpOnErrorField.set(log, dumpOnError); + dumpOnError = null; + } catch (Exception e) {} + + if (promptOnError != null) try { + promptOnErrorField.set(log, promptOnError); + promptOnError = null; + } catch (Exception e) {} + + if (logDiagnosticListener != null) try { + diagnosticListenerField.set(log, logDiagnosticListener); + logDiagnosticListener = null; + } catch (Exception e) {} + + if (diagnosticHandlerField != null && queueCache.get() != null) try { + Object handler = diagnosticHandlerField.get(log); + Field field = getDeferredField(handler); + if (field != null) { + field.set(handler, queueCache.get()); + queueCache.set(null); + } + } catch (Exception e) {} + + if (deferDiagnosticsField != null && queueCache.get() != null) try { + deferredDiagnosticsField.set(log, queueCache.get()); + queueCache.set(null); + } catch (Exception e) {} + } + + public void removeAllBetween(JavaFileObject sourcefile, int startPos, int endPos) { + DiagnosticListener<?> listener = context.get(DiagnosticListener.class); + if (listener instanceof CapturingDiagnosticListener) { + ((CapturingDiagnosticListener) listener).suppress(startPos, endPos); + } + + Field field = null; + Object receiver = null; + if (deferDiagnosticsField != null) try { + if (Boolean.TRUE.equals(deferDiagnosticsField.get(log))) { + field = deferredDiagnosticsField; + receiver = log; + } + } catch (Exception e) {} + + if (diagnosticHandlerField != null) try { + Object handler = diagnosticHandlerField.get(log); + field = getDeferredField(handler); + receiver = handler; + } catch (Exception e) {} + + if (field == null || receiver == null) return; + + try { + ListBuffer<?> deferredDiagnostics = (ListBuffer<?>) field.get(receiver); + ListBuffer<Object> newDeferredDiagnostics = new ListBuffer<Object>(); + for (Object diag_ : deferredDiagnostics) { + if (!(diag_ instanceof JCDiagnostic)) { + newDeferredDiagnostics.add(diag_); + continue; + } + JCDiagnostic diag = (JCDiagnostic) diag_; + long here = diag.getStartPosition(); + if (here >= startPos && here < endPos && diag.getSource() == sourcefile) { + // We eliminate it + } else { + newDeferredDiagnostics.add(diag); + } + } + field.set(receiver, newDeferredDiagnostics); + } catch (Exception e) { + // We do not expect failure here; if failure does occur, the best course of action is to silently continue; the result will be that the error output of + // javac will contain rather a lot of messages, but this is a lot better than just crashing during compilation! + } + } +}
\ No newline at end of file diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index 2422b553..31bdc3a6 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -29,7 +29,6 @@ import java.util.List; import javax.annotation.processing.Messager; import javax.tools.Diagnostic; -import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; import lombok.core.AST; @@ -53,8 +52,6 @@ import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.JCDiagnostic; -import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @@ -343,17 +340,6 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { if (node != null) nodes.add(node); } - private static final Field JAVAC7_DEFERRED_DIAGNOSTICS; - - static { - Field f = null; - try { - f = Log.class.getField("deferredDiagnostics"); - if (!ListBuffer.class.isAssignableFrom(f.getType())) throw new NoSuchFieldException("deferredDiagnostics does not have the expected type."); - } catch (NoSuchFieldException e) {} - JAVAC7_DEFERRED_DIAGNOSTICS = f; - } - /** * Attempts to remove any compiler errors generated by java whose reporting position is located anywhere between the start and end of the supplied node. */ @@ -400,34 +386,8 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { } private void removeFromDeferredDiagnostics(int startPos, int endPos) { - DiagnosticListener<?> listener = getContext().get(DiagnosticListener.class); - if (listener instanceof CapturingDiagnosticListener) { - ((CapturingDiagnosticListener) listener).suppress(startPos, endPos); - } - try { - // TODO: This changed a bit in java8; there is now also a Handler thingie; see JavacResolution for what changed. - // Possibly integrate these 2 code paths. - if (JAVAC7_DEFERRED_DIAGNOSTICS != null) { - ListBuffer<?> deferredDiagnostics = (ListBuffer<?>) JAVAC7_DEFERRED_DIAGNOSTICS.get(log); - ListBuffer<Object> newDeferredDiagnostics = new ListBuffer<Object>(); - for (Object diag : deferredDiagnostics) { - if (!(diag instanceof JCDiagnostic)) { - newDeferredDiagnostics.add(diag); - continue; - } - long here = ((JCDiagnostic) diag).getStartPosition(); - if (here >= startPos && here < endPos) { - // We eliminate it - } else { - newDeferredDiagnostics.add(diag); - } - } - JAVAC7_DEFERRED_DIAGNOSTICS.set(log, newDeferredDiagnostics); - } - } catch (Exception e) { - // We do not expect failure here; if failure does occur, the best course of action is to silently continue; the result will be that the error output of - // javac will contain rather a lot of messages, but this is a lot better than just crashing during compilation! - } + JCCompilationUnit self = (JCCompilationUnit) top().get(); + new CompilerMessageSuppressor(getContext()).removeAllBetween(self.sourcefile, startPos, endPos); } /** {@inheritDoc} */ diff --git a/src/core/lombok/javac/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java index acfca6a6..5631e62c 100644 --- a/src/core/lombok/javac/JavacResolution.java +++ b/src/core/lombok/javac/JavacResolution.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 The Project Lombok Authors. + * Copyright (C) 2011-2013 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,19 +24,10 @@ package lombok.javac; import static lombok.javac.Javac.*; import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.lang.reflect.Field; import java.util.ArrayDeque; -import java.util.LinkedList; import java.util.Map; -import java.util.Queue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import javax.lang.model.type.TypeKind; -import javax.tools.DiagnosticListener; import com.sun.tools.javac.code.BoundKind; import com.sun.tools.javac.code.Symbol.TypeSymbol; @@ -62,216 +53,14 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; -import com.sun.tools.javac.util.Log; public class JavacResolution { private final Attr attr; - private final LogDisabler logDisabler; + private final CompilerMessageSuppressor messageSuppressor; public JavacResolution(Context context) { attr = Attr.instance(context); - logDisabler = new LogDisabler(context); - } - - /** - * During resolution, the resolver will emit resolution errors, but without appropriate file names and line numbers. If these resolution errors stick around - * then they will be generated AGAIN, this time with proper names and line numbers, at the end. Therefore, we want to suppress the logger. - */ - private static final class LogDisabler { - private final Log log; - private static final Field errWriterField, warnWriterField, noticeWriterField, dumpOnErrorField, promptOnErrorField, diagnosticListenerField; - private static final Field deferDiagnosticsField, deferredDiagnosticsField, diagnosticHandlerField; - private static final ConcurrentMap<Class<?>, Field> handlerDeferredFields = new ConcurrentHashMap<Class<?>, Field>(); - private static final Field NULL_FIELD; - private PrintWriter errWriter, warnWriter, noticeWriter; - private Boolean dumpOnError, promptOnError; - private DiagnosticListener<?> contextDiagnosticListener, logDiagnosticListener; - private final Context context; - - // If this is true, the fields changed. Better to print weird error messages than to fail outright. - private static final boolean dontBother; - - private static final ThreadLocal<Queue<?>> queueCache = new ThreadLocal<Queue<?>>(); - - static { - errWriterField = getDeclaredField(Log.class, "errWriter"); - warnWriterField = getDeclaredField(Log.class, "warnWriter"); - noticeWriterField = getDeclaredField(Log.class, "noticeWriter"); - dumpOnErrorField = getDeclaredField(Log.class, "dumpOnError"); - promptOnErrorField = getDeclaredField(Log.class, "promptOnError"); - diagnosticListenerField = getDeclaredField(Log.class, "diagListener"); - - dontBother = - errWriterField == null || - warnWriterField == null || - noticeWriterField == null || - dumpOnErrorField == null || - promptOnErrorField == null || - diagnosticListenerField == null; - - - deferDiagnosticsField = getDeclaredField(Log.class, "deferDiagnostics"); - deferredDiagnosticsField = getDeclaredField(Log.class, "deferredDiagnostics"); - - // javac8 - diagnosticHandlerField = getDeclaredField(Log.class, "diagnosticHandler"); - - NULL_FIELD = getDeclaredField(JavacResolution.class, "NULL_FIELD"); - } - - static Field getDeclaredField(Class<?> c, String fieldName) { - try { - Field field = c.getDeclaredField(fieldName); - field.setAccessible(true); - return field; - } - catch (Throwable t) { - return null; - } - } - - LogDisabler(Context context) { - this.log = Log.instance(context); - this.context = context; - } - - boolean disableLoggers() { - contextDiagnosticListener = context.get(DiagnosticListener.class); - context.put(DiagnosticListener.class, (DiagnosticListener<?>) null); - if (dontBother) return false; - boolean dontBotherInstance = false; - - PrintWriter dummyWriter = new PrintWriter(new OutputStream() { - @Override public void write(int b) throws IOException { - // Do nothing on purpose - } - }); - - if (deferDiagnosticsField != null) try { - if (Boolean.TRUE.equals(deferDiagnosticsField.get(log))) { - queueCache.set((Queue<?>) deferredDiagnosticsField.get(log)); - Queue<?> empty = new LinkedList<Object>(); - deferredDiagnosticsField.set(log, empty); - } - } catch (Exception e) {} - - if (diagnosticHandlerField != null) try { - Object handler = diagnosticHandlerField.get(log); - Field field = getDeferredField(handler); - if (field != null) { - queueCache.set((Queue<?>) field.get(handler)); - Queue<?> empty = new LinkedList<Object>(); - field.set(handler, empty); - } - } catch (Exception e) {} - - if (!dontBotherInstance) try { - errWriter = (PrintWriter) errWriterField.get(log); - errWriterField.set(log, dummyWriter); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (!dontBotherInstance) try { - warnWriter = (PrintWriter) warnWriterField.get(log); - warnWriterField.set(log, dummyWriter); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (!dontBotherInstance) try { - noticeWriter = (PrintWriter) noticeWriterField.get(log); - noticeWriterField.set(log, dummyWriter); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (!dontBotherInstance) try { - dumpOnError = (Boolean) dumpOnErrorField.get(log); - dumpOnErrorField.set(log, false); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (!dontBotherInstance) try { - promptOnError = (Boolean) promptOnErrorField.get(log); - promptOnErrorField.set(log, false); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (!dontBotherInstance) try { - logDiagnosticListener = (DiagnosticListener<?>) diagnosticListenerField.get(log); - diagnosticListenerField.set(log, null); - } catch (Exception e) { - dontBotherInstance = true; - } - - if (dontBotherInstance) enableLoggers(); - return !dontBotherInstance; - } - - private static Field getDeferredField(Object handler) { - Class<? extends Object> key = handler.getClass(); - Field field = handlerDeferredFields.get(key); - if (field != null) { - return field == NULL_FIELD ? null : field; - } - Field value = getDeclaredField(key, "deferred"); - handlerDeferredFields.put(key, value == null ? NULL_FIELD : value); - return getDeferredField(handler); - } - - void enableLoggers() { - if (contextDiagnosticListener != null) { - context.put(DiagnosticListener.class, contextDiagnosticListener); - contextDiagnosticListener = null; - } - - if (errWriter != null) try { - errWriterField.set(log, errWriter); - errWriter = null; - } catch (Exception e) {} - - if (warnWriter != null) try { - warnWriterField.set(log, warnWriter); - warnWriter = null; - } catch (Exception e) {} - - if (noticeWriter != null) try { - noticeWriterField.set(log, noticeWriter); - noticeWriter = null; - } catch (Exception e) {} - - if (dumpOnError != null) try { - dumpOnErrorField.set(log, dumpOnError); - dumpOnError = null; - } catch (Exception e) {} - - if (promptOnError != null) try { - promptOnErrorField.set(log, promptOnError); - promptOnError = null; - } catch (Exception e) {} - - if (logDiagnosticListener != null) try { - diagnosticListenerField.set(log, logDiagnosticListener); - logDiagnosticListener = null; - } catch (Exception e) {} - - if (diagnosticHandlerField != null && queueCache.get() != null) try { - Object handler = diagnosticHandlerField.get(log); - Field field = getDeferredField(handler); - if (field != null) { - field.set(handler, queueCache.get()); - queueCache.set(null); - } - } catch (Exception e) {} - - if (deferDiagnosticsField != null && queueCache.get() != null) try { - deferredDiagnosticsField.set(log, queueCache.get()); - queueCache.set(null); - } catch (Exception e) {} - } + messageSuppressor = new CompilerMessageSuppressor(context); } /* @@ -351,7 +140,7 @@ public class JavacResolution { } } - logDisabler.disableLoggers(); + messageSuppressor.disableLoggers(); try { EnvFinder finder = new EnvFinder(node.getContext()); while (!stack.isEmpty()) stack.pop().accept(finder); @@ -362,7 +151,7 @@ public class JavacResolution { attrib(copy, finder.get()); return mirrorMaker.getOriginalToCopyMap(); } finally { - logDisabler.enableLoggers(); + messageSuppressor.enableLoggers(); } } @@ -377,14 +166,14 @@ public class JavacResolution { } } - logDisabler.disableLoggers(); + messageSuppressor.disableLoggers(); try { EnvFinder finder = new EnvFinder(node.getContext()); while (!stack.isEmpty()) stack.pop().accept(finder); attrib(node.get(), finder.get()); } finally { - logDisabler.enableLoggers(); + messageSuppressor.enableLoggers(); } } |