mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
[flutter_tools] Separate style and data from AnalysisError (#60591)
This commit is contained in:
parent
c65f32f447
commit
72258eac5f
@ -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 {
|
|||||||
// 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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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> {
|
|||||||
_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;
|
||||||
|
|
||||||
|
String get _separator => _platform.isWindows ? '-' : '•';
|
||||||
|
|
||||||
|
String get colorSeverity {
|
||||||
|
switch (writtenError.severityLevel) {
|
||||||
|
case _AnalysisSeverity.error:
|
||||||
|
return _terminal.color(writtenError.severity, TerminalColor.red);
|
||||||
|
case _AnalysisSeverity.warning:
|
||||||
|
return _terminal.color(writtenError.severity, TerminalColor.yellow);
|
||||||
|
case _AnalysisSeverity.info:
|
||||||
|
case _AnalysisSeverity.none:
|
||||||
|
return writtenError.severity;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String get type => writtenError.type;
|
||||||
|
String get code => writtenError.code;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int compareTo(AnalysisError other) {
|
||||||
|
// Sort in order of file path, error location, severity, and message.
|
||||||
|
if (writtenError.file != other.writtenError.file) {
|
||||||
|
return writtenError.file.compareTo(other.writtenError.file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writtenError.offset != other.writtenError.offset) {
|
||||||
|
return writtenError.offset - other.writtenError.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int diff = other.writtenError.severityLevel.index -
|
||||||
|
writtenError.severityLevel.index;
|
||||||
|
if (diff != 0) {
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return writtenError.message.compareTo(other.writtenError.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
// Can't use "padLeft" because of ANSI color sequences in the colorized
|
||||||
|
// severity.
|
||||||
|
final String padding = ' ' * math.max(0, 7 - writtenError.severity.length);
|
||||||
|
return '$padding${colorSeverity.toLowerCase()} $_separator '
|
||||||
|
'${writtenError.messageSentenceFragment} $_separator '
|
||||||
|
'${_fileSystem.path.relative(writtenError.file)}:${writtenError.startLine}:${writtenError.startColumn} $_separator '
|
||||||
|
'$code';
|
||||||
|
}
|
||||||
|
|
||||||
|
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>{
|
static final Map<String, _AnalysisSeverity> _severityMap = <String, _AnalysisSeverity>{
|
||||||
'INFO': _AnalysisSeverity.info,
|
'INFO': _AnalysisSeverity.info,
|
||||||
'WARNING': _AnalysisSeverity.warning,
|
'WARNING': _AnalysisSeverity.warning,
|
||||||
'ERROR': _AnalysisSeverity.error,
|
'ERROR': _AnalysisSeverity.error,
|
||||||
};
|
};
|
||||||
|
|
||||||
String get _separator => _platform.isWindows ? '-' : '•';
|
_AnalysisSeverity get severityLevel =>
|
||||||
|
_severityMap[severity] ?? _AnalysisSeverity.none;
|
||||||
// "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 {
|
|
||||||
switch(_severityLevel) {
|
|
||||||
case _AnalysisSeverity.error:
|
|
||||||
return _terminal.color(severity, TerminalColor.red);
|
|
||||||
case _AnalysisSeverity.warning:
|
|
||||||
return _terminal.color(severity, TerminalColor.yellow);
|
|
||||||
case _AnalysisSeverity.info:
|
|
||||||
case _AnalysisSeverity.none:
|
|
||||||
return severity;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
int get startLine => json['location']['startLine'] as int;
|
|
||||||
int get startColumn => json['location']['startColumn'] as int;
|
|
||||||
int get offset => json['location']['offset'] as int;
|
|
||||||
|
|
||||||
String get messageSentenceFragment {
|
String get messageSentenceFragment {
|
||||||
if (message.endsWith('.')) {
|
if (message.endsWith('.')) {
|
||||||
return message.substring(0, message.length - 1);
|
return message.substring(0, message.length - 1);
|
||||||
} else {
|
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
}
|
return message;
|
||||||
|
|
||||||
@override
|
|
||||||
int compareTo(AnalysisError other) {
|
|
||||||
// Sort in order of file path, error location, severity, and message.
|
|
||||||
if (file != other.file) {
|
|
||||||
return file.compareTo(other.file);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset != other.offset) {
|
|
||||||
return offset - other.offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int diff = other._severityLevel.index - _severityLevel.index;
|
|
||||||
if (diff != 0) {
|
|
||||||
return diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
return message.compareTo(other.message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
// Can't use "padLeft" because of ANSI color sequences in the colorized
|
|
||||||
// severity.
|
|
||||||
final String padding = ' ' * math.max(0, 7 - severity.length);
|
|
||||||
return '$padding${colorSeverity.toLowerCase()} $_separator '
|
|
||||||
'$messageSentenceFragment $_separator '
|
|
||||||
'${_fileSystem.path.relative(file)}:$startLine:$startColumn $_separator '
|
|
||||||
'$code';
|
|
||||||
}
|
|
||||||
|
|
||||||
String toLegacyString() {
|
|
||||||
return '[${severity.toLowerCase()}] $messageSentenceFragment ($file:$startLine:$startColumn)';
|
return '[${severity.toLowerCase()}] $messageSentenceFragment ($file:$startLine:$startColumn)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
|||||||
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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user