001: /*
002: $Id: ErrorCollector.java 4534 2006-12-21 17:34:36Z blackdrag $
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 4534 2006-12-21 17:34:36Z blackdrag $
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: * Adds an error to the message set, but don't fail.
115: */
116: public void addErrorAndContinue(Message message) {
117: if (this .errors == null) {
118: this .errors = new LinkedList();
119: }
120:
121: this .errors.add(message);
122: }
123:
124: /**
125: * Adds a non-fatal error to the message set.
126: */
127: public void addError(Message message)
128: throws CompilationFailedException {
129: addErrorAndContinue(message);
130:
131: if (errors != null
132: && 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)
142: throws CompilationFailedException {
143: if (fatal) {
144: addFatalError(message);
145: } else {
146: addError(message);
147: }
148: }
149:
150: /**
151: * Convenience wrapper for addError().
152: */
153: public void addError(SyntaxException error, SourceUnit source)
154: throws CompilationFailedException {
155: addError(Message.create(error, source), error.isFatal());
156: }
157:
158: /**
159: * Convenience wrapper for addError().
160: */
161: public void addError(String text, CSTNode context, SourceUnit source)
162: throws CompilationFailedException {
163: addError(new LocatedMessage(text, context, source));
164: }
165:
166: /**
167: * Adds a fatal exception to the message set and throws
168: * the unit as a PhaseFailedException.
169: */
170: public void addFatalError(Message message)
171: throws CompilationFailedException {
172: addError(message);
173: failIfErrors();
174: }
175:
176: public void addException(Exception cause, SourceUnit source)
177: throws CompilationFailedException {
178: addError(new ExceptionMessage(cause, configuration.getDebug(),
179: source));
180: failIfErrors();
181: }
182:
183: /**
184: * Returns true if there are any errors pending.
185: */
186: public boolean hasErrors() {
187: return this .errors != null;
188: }
189:
190: /**
191: * Returns true if there are any warnings pending.
192: */
193: public boolean hasWarnings() {
194: return this .warnings != null;
195: }
196:
197: /**
198: * Returns the list of warnings, or null if there are none.
199: */
200: public List getWarnings() {
201: return this .warnings;
202: }
203:
204: /**
205: * Returns the list of errors, or null if there are none.
206: */
207: public List getErrors() {
208: return this .errors;
209: }
210:
211: /**
212: * Returns the number of warnings.
213: */
214: public int getWarningCount() {
215: return ((this .warnings == null) ? 0 : this .warnings.size());
216: }
217:
218: /**
219: * Returns the number of errors.
220: */
221: public int getErrorCount() {
222: return ((this .errors == null) ? 0 : this .errors.size());
223: }
224:
225: /**
226: * Returns the specified warning message, or null.
227: */
228: public WarningMessage getWarning(int index) {
229: if (index < getWarningCount()) {
230: return (WarningMessage) this .warnings.get(index);
231: }
232: return null;
233: }
234:
235: /**
236: * Returns the specified error message, or null.
237: */
238: public Message getError(int index) {
239: if (index < getErrorCount()) {
240: return (Message) this .errors.get(index);
241: }
242: return null;
243: }
244:
245: /**
246: * Returns the last error reported
247: */
248: public Message getLastError() {
249: return (Message) this .errors.getLast();
250: }
251:
252: /**
253: * Convenience routine to return the specified error's
254: * underlying SyntaxException, or null if it isn't one.
255: */
256: public SyntaxException getSyntaxError(int index) {
257: SyntaxException exception = null;
258:
259: Message message = getError(index);
260: if (message != null && message instanceof SyntaxErrorMessage) {
261: exception = ((SyntaxErrorMessage) message).getCause();
262: }
263: return exception;
264: }
265:
266: /**
267: * Convenience routine to return the specified error's
268: * underlying Exception, or null if it isn't one.
269: */
270: public Exception getException(int index) {
271: Exception exception = null;
272:
273: Message message = getError(index);
274: if (message != null) {
275: if (message instanceof ExceptionMessage) {
276: exception = ((ExceptionMessage) message).getCause();
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: * Convenience wrapper for addWarning() that won't create an object
299: * unless it is relevant.
300: */
301: public void addWarning(int importance, String text,
302: CSTNode context, SourceUnit source) {
303: if (WarningMessage.isRelevant(importance, configuration
304: .getWarningLevel())) {
305: addWarning(new WarningMessage(importance, text, context,
306: source));
307: }
308: }
309:
310: /**
311: * Convenience wrapper for addWarning() that won't create an object
312: * unless it is relevant.
313: */
314: public void addWarning(int importance, String text, Object data,
315: CSTNode context, SourceUnit source) {
316: if (WarningMessage.isRelevant(importance, configuration
317: .getWarningLevel())) {
318: addWarning(new WarningMessage(importance, text, data,
319: context, source));
320: }
321: }
322:
323: /**
324: * Causes the current phase to fail by throwing a
325: * CompilationFailedException.
326: */
327: protected void failIfErrors() throws CompilationFailedException {
328: if (hasErrors()) {
329: throw new MultipleCompilationErrorsException(this );
330: }
331: }
332:
333: //---------------------------------------------------------------------------
334: // OUTPUT
335:
336: private void write(PrintWriter writer, Janitor janitor,
337: List messages, String txt) {
338: if (messages == null || messages.size() == 0)
339: return;
340: Iterator iterator = messages.iterator();
341: while (iterator.hasNext()) {
342: Message message = (Message) iterator.next();
343: message.write(writer, janitor);
344:
345: if (configuration.getDebug()
346: && (message instanceof SyntaxErrorMessage)) {
347: SyntaxErrorMessage sem = (SyntaxErrorMessage) message;
348: sem.getCause().printStackTrace(writer);
349: }
350: }
351:
352: writer.println();
353: writer.print(messages.size());
354: writer.print(" " + txt);
355: if (messages.size() > 1)
356: writer.print("s");
357: writer.println();
358: }
359:
360: /**
361: * Writes error messages to the specified PrintWriter.
362: */
363: public void write(PrintWriter writer, Janitor janitor) {
364: write(writer, janitor, warnings, "warning");
365: write(writer, janitor, errors, "error");
366: }
367:
368: }
|