| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.codehaus.groovy.control; |
| |
| import org.codehaus.groovy.control.messages.ExceptionMessage; |
| import org.codehaus.groovy.control.messages.LocatedMessage; |
| import org.codehaus.groovy.control.messages.Message; |
| import org.codehaus.groovy.control.messages.SyntaxErrorMessage; |
| import org.codehaus.groovy.control.messages.WarningMessage; |
| import org.codehaus.groovy.syntax.CSTNode; |
| import org.codehaus.groovy.syntax.SyntaxException; |
| |
| import java.io.PrintWriter; |
| import java.io.Serializable; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| /** |
| * A base class for collecting messages and errors during processing. |
| * Each CompilationUnit should have an ErrorCollector, and the SourceUnits |
| * should share their ErrorCollector with the CompilationUnit. |
| */ |
| public class ErrorCollector implements Serializable { |
| |
| private static final long serialVersionUID = 2844774170905056755L; |
| /** |
| * WarningMessages collected during processing |
| */ |
| protected LinkedList warnings; |
| /** |
| * ErrorMessages collected during processing |
| */ |
| protected LinkedList errors; |
| /** |
| * Configuration and other settings that control processing |
| */ |
| protected CompilerConfiguration configuration; |
| |
| /** |
| * Initialize the ErrorReporter. |
| */ |
| public ErrorCollector(CompilerConfiguration configuration) { |
| this.warnings = null; |
| this.errors = null; |
| |
| this.configuration = configuration; |
| } |
| |
| public void addCollectorContents(ErrorCollector er) { |
| if (er.errors!=null) { |
| if (errors==null) { |
| errors = er.errors; |
| } else { |
| errors.addAll(er.errors); |
| } |
| } |
| if (er.warnings!=null) { |
| if (warnings==null) { |
| warnings = er.warnings; |
| } else { |
| warnings.addAll(er.warnings); |
| } |
| } |
| } |
| |
| public void addErrorAndContinue(SyntaxException error, SourceUnit source) throws CompilationFailedException { |
| addErrorAndContinue(Message.create(error, source)); |
| } |
| |
| /** |
| * Adds an error to the message set, but does not cause a failure. The message is not required to have a source |
| * line and column specified, but it is best practice to try and include that information. |
| */ |
| public void addErrorAndContinue(Message message) { |
| if (this.errors == null) { |
| this.errors = new LinkedList(); |
| } |
| |
| this.errors.add(message); |
| } |
| |
| /** |
| * Adds a non-fatal error to the message set, which may cause a failure if the error threshold is exceeded. |
| * The message is not required to have a source line and column specified, but it is best practice to try |
| * and include that information. |
| */ |
| public void addError(Message message) throws CompilationFailedException { |
| addErrorAndContinue(message); |
| |
| if (errors!=null && this.errors.size() >= configuration.getTolerance()) { |
| failIfErrors(); |
| } |
| } |
| |
| /** |
| * Adds an optionally-fatal error to the message set. |
| * The message is not required to have a source line and column specified, but it is best practice to try |
| * and include that information. |
| * @param fatal |
| * if true then then processing will stop |
| */ |
| public void addError(Message message, boolean fatal) throws CompilationFailedException { |
| if (fatal) { |
| addFatalError(message); |
| } |
| else { |
| addError(message); |
| } |
| } |
| |
| |
| /** |
| * Convenience wrapper for addError(). |
| */ |
| public void addError(SyntaxException error, SourceUnit source) throws CompilationFailedException { |
| addError(Message.create(error, source), error.isFatal()); |
| } |
| |
| |
| /** |
| * Convenience wrapper for addError(). |
| */ |
| public void addError(String text, CSTNode context, SourceUnit source) throws CompilationFailedException { |
| addError(new LocatedMessage(text, context, source)); |
| } |
| |
| |
| /** |
| * Adds a fatal exception to the message set and throws |
| * the unit as a PhaseFailedException. |
| */ |
| public void addFatalError(Message message) throws CompilationFailedException { |
| addError(message); |
| failIfErrors(); |
| } |
| |
| |
| public void addException(Exception cause, SourceUnit source) throws CompilationFailedException { |
| addError(new ExceptionMessage(cause,configuration.getDebug(),source)); |
| failIfErrors(); |
| } |
| |
| /** |
| * Returns true if there are any errors pending. |
| */ |
| public boolean hasErrors() { |
| return this.errors != null; |
| } |
| |
| /** |
| * @return the compiler configuration used to create this error collector |
| */ |
| public CompilerConfiguration getConfiguration() { |
| return configuration; |
| } |
| |
| /** |
| * Returns true if there are any warnings pending. |
| */ |
| public boolean hasWarnings() { |
| return this.warnings != null; |
| } |
| |
| /** |
| * Returns the list of warnings, or null if there are none. |
| */ |
| public List getWarnings() { |
| return this.warnings; |
| } |
| |
| /** |
| * Returns the list of errors, or null if there are none. |
| */ |
| public List getErrors() { |
| return this.errors; |
| } |
| |
| /** |
| * Returns the number of warnings. |
| */ |
| public int getWarningCount() { |
| return ((this.warnings == null) ? 0 : this.warnings.size()); |
| } |
| |
| /** |
| * Returns the number of errors. |
| */ |
| public int getErrorCount() { |
| return ((this.errors == null) ? 0 : this.errors.size()); |
| } |
| |
| /** |
| * Returns the specified warning message, or null. |
| */ |
| public WarningMessage getWarning(int index) { |
| if (index < getWarningCount()) { |
| return (WarningMessage) this.warnings.get(index); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the specified error message, or null. |
| */ |
| public Message getError(int index) { |
| if (index < getErrorCount()) { |
| return (Message) this.errors.get(index); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the last error reported |
| */ |
| public Message getLastError() { |
| return (Message) this.errors.getLast(); |
| } |
| |
| /** |
| * Convenience routine to return the specified error's |
| * underlying SyntaxException, or null if it isn't one. |
| */ |
| public SyntaxException getSyntaxError(int index) { |
| SyntaxException exception = null; |
| |
| Message message = getError(index); |
| if (message instanceof SyntaxErrorMessage) { |
| exception = ((SyntaxErrorMessage) message).getCause(); |
| } |
| return exception; |
| } |
| |
| /** |
| * Convenience routine to return the specified error's |
| * underlying Exception, or null if it isn't one. |
| */ |
| public Exception getException(int index) { |
| Exception exception = null; |
| |
| Message message = getError(index); |
| if (message != null) { |
| if (message instanceof ExceptionMessage) { |
| exception = ((ExceptionMessage) message).getCause(); |
| } |
| else if (message instanceof SyntaxErrorMessage) { |
| exception = ((SyntaxErrorMessage) message).getCause(); |
| } |
| } |
| return exception; |
| } |
| |
| /** |
| * Adds a WarningMessage to the message set. |
| */ |
| public void addWarning(WarningMessage message) { |
| if (message.isRelevant(configuration.getWarningLevel())) { |
| if (this.warnings == null) { |
| this.warnings = new LinkedList(); |
| } |
| |
| this.warnings.add(message); |
| } |
| } |
| |
| |
| /** |
| * Convenience wrapper for addWarning() that won't create an object |
| * unless it is relevant. |
| */ |
| public void addWarning(int importance, String text, CSTNode context, SourceUnit source) { |
| if (WarningMessage.isRelevant(importance, configuration.getWarningLevel())) { |
| addWarning(new WarningMessage(importance, text, context, source)); |
| } |
| } |
| |
| |
| /** |
| * Convenience wrapper for addWarning() that won't create an object |
| * unless it is relevant. |
| */ |
| public void addWarning(int importance, String text, Object data, CSTNode context, SourceUnit source) { |
| if (WarningMessage.isRelevant(importance, configuration.getWarningLevel())) { |
| addWarning(new WarningMessage(importance, text, data, context, source)); |
| } |
| } |
| |
| |
| /** |
| * Causes the current phase to fail by throwing a |
| * CompilationFailedException. |
| */ |
| protected void failIfErrors() throws CompilationFailedException { |
| if (hasErrors()) { |
| throw new MultipleCompilationErrorsException(this); |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| // OUTPUT |
| |
| |
| private void write(PrintWriter writer, Janitor janitor, List messages, String txt) { |
| if (messages==null || messages.isEmpty()) return; |
| Iterator iterator = messages.iterator(); |
| while (iterator.hasNext()) { |
| Message message = (Message) iterator.next(); |
| message.write(writer, janitor); |
| |
| if (configuration.getDebug() && (message instanceof SyntaxErrorMessage)){ |
| SyntaxErrorMessage sem = (SyntaxErrorMessage) message; |
| sem.getCause().printStackTrace(writer); |
| } |
| writer.println(); |
| } |
| |
| writer.print(messages.size()); |
| writer.print(" "+txt); |
| if (messages.size()>1) writer.print("s"); |
| writer.println(); |
| } |
| |
| /** |
| * Writes error messages to the specified PrintWriter. |
| */ |
| public void write(PrintWriter writer, Janitor janitor) { |
| write(writer,janitor,warnings,"warning"); |
| write(writer,janitor,errors,"error"); |
| } |
| |
| } |