blob: 3e6e289dc242b991e58d0c3c84f598a909be2dde [file] [log] [blame]
// Copyright (c) 2015, 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.
import 'dart:io';
import 'dart:math';
import 'package:analyzer/diagnostic/diagnostic.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/utilities/extensions/string.dart';
String _getLineContents(int lineNumber, Diagnostic diagnostic) {
var path = diagnostic.source.fullName;
var file = File(path);
String failureDetails;
if (!file.existsSync()) {
failureDetails = 'file at $path does not exist';
} else {
var lines = file.readAsLinesSync();
var lineIndex = lineNumber - 1;
if (lines.length > lineIndex) {
return lines[lineIndex];
}
failureDetails =
'line index ($lineIndex), outside of file line range (${lines.length})';
}
throw StateError('Unable to get contents for line: $failureDetails');
}
class ReportFormatter {
final StringSink out;
final Iterable<Diagnostic> diagnostics;
int diagnosticCount = 0;
ReportFormatter(this.diagnostics, this.out);
/// Override to influence diagnostic sorting.
int compare(Diagnostic diagnostic1, Diagnostic diagnostic2) {
// Severity.
var compare = diagnostic2.diagnosticCode.severity.compareTo(
diagnostic1.diagnosticCode.severity,
);
if (compare != 0) {
return compare;
}
// Path.
compare = Comparable.compare(
diagnostic1.source.fullName.toLowerCase(),
diagnostic2.source.fullName.toLowerCase(),
);
if (compare != 0) {
return compare;
}
// Offset.
return diagnostic1.offset - diagnostic2.offset;
}
void write() {
_writeLints();
_writeSummary();
out.writeln();
}
void writeLint(
Diagnostic diagnostic, {
required int offset,
required int line,
required int column,
}) {
// test/engine_test.dart 452:9 [lint] DO name types using UpperCamelCase.
out
..write('${diagnostic.source.fullName} ')
..write('$line:$column ')
..writeln(
'[${diagnostic.diagnosticCode.type.displayName}] ${diagnostic.message}',
);
var contents = _getLineContents(line, diagnostic);
out.writeln(contents);
var spaces = column - 1;
var arrows = max(1, min(diagnostic.length, contents.length - spaces));
var result = '${" " * spaces}${"^" * arrows}';
out.writeln(result);
}
void _writeLint(Diagnostic diagnostic) {
var offset = diagnostic.offset;
var lineInfo = LineInfo.fromContent(diagnostic.source.contents.data);
var location = lineInfo.getLocation(offset);
var line = location.lineNumber;
var column = location.columnNumber;
writeLint(diagnostic, offset: offset, column: column, line: line);
}
void _writeLints() {
for (var e in (diagnostics.toList()..sort(compare))) {
++diagnosticCount;
_writeLint(e);
}
out.writeln();
}
void _writeSummary() {
var summary =
'files analyzed, '
'$diagnosticCount ${"issue".pluralized(diagnosticCount)} found.';
out.writeln(summary);
}
}