Index: lib/src/report.dart |
diff --git a/lib/src/report.dart b/lib/src/report.dart |
index 7b6b94f5d15ee0635a5a4b35a95201810b3dce8e..9493ea6081b982965633f99327f6cb0ca8b02b41 100644 |
--- a/lib/src/report.dart |
+++ b/lib/src/report.dart |
@@ -2,18 +2,11 @@ |
// 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. |
-/// Summarizes the information produced by the checker. |
- |
-import 'dart:math' show max; |
- |
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
import 'package:analyzer/src/generated/error.dart'; |
import 'package:logging/logging.dart'; |
import 'package:path/path.dart' as path; |
-import 'package:source_span/source_span.dart'; |
- |
import 'utils.dart'; |
-import 'summary.dart'; |
final _checkerLogger = new Logger('dev_compiler.checker'); |
@@ -101,269 +94,3 @@ const _severityToLevel = const { |
ErrorSeverity.WARNING: Level.WARNING, |
ErrorSeverity.INFO: Level.INFO |
}; |
- |
-/// A reporter that gathers all the information in a [GlobalSummary]. |
-class SummaryReporter implements AnalysisErrorListener { |
- GlobalSummary result = new GlobalSummary(); |
- final Level _level; |
- final AnalysisContext _context; |
- |
- SummaryReporter(this._context, [this._level = Level.ALL]); |
- |
- IndividualSummary _getIndividualSummary(Uri uri) { |
- if (uri.path.endsWith('.html')) { |
- return result.loose.putIfAbsent('$uri', () => new HtmlSummary('$uri')); |
- } |
- |
- var container; |
- if (uri.scheme == 'package') { |
- var pname = path.split(uri.path)[0]; |
- result.packages.putIfAbsent(pname, () => new PackageSummary(pname)); |
- container = result.packages[pname].libraries; |
- } else if (uri.scheme == 'dart') { |
- container = result.system; |
- } else { |
- container = result.loose; |
- } |
- return container.putIfAbsent('$uri', () => new LibrarySummary('$uri')); |
- } |
- |
- void onError(AnalysisError error) { |
- // Only summarize messages per configured logging level |
- var code = error.errorCode; |
- if (_severityToLevel[code.errorSeverity] < _level) return; |
- |
- var span = _toSpan(_context, error); |
- var summary = _getIndividualSummary(error.source.uri); |
- if (summary is LibrarySummary) { |
- summary.recordSourceLines(error.source.uri, () { |
- // TODO(jmesserly): parsing is serious overkill for this. |
- // Should be cached, but still. |
- // On the other hand, if we are going to parse, we could get a much |
- // better source lines of code estimate by excluding things like |
- // comments, blank lines, and closing braces. |
- var unit = _context.parseCompilationUnit(error.source); |
- return unit.lineInfo.getLocation(unit.endToken.end).lineNumber; |
- }); |
- } |
- summary.messages.add(new MessageSummary(errorCodeName(code), |
- code.errorSeverity.displayName, span, error.message)); |
- } |
- |
- // TODO(jmesserly): fix to not depend on SourceSpan. This will be really slow |
- // because it will reload source text from disk, for every single message... |
- SourceSpanWithContext _toSpan(AnalysisContext context, AnalysisError error) { |
- var source = error.source; |
- var lineInfo = context.computeLineInfo(source); |
- var content = context.getContents(source).data; |
- var start = error.offset; |
- var end = start + error.length; |
- return createSpanHelper(lineInfo, start, end, source, content); |
- } |
- |
- void clearLibrary(Uri uri) { |
- (_getIndividualSummary(uri) as LibrarySummary).clear(); |
- } |
- |
- void clearHtml(Uri uri) { |
- HtmlSummary htmlSummary = result.loose['$uri']; |
- if (htmlSummary != null) htmlSummary.messages.clear(); |
- } |
-} |
- |
-/// Produces a string representation of the summary. |
-String summaryToString(GlobalSummary summary) { |
- var counter = new _Counter(); |
- summary.accept(counter); |
- |
- var table = new _Table(); |
- // Declare columns and add header |
- table.declareColumn('package'); |
- table.declareColumn('AnalyzerError', abbreviate: true); |
- |
- var activeInfoTypes = counter.totals.keys; |
- activeInfoTypes.forEach((t) => table.declareColumn(t, abbreviate: true)); |
- table.declareColumn('LinesOfCode', abbreviate: true); |
- table.addHeader(); |
- |
- // Add entries for each package |
- appendCount(count) => table.addEntry(count == null ? 0 : count); |
- for (var package in counter.errorCount.keys) { |
- appendCount(package); |
- appendCount(counter.errorCount[package]['AnalyzerError']); |
- activeInfoTypes.forEach((t) => appendCount(counter.errorCount[package][t])); |
- appendCount(counter.linesOfCode[package]); |
- } |
- |
- // Add totals, percents and a new header for quick reference |
- table.addEmptyRow(); |
- table.addHeader(); |
- table.addEntry('total'); |
- appendCount(counter.totals['AnalyzerError']); |
- activeInfoTypes.forEach((t) => appendCount(counter.totals[t])); |
- appendCount(counter.totalLinesOfCode); |
- |
- appendPercent(count, total) { |
- if (count == null) count = 0; |
- var value = (count * 100 / total).toStringAsFixed(2); |
- table.addEntry(value); |
- } |
- |
- var totalLOC = counter.totalLinesOfCode; |
- table.addEntry('%'); |
- appendPercent(counter.totals['AnalyzerError'], totalLOC); |
- activeInfoTypes.forEach((t) => appendPercent(counter.totals[t], totalLOC)); |
- appendCount(100); |
- |
- return table.toString(); |
-} |
- |
-/// Helper class to combine all the information in table form. |
-class _Table { |
- int _totalColumns = 0; |
- int get totalColumns => _totalColumns; |
- |
- /// Abbreviations, used to make headers shorter. |
- Map<String, String> abbreviations = {}; |
- |
- /// Width of each column. |
- List<int> widths = <int>[]; |
- |
- /// The header for each column (`header.length == totalColumns`). |
- List header = []; |
- |
- /// Each row on the table. Note that all rows have the same size |
- /// (`rows[*].length == totalColumns`). |
- List<List> rows = []; |
- |
- /// Whether we started adding entries. Indicates that no more columns can be |
- /// added. |
- bool _sealed = false; |
- |
- /// Current row being built by [addEntry]. |
- List _currentRow; |
- |
- /// Add a column with the given [name]. |
- void declareColumn(String name, {bool abbreviate: false}) { |
- assert(!_sealed); |
- var headerName = name; |
- if (abbreviate) { |
- // abbreviate the header by using only the capital initials. |
- headerName = name.replaceAll(new RegExp('[a-z]'), ''); |
- while (abbreviations[headerName] != null) headerName = "$headerName'"; |
- abbreviations[headerName] = name; |
- } |
- widths.add(max(5, headerName.length + 1) as int); |
- header.add(headerName); |
- _totalColumns++; |
- } |
- |
- /// Add an entry in the table, creating a new row each time [totalColumns] |
- /// entries are added. |
- void addEntry(entry) { |
- if (_currentRow == null) { |
- _sealed = true; |
- _currentRow = []; |
- } |
- int pos = _currentRow.length; |
- assert(pos < _totalColumns); |
- |
- widths[pos] = max(widths[pos], '$entry'.length + 1); |
- _currentRow.add('$entry'); |
- |
- if (pos + 1 == _totalColumns) { |
- rows.add(_currentRow); |
- _currentRow = []; |
- } |
- } |
- |
- /// Add an empty row to divide sections of the table. |
- void addEmptyRow() { |
- var emptyRow = []; |
- for (int i = 0; i < _totalColumns; i++) { |
- emptyRow.add('-' * widths[i]); |
- } |
- rows.add(emptyRow); |
- } |
- |
- /// Enter the header titles. OK to do so more than once in long tables. |
- void addHeader() { |
- rows.add(header); |
- } |
- |
- /// Generates a string representation of the table to print on a terminal. |
- // TODO(sigmund): add also a .csv format |
- String toString() { |
- var sb = new StringBuffer(); |
- sb.write('\n'); |
- for (var row in rows) { |
- for (int i = 0; i < _totalColumns; i++) { |
- var entry = row[i]; |
- // Align first column to the left, everything else to the right. |
- sb.write( |
- i == 0 ? entry.padRight(widths[i]) : entry.padLeft(widths[i] + 1)); |
- } |
- sb.write('\n'); |
- } |
- sb.write('\nWhere:\n'); |
- for (var id in abbreviations.keys) { |
- sb.write(' $id:'.padRight(7)); |
- sb.write(' ${abbreviations[id]}\n'); |
- } |
- return sb.toString(); |
- } |
-} |
- |
-/// An example visitor that counts the number of errors per package and total. |
-class _Counter extends RecursiveSummaryVisitor { |
- String _currentPackage; |
- String get currentPackage => |
- _currentPackage != null ? _currentPackage : "*other*"; |
- var sb = new StringBuffer(); |
- Map<String, Map<String, int>> errorCount = <String, Map<String, int>>{}; |
- Map<String, int> linesOfCode = <String, int>{}; |
- Map<String, int> totals = <String, int>{}; |
- int totalLinesOfCode = 0; |
- |
- void visitGlobal(GlobalSummary global) { |
- if (!global.system.isEmpty) { |
- for (var lib in global.system.values) { |
- lib.accept(this); |
- } |
- } |
- |
- if (!global.packages.isEmpty) { |
- for (var lib in global.packages.values) { |
- lib.accept(this); |
- } |
- } |
- |
- if (!global.loose.isEmpty) { |
- for (var lib in global.loose.values) { |
- lib.accept(this); |
- } |
- } |
- } |
- |
- void visitPackage(PackageSummary package) { |
- _currentPackage = package.name; |
- super.visitPackage(package); |
- _currentPackage = null; |
- } |
- |
- void visitLibrary(LibrarySummary lib) { |
- super.visitLibrary(lib); |
- linesOfCode.putIfAbsent(currentPackage, () => 0); |
- linesOfCode[currentPackage] += lib.lines; |
- totalLinesOfCode += lib.lines; |
- } |
- |
- visitMessage(MessageSummary message) { |
- var kind = message.kind; |
- errorCount.putIfAbsent(currentPackage, () => <String, int>{}); |
- errorCount[currentPackage].putIfAbsent(kind, () => 0); |
- errorCount[currentPackage][kind]++; |
- totals.putIfAbsent(kind, () => 0); |
- totals[kind]++; |
- } |
-} |