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 }