Unverified Commit 72258eac authored by includecmath's avatar includecmath Committed by GitHub

[flutter_tools] Separate style and data from AnalysisError (#60591)

parent c65f32f4
...@@ -19,7 +19,9 @@ import '../convert.dart'; ...@@ -19,7 +19,9 @@ import '../convert.dart';
/// An interface to the Dart analysis server. /// An interface to the Dart analysis server.
class AnalysisServer { class AnalysisServer {
AnalysisServer(this.sdkPath, this.directories, { AnalysisServer(
this.sdkPath,
this.directories, {
@required FileSystem fileSystem, @required FileSystem fileSystem,
@required ProcessManager processManager, @required ProcessManager processManager,
@required Logger logger, @required Logger logger,
...@@ -78,12 +80,14 @@ class AnalysisServer { ...@@ -78,12 +80,14 @@ class AnalysisServer {
// This callback hookup can't throw. // This callback hookup can't throw.
unawaited(_process.exitCode.whenComplete(() => _process = null)); unawaited(_process.exitCode.whenComplete(() => _process = null));
final Stream<String> errorStream = final Stream<String> errorStream = _process.stderr
_process.stderr.transform<String>(utf8.decoder).transform<String>(const LineSplitter()); .transform<String>(utf8.decoder)
.transform<String>(const LineSplitter());
errorStream.listen(_logger.printError); errorStream.listen(_logger.printError);
final Stream<String> inStream = final Stream<String> inStream = _process.stdout
_process.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()); .transform<String>(utf8.decoder)
.transform<String>(const LineSplitter());
inStream.listen(_handleServerResponse); inStream.listen(_handleServerResponse);
_sendCommand('server.setSubscriptions', <String, dynamic>{ _sendCommand('server.setSubscriptions', <String, dynamic>{
...@@ -95,7 +99,9 @@ class AnalysisServer { ...@@ -95,7 +99,9 @@ class AnalysisServer {
} }
bool get didServerErrorOccur => _didServerErrorOccur; bool get didServerErrorOccur => _didServerErrorOccur;
Stream<bool> get onAnalyzing => _analyzingController.stream; Stream<bool> get onAnalyzing => _analyzingController.stream;
Stream<FileAnalysisErrors> get onErrors => _errorsController.stream; Stream<FileAnalysisErrors> get onErrors => _errorsController.stream;
Future<int> get onExit => _process.exitCode; Future<int> get onExit => _process.exitCode;
...@@ -165,7 +171,7 @@ class AnalysisServer { ...@@ -165,7 +171,7 @@ class AnalysisServer {
final List<AnalysisError> errors = errorsList final List<AnalysisError> errors = errorsList
.map<Map<String, dynamic>>(castStringKeyedMap) .map<Map<String, dynamic>>(castStringKeyedMap)
.map<AnalysisError>((Map<String, dynamic> json) { .map<AnalysisError>((Map<String, dynamic> json) {
return AnalysisError(json, return AnalysisError(WrittenError.fromJson(json),
fileSystem: _fileSystem, fileSystem: _fileSystem,
platform: _platform, platform: _platform,
terminal: _terminal, terminal: _terminal,
...@@ -191,8 +197,10 @@ enum _AnalysisSeverity { ...@@ -191,8 +197,10 @@ enum _AnalysisSeverity {
none, none,
} }
/// [AnalysisError] with command line style.
class AnalysisError implements Comparable<AnalysisError> { class AnalysisError implements Comparable<AnalysisError> {
AnalysisError(this.json, { AnalysisError(
this.writtenError, {
@required Platform platform, @required Platform platform,
@required Terminal terminal, @required Terminal terminal,
@required FileSystem fileSystem, @required FileSystem fileSystem,
...@@ -200,85 +208,132 @@ class AnalysisError implements Comparable<AnalysisError> { ...@@ -200,85 +208,132 @@ class AnalysisError implements Comparable<AnalysisError> {
_terminal = terminal, _terminal = terminal,
_fileSystem = fileSystem; _fileSystem = fileSystem;
final WrittenError writtenError;
final Platform _platform; final Platform _platform;
final Terminal _terminal; final Terminal _terminal;
final FileSystem _fileSystem; final FileSystem _fileSystem;
static final Map<String, _AnalysisSeverity> _severityMap = <String, _AnalysisSeverity>{
'INFO': _AnalysisSeverity.info,
'WARNING': _AnalysisSeverity.warning,
'ERROR': _AnalysisSeverity.error,
};
String get _separator => _platform.isWindows ? '-' : '•'; String get _separator => _platform.isWindows ? '-' : '•';
// "severity":"INFO","type":"TODO","location":{
// "file":"/Users/.../lib/test.dart","offset":362,"length":72,"startLine":15,"startColumn":4
// },"message":"...","hasFix":false}
Map<String, dynamic> json;
String get severity => json['severity'] as String;
String get colorSeverity { String get colorSeverity {
switch(_severityLevel) { switch (writtenError.severityLevel) {
case _AnalysisSeverity.error: case _AnalysisSeverity.error:
return _terminal.color(severity, TerminalColor.red); return _terminal.color(writtenError.severity, TerminalColor.red);
case _AnalysisSeverity.warning: case _AnalysisSeverity.warning:
return _terminal.color(severity, TerminalColor.yellow); return _terminal.color(writtenError.severity, TerminalColor.yellow);
case _AnalysisSeverity.info: case _AnalysisSeverity.info:
case _AnalysisSeverity.none: case _AnalysisSeverity.none:
return severity; return writtenError.severity;
} }
return null; return null;
} }
_AnalysisSeverity get _severityLevel => _severityMap[severity] ?? _AnalysisSeverity.none;
String get type => json['type'] as String;
String get message => json['message'] as String;
String get code => json['code'] as String;
String get file => json['location']['file'] as String; String get type => writtenError.type;
int get startLine => json['location']['startLine'] as int; String get code => writtenError.code;
int get startColumn => json['location']['startColumn'] as int;
int get offset => json['location']['offset'] as int;
String get messageSentenceFragment {
if (message.endsWith('.')) {
return message.substring(0, message.length - 1);
} else {
return message;
}
}
@override @override
int compareTo(AnalysisError other) { int compareTo(AnalysisError other) {
// Sort in order of file path, error location, severity, and message. // Sort in order of file path, error location, severity, and message.
if (file != other.file) { if (writtenError.file != other.writtenError.file) {
return file.compareTo(other.file); return writtenError.file.compareTo(other.writtenError.file);
} }
if (offset != other.offset) { if (writtenError.offset != other.writtenError.offset) {
return offset - other.offset; return writtenError.offset - other.writtenError.offset;
} }
final int diff = other._severityLevel.index - _severityLevel.index; final int diff = other.writtenError.severityLevel.index -
writtenError.severityLevel.index;
if (diff != 0) { if (diff != 0) {
return diff; return diff;
} }
return message.compareTo(other.message); return writtenError.message.compareTo(other.writtenError.message);
} }
@override @override
String toString() { String toString() {
// Can't use "padLeft" because of ANSI color sequences in the colorized // Can't use "padLeft" because of ANSI color sequences in the colorized
// severity. // severity.
final String padding = ' ' * math.max(0, 7 - severity.length); final String padding = ' ' * math.max(0, 7 - writtenError.severity.length);
return '$padding${colorSeverity.toLowerCase()} $_separator ' return '$padding${colorSeverity.toLowerCase()} $_separator '
'$messageSentenceFragment $_separator ' '${writtenError.messageSentenceFragment} $_separator '
'${_fileSystem.path.relative(file)}:$startLine:$startColumn $_separator ' '${_fileSystem.path.relative(writtenError.file)}:${writtenError.startLine}:${writtenError.startColumn} $_separator '
'$code'; '$code';
} }
String toLegacyString() { String toLegacyString() {
return writtenError.toString();
}
}
/// [AnalysisError] in plain text content.
class WrittenError {
WrittenError._({
@required this.severity,
@required this.type,
@required this.message,
@required this.code,
@required this.file,
@required this.startLine,
@required this.startColumn,
@required this.offset,
});
/// {
/// "severity":"INFO",
/// "type":"TODO",
/// "location":{
/// "file":"/Users/.../lib/test.dart",
/// "offset":362,
/// "length":72,
/// "startLine":15,
/// "startColumn":4
/// },
/// "message":"...",
/// "hasFix":false
/// }
static WrittenError fromJson(Map<String, dynamic> json) {
return WrittenError._(
severity: json['severity'] as String,
type: json['type'] as String,
message: json['message'] as String,
code: json['code'] as String,
file: json['location']['file'] as String,
startLine: json['location']['startLine'] as int,
startColumn: json['location']['startColumn'] as int,
offset: json['location']['offset'] as int,
);
}
final String severity;
final String type;
final String message;
final String code;
final String file;
final int startLine;
final int startColumn;
final int offset;
static final Map<String, _AnalysisSeverity> _severityMap = <String, _AnalysisSeverity>{
'INFO': _AnalysisSeverity.info,
'WARNING': _AnalysisSeverity.warning,
'ERROR': _AnalysisSeverity.error,
};
_AnalysisSeverity get severityLevel =>
_severityMap[severity] ?? _AnalysisSeverity.none;
String get messageSentenceFragment {
if (message.endsWith('.')) {
return message.substring(0, message.length - 1);
}
return message;
}
@override
String toString() {
return '[${severity.toLowerCase()}] $messageSentenceFragment ($file:$startLine:$startColumn)'; return '[${severity.toLowerCase()}] $messageSentenceFragment ($file:$startLine:$startColumn)';
} }
} }
......
...@@ -6,6 +6,7 @@ import 'package:file/file.dart'; ...@@ -6,6 +6,7 @@ import 'package:file/file.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/analyze_base.dart'; import 'package:flutter_tools/src/commands/analyze_base.dart';
import 'package:flutter_tools/src/dart/analysis.dart';
import '../../src/common.dart'; import '../../src/common.dart';
...@@ -43,6 +44,24 @@ void main() { ...@@ -43,6 +44,24 @@ void main() {
inRepo(null, fileSystem); inRepo(null, fileSystem);
inRepo(<String>[], fileSystem); inRepo(<String>[], fileSystem);
}); });
testWithoutContext('AnalysisError from json write correct', () {
final Map<String, dynamic> json = <String, dynamic>{
'severity': 'INFO',
'type': 'TODO',
'location': <String, dynamic>{
'file': '/Users/.../lib/test.dart',
'offset': 362,
'length': 72,
'startLine': 15,
'startColumn': 4
},
'message': 'Prefer final for variable declarations if they are not reassigned.',
'hasFix': false
};
expect(WrittenError.fromJson(json).toString(),
'[info] Prefer final for variable declarations if they are not reassigned (/Users/.../lib/test.dart:15:4)');
});
} }
bool inRepo(List<String> fileList, FileSystem fileSystem) { bool inRepo(List<String> fileList, FileSystem fileSystem) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment