001 /*
002 $Id: ErrorCollector.java,v 1.5 2005/06/13 09:31:01 blackdrag Exp $
003
004 Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005
006 Redistribution and use of this software and associated documentation
007 ("Software"), with or without modification, are permitted provided
008 that the following conditions are met:
009
010 1. Redistributions of source code must retain copyright
011 statements and notices. Redistributions must also contain a
012 copy of this document.
013
014 2. Redistributions in binary form must reproduce the
015 above copyright notice, this list of conditions and the
016 following disclaimer in the documentation and/or other
017 materials provided with the distribution.
018
019 3. The name "groovy" must not be used to endorse or promote
020 products derived from this Software without prior written
021 permission of The Codehaus. For written permission,
022 please contact info@codehaus.org.
023
024 4. Products derived from this Software may not be called "groovy"
025 nor may "groovy" appear in their names without prior written
026 permission of The Codehaus. "groovy" is a registered
027 trademark of The Codehaus.
028
029 5. Due credit should be given to The Codehaus -
030 http://groovy.codehaus.org/
031
032 THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036 THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043 OF THE POSSIBILITY OF SUCH DAMAGE.
044
045 */
046
047 package org.codehaus.groovy.control;
048
049 import java.io.PrintWriter;
050 import java.util.Iterator;
051 import java.util.LinkedList;
052 import java.util.List;
053
054 import org.codehaus.groovy.control.messages.ExceptionMessage;
055 import org.codehaus.groovy.control.messages.LocatedMessage;
056 import org.codehaus.groovy.control.messages.Message;
057 import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
058 import org.codehaus.groovy.control.messages.WarningMessage;
059 import org.codehaus.groovy.syntax.CSTNode;
060 import org.codehaus.groovy.syntax.SyntaxException;
061
062 /**
063 * A base class for collecting messages and errors during processing.
064 * Each CompilationUnit should have one and SourceUnits should share
065 * their ErrorCollector with the CompilationUnit.
066 *
067 * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
068 * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
069 * @version $Id: ErrorCollector.java,v 1.5 2005/06/13 09:31:01 blackdrag Exp $
070 */
071 public class ErrorCollector {
072
073 /**
074 * WarningMessages collected during processing
075 */
076 protected LinkedList warnings;
077 /**
078 * ErrorMessages collected during processing
079 */
080 protected LinkedList errors;
081 /**
082 * Configuration and other settings that control processing
083 */
084 protected CompilerConfiguration configuration;
085
086 /**
087 * Initialize the ErrorReporter.
088 */
089 public ErrorCollector(CompilerConfiguration configuration) {
090 this.warnings = null;
091 this.errors = null;
092
093 this.configuration = configuration;
094 }
095
096 public void addCollectorContents(ErrorCollector er) {
097 if (er.errors!=null) {
098 if (errors==null) {
099 errors = er.errors;
100 } else {
101 errors.addAll(errors);
102 }
103 }
104 if (er.warnings!=null) {
105 if (warnings==null) {
106 warnings = er.warnings;
107 } else {
108 warnings.addAll(warnings);
109 }
110 }
111 }
112
113
114
115 /**
116 * Adds an error to the message set, but don't fail.
117 */
118 public void addErrorAndContinue(Message message) {
119 if (this.errors == null) {
120 this.errors = new LinkedList();
121 }
122
123 this.errors.add(message);
124 }
125
126 /**
127 * Adds a non-fatal error to the message set.
128 */
129 public void addError(Message message) throws CompilationFailedException {
130 addErrorAndContinue(message);
131
132 if (errors!=null && this.errors.size() >= configuration.getTolerance()) {
133 failIfErrors();
134 }
135 }
136
137 /**
138 * Adds an optionally-fatal error to the message set. Throws
139 * the unit as a PhaseFailedException, if the error is fatal.
140 */
141 public void addError(Message message, boolean fatal) throws CompilationFailedException {
142 if (fatal) {
143 addFatalError(message);
144 }
145 else {
146 addError(message);
147 }
148 }
149
150
151 /**
152 * Convenience wrapper for addError().
153 */
154 public void addError(SyntaxException error, SourceUnit source) throws CompilationFailedException {
155 addError(Message.create(error, source), error.isFatal());
156 }
157
158
159 /**
160 * Convenience wrapper for addError().
161 */
162 public void addError(String text, CSTNode context, SourceUnit source) throws CompilationFailedException {
163 addError(new LocatedMessage(text, context, source));
164 }
165
166
167 /**
168 * Adds a fatal exception to the message set and throws
169 * the unit as a PhaseFailedException.
170 */
171 public void addFatalError(Message message) throws CompilationFailedException {
172 addError(message);
173 failIfErrors();
174 }
175
176
177 public void addException(Exception cause, SourceUnit source) throws CompilationFailedException {
178 addError(new ExceptionMessage(cause,configuration.getDebug(),source));
179 failIfErrors();
180 }
181
182 /**
183 * Returns true if there are any errors pending.
184 */
185 public boolean hasErrors() {
186 return this.errors != null;
187 }
188
189 /**
190 * Returns true if there are any warnings pending.
191 */
192 public boolean hasWarnings() {
193 return this.warnings != null;
194 }
195
196 /**
197 * Returns the list of warnings, or null if there are none.
198 */
199 public List getWarnings() {
200 return this.warnings;
201 }
202
203 /**
204 * Returns the list of errors, or null if there are none.
205 */
206 public List getErrors() {
207 return this.errors;
208 }
209
210 /**
211 * Returns the number of warnings.
212 */
213 public int getWarningCount() {
214 return ((this.warnings == null) ? 0 : this.warnings.size());
215 }
216
217 /**
218 * Returns the number of errors.
219 */
220 public int getErrorCount() {
221 return ((this.errors == null) ? 0 : this.errors.size());
222 }
223
224 /**
225 * Returns the specified warning message, or null.
226 */
227 public WarningMessage getWarning(int index) {
228 if (index < getWarningCount()) {
229 return (WarningMessage) this.warnings.get(index);
230 }
231 return null;
232 }
233
234 /**
235 * Returns the specified error message, or null.
236 */
237 public Message getError(int index) {
238 if (index < getErrorCount()) {
239 return (Message) this.errors.get(index);
240 }
241 return null;
242 }
243
244 /**
245 * Returns the last error reported
246 */
247 public Message getLastError() {
248 return (Message) this.errors.getLast();
249 }
250
251 /**
252 * Convenience routine to return the specified error's
253 * underlying SyntaxException, or null if it isn't one.
254 */
255 public SyntaxException getSyntaxError(int index) {
256 SyntaxException exception = null;
257
258 Message message = getError(index);
259 if (message != null && message instanceof SyntaxErrorMessage) {
260 exception = ((SyntaxErrorMessage) message).getCause();
261 }
262 return exception;
263 }
264
265 /**
266 * Convenience routine to return the specified error's
267 * underlying Exception, or null if it isn't one.
268 */
269 public Exception getException(int index) {
270 Exception exception = null;
271
272 Message message = getError(index);
273 if (message != null) {
274 if (message instanceof ExceptionMessage) {
275 exception = ((ExceptionMessage) message).getCause();
276 }
277 else if (message instanceof SyntaxErrorMessage) {
278 exception = ((SyntaxErrorMessage) message).getCause();
279 }
280 }
281 return exception;
282 }
283
284 /**
285 * Adds a WarningMessage to the message set.
286 */
287 public void addWarning(WarningMessage message) {
288 if (message.isRelevant(configuration.getWarningLevel())) {
289 if (this.warnings == null) {
290 this.warnings = new LinkedList();
291 }
292
293 this.warnings.add(message);
294 }
295 }
296
297
298 /**
299 * Convenience wrapper for addWarning() that won't create an object
300 * unless it is relevant.
301 */
302 public void addWarning(int importance, String text, CSTNode context, SourceUnit source) {
303 if (WarningMessage.isRelevant(importance, configuration.getWarningLevel())) {
304 addWarning(new WarningMessage(importance, text, context, source));
305 }
306 }
307
308
309 /**
310 * Convenience wrapper for addWarning() that won't create an object
311 * unless it is relevant.
312 */
313 public void addWarning(int importance, String text, Object data, CSTNode context, SourceUnit source) {
314 if (WarningMessage.isRelevant(importance, configuration.getWarningLevel())) {
315 addWarning(new WarningMessage(importance, text, data, context, source));
316 }
317 }
318
319
320 /**
321 * Causes the current phase to fail by throwing a
322 * CompilationFailedException.
323 */
324 protected void failIfErrors() throws CompilationFailedException {
325 if (hasErrors()) throw new MultipleCompilationErrorsException(this);
326 }
327
328 //---------------------------------------------------------------------------
329 // OUTPUT
330
331
332 /**
333 * Writes error messages to the specified PrintWriter.
334 */
335 public void write(PrintWriter writer, Janitor janitor) {
336 if (this.warnings != null) {
337 Iterator iterator = this.warnings.iterator();
338 while (iterator.hasNext()) {
339 WarningMessage warning = (WarningMessage) iterator.next();
340 warning.write(writer, janitor);
341 }
342
343 writer.println();
344 writer.print(warnings.size());
345 writer.print(" Warning");
346 if (warnings.size()>1) writer.print("s");
347 writer.println();
348
349 this.warnings = null;
350 }
351
352 if (this.errors != null) {
353 Iterator iterator = this.errors.iterator();
354 while (iterator.hasNext()) {
355 Message message = (Message) iterator.next();
356 message.write(writer, janitor);
357
358 if (configuration.getDebug() && (message instanceof SyntaxErrorMessage)) {
359 SyntaxErrorMessage sem = (SyntaxErrorMessage) message;
360 SyntaxException se = sem.getCause();
361 se.printStackTrace(writer);
362 }
363 }
364
365 writer.println();
366 writer.print(errors.size());
367 writer.print(" Error");
368 if (errors.size()>1) writer.print("s");
369 writer.println();
370 }
371 }
372
373 }