| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// Summarizes the information produced by the checker. | 5 /// Summarizes the information produced by the checker. |
| 6 library dev_compiler.src.report; | 6 library dev_compiler.src.report; |
| 7 | 7 |
| 8 import 'dart:math' show max; | 8 import 'dart:math' show max; |
| 9 | 9 |
| 10 import 'package:analyzer/src/generated/ast.dart' show AstNode, CompilationUnit; |
| 11 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; |
| 10 import 'package:analyzer/src/generated/source.dart' show Source; | 12 import 'package:analyzer/src/generated/source.dart' show Source; |
| 11 import 'package:logging/logging.dart'; | 13 import 'package:logging/logging.dart'; |
| 12 import 'package:path/path.dart' as path; | 14 import 'package:path/path.dart' as path; |
| 13 import 'package:source_span/source_span.dart'; | 15 import 'package:source_span/source_span.dart'; |
| 14 | 16 |
| 15 import 'info.dart'; | 17 import 'info.dart'; |
| 16 import 'utils.dart'; | 18 import 'utils.dart'; |
| 17 import 'summary.dart'; | 19 import 'summary.dart'; |
| 18 | 20 |
| 19 /// A message (error or warning) produced by the dev_compiler and it's location | 21 /// A message (error or warning) produced by the dev_compiler and it's location |
| 20 /// information. | 22 /// information. |
| 21 /// | 23 /// |
| 22 /// Currently the location information includes only the offsets within a file | 24 /// Currently the location information includes only the offsets within a file |
| 23 /// where the error occurs. This is used in the context of a [CheckerReporter], | 25 /// where the error occurs. This is used in the context of a [CheckerReporter], |
| 24 /// where the current file is being tracked. | 26 /// where the current file is being tracked. |
| 25 abstract class Message { | 27 class Message { |
| 26 // Message description. | 28 // Message description. |
| 27 final String message; | 29 final String message; |
| 28 | 30 |
| 29 /// Log level. This is a placeholder for severity. | 31 /// Log level. This is a placeholder for severity. |
| 30 final Level level; | 32 final Level level; |
| 31 | 33 |
| 32 /// Offset where the error message begins in the tracked source file. | 34 /// Offset where the error message begins in the tracked source file. |
| 33 final int begin; | 35 final int begin; |
| 34 | 36 |
| 35 /// Offset where the error message ends in the tracked source file. | 37 /// Offset where the error message ends in the tracked source file. |
| 36 final int end; | 38 final int end; |
| 37 | 39 |
| 38 const Message(this.message, this.level, this.begin, this.end); | 40 const Message(this.message, this.level, this.begin, this.end); |
| 39 } | 41 } |
| 40 | 42 |
| 41 /// Like [Message], but with a precomputed source span. | |
| 42 abstract class MessageWithSpan implements Message { | |
| 43 final String message; | |
| 44 | |
| 45 final Level level; | |
| 46 | |
| 47 final SourceSpan span; | |
| 48 | |
| 49 int get begin => span.start.offset; | |
| 50 int get end => span.end.offset; | |
| 51 | |
| 52 const MessageWithSpan(this.message, this.level, this.span); | |
| 53 } | |
| 54 | |
| 55 // Interface used to report error messages from the checker. | 43 // Interface used to report error messages from the checker. |
| 56 abstract class CheckerReporter { | 44 abstract class CheckerReporter { |
| 45 final AnalysisContext _context; |
| 46 CompilationUnit _unit; |
| 47 Source _unitSource; |
| 48 |
| 49 CheckerReporter(this._context); |
| 50 |
| 57 /// Called when starting to process a library. | 51 /// Called when starting to process a library. |
| 58 void enterLibrary(Uri uri); | 52 void enterLibrary(Uri uri); |
| 59 void leaveLibrary(); | 53 void leaveLibrary(); |
| 60 | 54 |
| 61 /// Called when starting to process an HTML source file. | 55 /// Called when starting to process an HTML source file. |
| 62 void enterHtml(Uri uri); | 56 void enterHtml(Uri uri); |
| 63 void leaveHtml(); | 57 void leaveHtml(); |
| 64 | 58 |
| 65 /// Called when starting to process a source. All subsequent log entries must | 59 /// Called when starting to process a source. All subsequent log entries must |
| 66 /// belong to this source until the next call to enterSource. | 60 /// belong to this source until the next call to enterSource. |
| 67 void enterSource(Source source); | 61 void enterCompilationUnit(CompilationUnit unit, [Source source]) { |
| 68 void leaveSource(); | 62 _unit = unit; |
| 63 _unitSource = source; |
| 64 } |
| 65 void leaveCompilationUnit() { |
| 66 _unit = null; |
| 67 _unitSource = null; |
| 68 } |
| 69 |
| 69 void log(Message message); | 70 void log(Message message); |
| 70 | 71 |
| 71 // Called in server-mode. | 72 // Called in server-mode. |
| 72 void clearLibrary(Uri uri); | 73 void clearLibrary(Uri uri); |
| 73 void clearHtml(Uri uri); | 74 void clearHtml(Uri uri); |
| 74 void clearAll(); | 75 void clearAll(); |
| 76 |
| 77 SourceSpanWithContext _createSpan(int start, int end) => |
| 78 createSpan(_context, _unit, start, end, _unitSource); |
| 75 } | 79 } |
| 76 | 80 |
| 77 final _checkerLogger = new Logger('dev_compiler.checker'); | 81 final _checkerLogger = new Logger('dev_compiler.checker'); |
| 78 | 82 |
| 79 /// Simple reporter that logs checker messages as they are seen. | 83 /// Simple reporter that logs checker messages as they are seen. |
| 80 class LogReporter implements CheckerReporter { | 84 class LogReporter extends CheckerReporter { |
| 81 final bool useColors; | 85 final bool useColors; |
| 82 SourceFile _file; | |
| 83 Source _current; | 86 Source _current; |
| 84 | 87 |
| 85 LogReporter([this.useColors = false]); | 88 LogReporter(AnalysisContext context, {this.useColors: false}) |
| 89 : super(context); |
| 86 | 90 |
| 87 void enterLibrary(Uri uri) {} | 91 void enterLibrary(Uri uri) {} |
| 88 void leaveLibrary() {} | 92 void leaveLibrary() {} |
| 89 | 93 |
| 90 void enterHtml(Uri uri) {} | 94 void enterHtml(Uri uri) {} |
| 91 void leaveHtml() {} | 95 void leaveHtml() {} |
| 92 | 96 |
| 93 void enterSource(Source source) { | |
| 94 _file = new SourceFile(source.contents.data, url: source.uri); | |
| 95 _current = source; | |
| 96 } | |
| 97 | |
| 98 void leaveSource() { | |
| 99 _file = null; | |
| 100 _current = null; | |
| 101 } | |
| 102 | |
| 103 void log(Message message) { | 97 void log(Message message) { |
| 104 if (message is StaticInfo) { | 98 if (message is StaticInfo) { |
| 105 assert((message.node as dynamic).root.element.source == _current); | 99 assert(message.node.root == _unit); |
| 106 } | 100 } |
| 107 // TODO(sigmund): convert to use span information from AST (issue #73) | 101 // TODO(sigmund): convert to use span information from AST (issue #73) |
| 108 final span = message is MessageWithSpan | 102 final span = _createSpan(message.begin, message.end); |
| 109 ? message.span | |
| 110 : _file.span(message.begin, message.end); | |
| 111 final level = message.level; | 103 final level = message.level; |
| 112 final color = useColors ? colorOf(level.name) : null; | 104 final color = useColors ? colorOf(level.name) : null; |
| 113 final text = '[${message.runtimeType}] ${message.message}'; | 105 final text = '[${message.runtimeType}] ${message.message}'; |
| 114 _checkerLogger.log(level, span.message(text, color: color)); | 106 _checkerLogger.log(level, span.message(text, color: color)); |
| 115 } | 107 } |
| 116 | 108 |
| 117 void clearLibrary(Uri uri) {} | 109 void clearLibrary(Uri uri) {} |
| 118 void clearHtml(Uri uri) {} | 110 void clearHtml(Uri uri) {} |
| 119 void clearAll() {} | 111 void clearAll() {} |
| 120 } | 112 } |
| 121 | 113 |
| 122 /// A reporter that gathers all the information in a [GlobalSummary]. | 114 /// A reporter that gathers all the information in a [GlobalSummary]. |
| 123 class SummaryReporter implements CheckerReporter { | 115 class SummaryReporter extends CheckerReporter { |
| 124 GlobalSummary result = new GlobalSummary(); | 116 GlobalSummary result = new GlobalSummary(); |
| 125 IndividualSummary _current; | 117 IndividualSummary _current; |
| 126 SourceFile _file; | 118 |
| 119 SummaryReporter(AnalysisContext context) : super(context); |
| 127 | 120 |
| 128 void enterLibrary(Uri uri) { | 121 void enterLibrary(Uri uri) { |
| 129 var container; | 122 var container; |
| 130 if (uri.scheme == 'package') { | 123 if (uri.scheme == 'package') { |
| 131 var pname = path.split(uri.path)[0]; | 124 var pname = path.split(uri.path)[0]; |
| 132 result.packages.putIfAbsent(pname, () => new PackageSummary(pname)); | 125 result.packages.putIfAbsent(pname, () => new PackageSummary(pname)); |
| 133 container = result.packages[pname].libraries; | 126 container = result.packages[pname].libraries; |
| 134 } else if (uri.scheme == 'dart') { | 127 } else if (uri.scheme == 'dart') { |
| 135 container = result.system; | 128 container = result.system; |
| 136 } else { | 129 } else { |
| 137 container = result.loose; | 130 container = result.loose; |
| 138 } | 131 } |
| 139 _current = container.putIfAbsent('$uri', () => new LibrarySummary('$uri')); | 132 _current = container.putIfAbsent('$uri', () => new LibrarySummary('$uri')); |
| 140 } | 133 } |
| 141 | 134 |
| 142 void leaveLibrary() { | 135 void leaveLibrary() { |
| 143 _current = null; | 136 _current = null; |
| 144 } | 137 } |
| 145 | 138 |
| 146 void enterHtml(Uri uri) { | 139 void enterHtml(Uri uri) { |
| 147 _current = result.loose.putIfAbsent('$uri', () => new HtmlSummary('$uri')); | 140 _current = result.loose.putIfAbsent('$uri', () => new HtmlSummary('$uri')); |
| 148 } | 141 } |
| 149 | 142 |
| 150 void leaveHtml() { | 143 void leaveHtml() { |
| 151 _current = null; | 144 _current = null; |
| 152 } | 145 } |
| 153 | 146 |
| 154 void enterSource(Source source) { | 147 @override |
| 155 _file = new SourceFile(source.contents.data, url: source.uri); | 148 void enterCompilationUnit(CompilationUnit unit, [Source source]) { |
| 149 super.enterCompilationUnit(unit, source); |
| 156 if (_current is LibrarySummary) { | 150 if (_current is LibrarySummary) { |
| 157 (_current as LibrarySummary).lines += _file.lines; | 151 int lines = _unit.lineInfo.getLocation(_unit.endToken.end).lineNumber; |
| 152 (_current as LibrarySummary).lines += lines; |
| 158 } | 153 } |
| 159 } | 154 } |
| 160 | 155 |
| 161 void leaveSource() { | |
| 162 _file = null; | |
| 163 } | |
| 164 | |
| 165 void log(Message message) { | 156 void log(Message message) { |
| 166 assert(message is MessageWithSpan || _file != null); | 157 final span = _createSpan(message.begin, message.end); |
| 167 // TODO(sigmund): convert to use span information from AST (issue #73) | |
| 168 final span = message is MessageWithSpan | |
| 169 ? message.span | |
| 170 : _file.span(message.begin, message.end); | |
| 171 _current.messages.add(new MessageSummary('${message.runtimeType}', | 158 _current.messages.add(new MessageSummary('${message.runtimeType}', |
| 172 message.level.name.toLowerCase(), span, message.message)); | 159 message.level.name.toLowerCase(), span, message.message)); |
| 173 } | 160 } |
| 174 | 161 |
| 175 void clearLibrary(Uri uri) { | 162 void clearLibrary(Uri uri) { |
| 176 enterLibrary(uri); | 163 enterLibrary(uri); |
| 177 _current.messages.clear(); | 164 _current.messages.clear(); |
| 178 (_current as LibrarySummary).lines = 0; | 165 (_current as LibrarySummary).lines = 0; |
| 179 leaveLibrary(); | 166 leaveLibrary(); |
| 180 } | 167 } |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 | 368 |
| 382 visitMessage(MessageSummary message) { | 369 visitMessage(MessageSummary message) { |
| 383 var kind = message.kind; | 370 var kind = message.kind; |
| 384 errorCount.putIfAbsent(currentPackage, () => <String, int>{}); | 371 errorCount.putIfAbsent(currentPackage, () => <String, int>{}); |
| 385 errorCount[currentPackage].putIfAbsent(kind, () => 0); | 372 errorCount[currentPackage].putIfAbsent(kind, () => 0); |
| 386 errorCount[currentPackage][kind]++; | 373 errorCount[currentPackage][kind]++; |
| 387 totals.putIfAbsent(kind, () => 0); | 374 totals.putIfAbsent(kind, () => 0); |
| 388 totals[kind]++; | 375 totals[kind]++; |
| 389 } | 376 } |
| 390 } | 377 } |
| OLD | NEW |