blob: b64dfc6f7782d0294271ff21bbd708a2e2efc8a9 [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library error_formatter;
import 'package:analyzer/src/analyzer_impl.dart';
import '../options.dart';
import 'generated/engine.dart';
import 'generated/error.dart';
import 'generated/source_io.dart';
/// Allows any [AnalysisError].
bool _anyError(AnalysisError error) => true;
/// Returns `true` if [AnalysisError] should be printed.
typedef bool _ErrorFilter(AnalysisError error);
/**
* Helper for formatting [AnalysisError]s.
* The two format options are a user consumable format and a machine consumable format.
*/
class ErrorFormatter {
final StringSink out;
final CommandLineOptions options;
final _ErrorFilter errorFilter;
ErrorFormatter(this.out, this.options, [this.errorFilter = _anyError]);
void formatError(Map<AnalysisError, LineInfo> errorToLine,
AnalysisError error) {
Source source = error.source;
LineInfo_Location location = errorToLine[error].getLocation(error.offset);
int length = error.length;
ErrorSeverity severity =
AnalyzerImpl.computeSeverity(error, options.enableTypeChecks);
if (options.machineFormat) {
if (severity == ErrorSeverity.WARNING && options.warningsAreFatal) {
severity = ErrorSeverity.ERROR;
}
out.write(severity);
out.write('|');
out.write(error.errorCode.type);
out.write('|');
out.write(error.errorCode.name);
out.write('|');
out.write(escapePipe(source.fullName));
out.write('|');
out.write(location.lineNumber);
out.write('|');
out.write(location.columnNumber);
out.write('|');
out.write(length);
out.write('|');
out.write(escapePipe(error.message));
} else {
String errorType = severity.displayName;
if (error.errorCode.type == ErrorType.HINT) {
errorType = error.errorCode.type.displayName;
}
// [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2)
out.write('[$errorType] ${error.message} ');
out.write('(${source.fullName}');
out.write(', line ${location.lineNumber}, col ${location.columnNumber})');
}
out.writeln();
}
void formatErrors(List<AnalysisErrorInfo> errorInfos) {
var errors = new List<AnalysisError>();
var errorToLine = new Map<AnalysisError, LineInfo>();
for (AnalysisErrorInfo errorInfo in errorInfos) {
for (AnalysisError error in errorInfo.errors) {
if (errorFilter(error)) {
errors.add(error);
errorToLine[error] = errorInfo.lineInfo;
}
}
}
// sort errors
errors.sort((AnalysisError error1, AnalysisError error2) {
// severity
ErrorSeverity severity1 =
AnalyzerImpl.computeSeverity(error1, options.enableTypeChecks);
ErrorSeverity severity2 =
AnalyzerImpl.computeSeverity(error2, options.enableTypeChecks);
int compare = severity2.compareTo(severity1);
if (compare != 0) {
return compare;
}
// path
compare = Comparable.compare(
error1.source.fullName.toLowerCase(),
error2.source.fullName.toLowerCase());
if (compare != 0) {
return compare;
}
// offset
return error1.offset - error2.offset;
});
// format errors
int errorCount = 0;
int warnCount = 0;
int hintCount = 0;
int lintCount = 0;
for (AnalysisError error in errors) {
ErrorSeverity severity =
AnalyzerImpl.computeSeverity(error, options.enableTypeChecks);
if (severity == ErrorSeverity.ERROR) {
errorCount++;
} else if (severity == ErrorSeverity.WARNING) {
if (options.warningsAreFatal) {
errorCount++;
} else {
if (error.errorCode.type == ErrorType.HINT) {
hintCount++;
} else {
warnCount++;
}
}
} else if (error.errorCode.type == ErrorType.LINT) {
lintCount++;
}
formatError(errorToLine, error);
}
// print statistics
if (!options.machineFormat) {
var hasErrors = errorCount != 0;
var hasWarns = warnCount != 0;
var hasHints = hintCount != 0;
var hasLints = lintCount != 0;
bool hasContent = false;
if (hasErrors) {
out.write(errorCount);
out.write(' ');
out.write(pluralize("error", errorCount));
hasContent = true;
}
if (hasWarns) {
if (hasContent) {
if (!hasHints && !hasLints) {
out.write(' and ');
} else {
out.write(", ");
}
}
out.write(warnCount);
out.write(' ');
out.write(pluralize("warning", warnCount));
hasContent = true;
}
if (hasHints) {
if (hasContent) {
if (!hasLints) {
out.write(' and ');
} else {
out.write(", ");
}
}
out.write(hintCount);
out.write(' ');
out.write(pluralize("hint", hintCount));
hasContent = true;
}
if (hasLints) {
if (hasContent) {
out.write(" and ");
}
out.write(lintCount);
out.write(' ');
out.write(pluralize("lint", lintCount));
hasContent = true;
}
if (hasContent) {
out.writeln(" found.");
} else {
out.writeln("No issues found");
}
}
}
static String escapePipe(String input) {
var result = new StringBuffer();
for (var c in input.codeUnits) {
if (c == '\\' || c == '|') {
result.write('\\');
}
result.writeCharCode(c);
}
return result.toString();
}
static String pluralize(String word, int count) {
if (count == 1) {
return word;
} else {
return word + "s";
}
}
}