OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library error_formatter; |
| 6 |
| 7 import 'generated/engine.dart'; |
| 8 import 'generated/error.dart'; |
| 9 import 'generated/source_io.dart'; |
| 10 import '../options.dart'; |
| 11 |
| 12 /// Returns `true` if [AnalysisError] should be printed. |
| 13 typedef bool _ErrorFilter(AnalysisError error); |
| 14 |
| 15 /// Allows any [AnalysisError]. |
| 16 bool _anyError(AnalysisError error) => true; |
| 17 |
| 18 /** |
| 19 * Helper for formatting [AnalysisError]s. |
| 20 * The two format options are a user consumable format and a machine consumable
format. |
| 21 */ |
| 22 class ErrorFormatter { |
| 23 final StringSink out; |
| 24 final CommandLineOptions options; |
| 25 final _ErrorFilter errorFilter; |
| 26 |
| 27 ErrorFormatter(this.out, this.options, [this.errorFilter = _anyError]); |
| 28 |
| 29 void formatErrors(List<AnalysisErrorInfo> errorInfos) { |
| 30 var errors = new List<AnalysisError>(); |
| 31 var errorToLine = new Map<AnalysisError, LineInfo>(); |
| 32 for (AnalysisErrorInfo errorInfo in errorInfos) { |
| 33 for (AnalysisError error in errorInfo.errors) { |
| 34 if (errorFilter(error)) { |
| 35 errors.add(error); |
| 36 errorToLine[error] = errorInfo.lineInfo; |
| 37 } |
| 38 } |
| 39 } |
| 40 // sort errors |
| 41 errors.sort((AnalysisError error1, AnalysisError error2) { |
| 42 // severity |
| 43 int compare = error2.errorCode.errorSeverity.compareTo(error1.errorCode.er
rorSeverity); |
| 44 if (compare != 0) { |
| 45 return compare; |
| 46 } |
| 47 // path |
| 48 compare = Comparable.compare(error1.source.fullName.toLowerCase(), error2.
source.fullName.toLowerCase()); |
| 49 if (compare != 0) { |
| 50 return compare; |
| 51 } |
| 52 // offset |
| 53 return error1.offset - error2.offset; |
| 54 }); |
| 55 // format errors |
| 56 int errorCount = 0; |
| 57 int warnCount = 0; |
| 58 int hintCount = 0; |
| 59 for (AnalysisError error in errors) { |
| 60 var severity = error.errorCode.errorSeverity; |
| 61 if (severity == ErrorSeverity.ERROR) { |
| 62 errorCount++; |
| 63 } else if (severity == ErrorSeverity.WARNING) { |
| 64 if (options.warningsAreFatal) { |
| 65 errorCount++; |
| 66 } else { |
| 67 if (error.errorCode.type == ErrorType.HINT) { |
| 68 hintCount++; |
| 69 } else { |
| 70 warnCount++; |
| 71 } |
| 72 } |
| 73 } |
| 74 formatError(errorToLine, error); |
| 75 } |
| 76 // print statistics |
| 77 if (!options.machineFormat) { |
| 78 var hasErrors = errorCount != 0; |
| 79 var hasWarns = warnCount != 0; |
| 80 var hasHints = hintCount != 0; |
| 81 bool hasContent = false; |
| 82 if (hasErrors) { |
| 83 out.write(errorCount); |
| 84 out.write(' '); |
| 85 out.write(pluralize("error", errorCount)); |
| 86 hasContent = true; |
| 87 } |
| 88 if (hasWarns) { |
| 89 if (hasContent) { |
| 90 if (!hasHints) { |
| 91 out.write(' and '); |
| 92 } else { |
| 93 out.write(", "); |
| 94 } |
| 95 } |
| 96 out.write(warnCount); |
| 97 out.write(' '); |
| 98 out.write(pluralize("warning", warnCount)); |
| 99 hasContent = true; |
| 100 } |
| 101 if (hasHints) { |
| 102 if (hasContent) { |
| 103 out.write(" and "); |
| 104 } |
| 105 out.write(hintCount); |
| 106 out.write(' '); |
| 107 out.write(pluralize("hint", hintCount)); |
| 108 hasContent = true; |
| 109 } |
| 110 if (hasContent) { |
| 111 out.writeln(" found."); |
| 112 } else { |
| 113 out.writeln("No issues found"); |
| 114 } |
| 115 } |
| 116 } |
| 117 |
| 118 void formatError(Map<AnalysisError, LineInfo> errorToLine, AnalysisError error
) { |
| 119 Source source = error.source; |
| 120 LineInfo_Location location = errorToLine[error].getLocation(error.offset); |
| 121 int length = error.length; |
| 122 var severity = error.errorCode.errorSeverity; |
| 123 if (options.machineFormat) { |
| 124 if (severity == ErrorSeverity.WARNING && options.warningsAreFatal) { |
| 125 severity = ErrorSeverity.ERROR; |
| 126 } |
| 127 out.write(severity); |
| 128 out.write('|'); |
| 129 out.write(error.errorCode.type); |
| 130 out.write('|'); |
| 131 out.write(error.errorCode); |
| 132 out.write('|'); |
| 133 out.write(escapePipe(source.fullName)); |
| 134 out.write('|'); |
| 135 out.write(location.lineNumber); |
| 136 out.write('|'); |
| 137 out.write(location.columnNumber); |
| 138 out.write('|'); |
| 139 out.write(length); |
| 140 out.write('|'); |
| 141 out.write(escapePipe(error.message)); |
| 142 } else { |
| 143 String errorType = error.errorCode.errorSeverity.displayName; |
| 144 if (error.errorCode.type == ErrorType.HINT) { |
| 145 errorType = error.errorCode.type.displayName; |
| 146 } |
| 147 // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2) |
| 148 out.write('[$errorType] ${error.message} '); |
| 149 out.write('(${source.fullName}'); |
| 150 out.write(', line ${location.lineNumber}, col ${location.columnNumber})'); |
| 151 } |
| 152 out.writeln(); |
| 153 } |
| 154 |
| 155 static String escapePipe(String input) { |
| 156 var result = new StringBuffer(); |
| 157 for (var c in input.codeUnits) { |
| 158 if (c == '\\' || c == '|') { |
| 159 result.write('\\'); |
| 160 } |
| 161 result.writeCharCode(c); |
| 162 } |
| 163 return result.toString(); |
| 164 } |
| 165 |
| 166 static String pluralize(String word, int count) { |
| 167 if (count == 1) { |
| 168 return word; |
| 169 } else { |
| 170 return word + "s"; |
| 171 } |
| 172 } |
| 173 } |
OLD | NEW |