diff --git a/pkgs/dart_services/analysis_options.yaml b/pkgs/dart_services/analysis_options.yaml index 90258da1c..30c1f2760 100644 --- a/pkgs/dart_services/analysis_options.yaml +++ b/pkgs/dart_services/analysis_options.yaml @@ -12,6 +12,8 @@ analyzer: errors: lines_longer_than_80_chars: ignore unreachable_from_main: ignore + # Remove this once we remove the AnalysisIssue.sourceName field. + deprecated_member_use_from_same_package: ignore linter: rules: diff --git a/pkgs/dart_services/lib/src/analysis_server.dart b/pkgs/dart_services/lib/src/analysis_server.dart index 49b621214..ad11c485e 100644 --- a/pkgs/dart_services/lib/src/analysis_server.dart +++ b/pkgs/dart_services/lib/src/analysis_server.dart @@ -381,6 +381,7 @@ abstract class AnalysisServerWrapper { error.contextMessages?.map((m) => proto.DiagnosticMessage() ..message = utils.normalizeFilePaths(m.message) ..line = m.location.startLine + ..column = m.location.startColumn ..charStart = m.location.offset ..charLength = m.location.length) ?? [], diff --git a/pkgs/dart_services/lib/src/common_server_api.dart b/pkgs/dart_services/lib/src/common_server_api.dart index f93432bd0..74121111a 100644 --- a/pkgs/dart_services/lib/src/common_server_api.dart +++ b/pkgs/dart_services/lib/src/common_server_api.dart @@ -17,6 +17,7 @@ import 'protos/dart_services.pb.dart' as proto; import 'pub.dart'; import 'scheduler.dart'; import 'shared/model.dart' as api; +import 'shared/services.dart'; import 'shelf_cors.dart' as shelf_cors; export 'common_server_impl.dart' show log; @@ -62,12 +63,25 @@ class CommonServerApi { return api.AnalysisIssue( kind: issue.kind, message: issue.message, + location: api.Location( + charStart: issue.charStart, + charLength: issue.charLength, + line: issue.line, + column: issue.column, + ), correction: issue.hasCorrection() ? issue.correction : null, url: issue.hasUrl() ? issue.url : null, - charStart: issue.charStart, - charLength: issue.charLength, - line: issue.line, - column: issue.column, + contextMessages: issue.diagnosticMessages.map((diagnostic) { + return api.DiagnosticMessage( + message: diagnostic.message, + location: Location( + charStart: diagnostic.charStart, + charLength: diagnostic.charLength, + line: diagnostic.line, + column: diagnostic.column, + ), + ); + }).toList(), ); }).toList(), packageImports: result.packageImports, diff --git a/pkgs/dart_services/lib/src/protos/dart_services.pb.dart b/pkgs/dart_services/lib/src/protos/dart_services.pb.dart index 49a94aa46..bb16c423e 100644 --- a/pkgs/dart_services/lib/src/protos/dart_services.pb.dart +++ b/pkgs/dart_services/lib/src/protos/dart_services.pb.dart @@ -888,6 +888,7 @@ class DiagnosticMessage extends $pb.GeneratedMessage { $core.int? line, $core.int? charStart, $core.int? charLength, + $core.int? column, }) { final $result = create(); if (message != null) { @@ -902,6 +903,9 @@ class DiagnosticMessage extends $pb.GeneratedMessage { if (charLength != null) { $result.charLength = charLength; } + if (column != null) { + $result.column = column; + } return $result; } DiagnosticMessage._() : super(); @@ -923,6 +927,7 @@ class DiagnosticMessage extends $pb.GeneratedMessage { protoName: 'charStart') ..a<$core.int>(4, _omitFieldNames ? '' : 'charLength', $pb.PbFieldType.O3, protoName: 'charLength') + ..a<$core.int>(5, _omitFieldNames ? '' : 'column', $pb.PbFieldType.O3) ..hasRequiredFields = false; @$core.Deprecated('Using this can add significant overhead to your binary. ' @@ -995,6 +1000,18 @@ class DiagnosticMessage extends $pb.GeneratedMessage { $core.bool hasCharLength() => $_has(3); @$pb.TagNumber(4) void clearCharLength() => clearField(4); + + @$pb.TagNumber(5) + $core.int get column => $_getIZ(4); + @$pb.TagNumber(5) + set column($core.int v) { + $_setSignedInt32(4, v); + } + + @$pb.TagNumber(5) + $core.bool hasColumn() => $_has(4); + @$pb.TagNumber(5) + void clearColumn() => clearField(5); } class VersionRequest extends $pb.GeneratedMessage { diff --git a/pkgs/dart_services/lib/src/protos/dart_services.pbjson.dart b/pkgs/dart_services/lib/src/protos/dart_services.pbjson.dart index 26d416a56..73e4ce511 100644 --- a/pkgs/dart_services/lib/src/protos/dart_services.pbjson.dart +++ b/pkgs/dart_services/lib/src/protos/dart_services.pbjson.dart @@ -271,6 +271,7 @@ const DiagnosticMessage$json = { {'1': 'line', '3': 2, '4': 1, '5': 5, '10': 'line'}, {'1': 'charStart', '3': 3, '4': 1, '5': 5, '10': 'charStart'}, {'1': 'charLength', '3': 4, '4': 1, '5': 5, '10': 'charLength'}, + {'1': 'column', '3': 5, '4': 1, '5': 5, '10': 'column'}, ], }; @@ -278,7 +279,7 @@ const DiagnosticMessage$json = { final $typed_data.Uint8List diagnosticMessageDescriptor = $convert.base64Decode( 'ChFEaWFnbm9zdGljTWVzc2FnZRIYCgdtZXNzYWdlGAEgASgJUgdtZXNzYWdlEhIKBGxpbmUYAi' 'ABKAVSBGxpbmUSHAoJY2hhclN0YXJ0GAMgASgFUgljaGFyU3RhcnQSHgoKY2hhckxlbmd0aBgE' - 'IAEoBVIKY2hhckxlbmd0aA=='); + 'IAEoBVIKY2hhckxlbmd0aBIWCgZjb2x1bW4YBSABKAVSBmNvbHVtbg=='); @$core.Deprecated('Use versionRequestDescriptor instead') const VersionRequest$json = { diff --git a/pkgs/dart_services/lib/src/shared/model.dart b/pkgs/dart_services/lib/src/shared/model.dart index 61897cbf0..50b093274 100644 --- a/pkgs/dart_services/lib/src/shared/model.dart +++ b/pkgs/dart_services/lib/src/shared/model.dart @@ -42,22 +42,21 @@ class AnalysisResponse { class AnalysisIssue { final String kind; final String message; + final Location location; final String? correction; final String? url; - final int charStart; - final int charLength; - final int line; - final int column; + final List? contextMessages; + @Deprecated('Remove this once no longer referenced') + final String sourceName; AnalysisIssue({ required this.kind, required this.message, + required this.location, this.correction, this.url, - this.charStart = -1, - this.charLength = 0, - this.line = -1, - this.column = -1, + this.contextMessages, + this.sourceName = 'main.dart', }); factory AnalysisIssue.fromJson(Map json) => @@ -69,6 +68,42 @@ class AnalysisIssue { String toString() => '[$kind] $message'; } +@JsonSerializable() +class Location { + final int charStart; + final int charLength; + final int line; + final int column; + + Location({ + this.charStart = -1, + this.charLength = 0, + this.line = -1, + this.column = -1, + }); + + factory Location.fromJson(Map json) => + _$LocationFromJson(json); + + Map toJson() => _$LocationToJson(this); +} + +@JsonSerializable() +class DiagnosticMessage { + final String message; + final Location location; + + DiagnosticMessage({ + required this.message, + required this.location, + }); + + factory DiagnosticMessage.fromJson(Map json) => + _$DiagnosticMessageFromJson(json); + + Map toJson() => _$DiagnosticMessageToJson(this); +} + @JsonSerializable() class CompileRequest { final String source; diff --git a/pkgs/dart_services/lib/src/shared/model.g.dart b/pkgs/dart_services/lib/src/shared/model.g.dart index 642d49aa4..f670137e0 100644 --- a/pkgs/dart_services/lib/src/shared/model.g.dart +++ b/pkgs/dart_services/lib/src/shared/model.g.dart @@ -38,26 +38,52 @@ AnalysisIssue _$AnalysisIssueFromJson(Map json) => AnalysisIssue( kind: json['kind'] as String, message: json['message'] as String, + location: Location.fromJson(json['location'] as Map), correction: json['correction'] as String?, url: json['url'] as String?, - charStart: json['charStart'] as int? ?? -1, - charLength: json['charLength'] as int? ?? 0, - line: json['line'] as int? ?? -1, - column: json['column'] as int? ?? -1, + contextMessages: (json['contextMessages'] as List?) + ?.map((e) => DiagnosticMessage.fromJson(e as Map)) + .toList(), + sourceName: json['sourceName'] as String? ?? 'main.dart', ); Map _$AnalysisIssueToJson(AnalysisIssue instance) => { 'kind': instance.kind, 'message': instance.message, + 'location': instance.location, 'correction': instance.correction, 'url': instance.url, + 'contextMessages': instance.contextMessages, + 'sourceName': instance.sourceName, + }; + +Location _$LocationFromJson(Map json) => Location( + charStart: json['charStart'] as int? ?? -1, + charLength: json['charLength'] as int? ?? 0, + line: json['line'] as int? ?? -1, + column: json['column'] as int? ?? -1, + ); + +Map _$LocationToJson(Location instance) => { 'charStart': instance.charStart, 'charLength': instance.charLength, 'line': instance.line, 'column': instance.column, }; +DiagnosticMessage _$DiagnosticMessageFromJson(Map json) => + DiagnosticMessage( + message: json['message'] as String, + location: Location.fromJson(json['location'] as Map), + ); + +Map _$DiagnosticMessageToJson(DiagnosticMessage instance) => + { + 'message': instance.message, + 'location': instance.location, + }; + CompileRequest _$CompileRequestFromJson(Map json) => CompileRequest( source: json['source'] as String, diff --git a/pkgs/dart_services/protos/dart_services.proto b/pkgs/dart_services/protos/dart_services.proto index 59b185d64..47353671c 100644 --- a/pkgs/dart_services/protos/dart_services.proto +++ b/pkgs/dart_services/protos/dart_services.proto @@ -91,6 +91,7 @@ message DiagnosticMessage { int32 line = 2; int32 charStart = 3; int32 charLength = 4; + int32 column = 5; } message VersionRequest {} diff --git a/pkgs/dart_services/test/server_v3_test.dart b/pkgs/dart_services/test/server_v3_test.dart index 6a4aa7013..059e3e4b5 100644 --- a/pkgs/dart_services/test/server_v3_test.dart +++ b/pkgs/dart_services/test/server_v3_test.dart @@ -95,7 +95,7 @@ void main() { issue.message, contains( "A value of type 'String' can't be assigned to a variable of type 'int'")); - expect(issue.line, 2); + expect(issue.location.line, 2); }); test('complete', () async { diff --git a/pkgs/dartpad_shared/analysis_options.yaml b/pkgs/dartpad_shared/analysis_options.yaml index c5bc1a8fc..9cfac8475 100644 --- a/pkgs/dartpad_shared/analysis_options.yaml +++ b/pkgs/dartpad_shared/analysis_options.yaml @@ -5,6 +5,9 @@ analyzer: strict-casts: true strict-inference: true strict-raw-types: true + errors: + # Remove this once we remove the AnalysisIssue.sourceName field. + deprecated_member_use_from_same_package: ignore linter: rules: diff --git a/pkgs/dartpad_shared/lib/model.dart b/pkgs/dartpad_shared/lib/model.dart index 61897cbf0..50b093274 100644 --- a/pkgs/dartpad_shared/lib/model.dart +++ b/pkgs/dartpad_shared/lib/model.dart @@ -42,22 +42,21 @@ class AnalysisResponse { class AnalysisIssue { final String kind; final String message; + final Location location; final String? correction; final String? url; - final int charStart; - final int charLength; - final int line; - final int column; + final List? contextMessages; + @Deprecated('Remove this once no longer referenced') + final String sourceName; AnalysisIssue({ required this.kind, required this.message, + required this.location, this.correction, this.url, - this.charStart = -1, - this.charLength = 0, - this.line = -1, - this.column = -1, + this.contextMessages, + this.sourceName = 'main.dart', }); factory AnalysisIssue.fromJson(Map json) => @@ -69,6 +68,42 @@ class AnalysisIssue { String toString() => '[$kind] $message'; } +@JsonSerializable() +class Location { + final int charStart; + final int charLength; + final int line; + final int column; + + Location({ + this.charStart = -1, + this.charLength = 0, + this.line = -1, + this.column = -1, + }); + + factory Location.fromJson(Map json) => + _$LocationFromJson(json); + + Map toJson() => _$LocationToJson(this); +} + +@JsonSerializable() +class DiagnosticMessage { + final String message; + final Location location; + + DiagnosticMessage({ + required this.message, + required this.location, + }); + + factory DiagnosticMessage.fromJson(Map json) => + _$DiagnosticMessageFromJson(json); + + Map toJson() => _$DiagnosticMessageToJson(this); +} + @JsonSerializable() class CompileRequest { final String source; diff --git a/pkgs/dartpad_shared/lib/model.g.dart b/pkgs/dartpad_shared/lib/model.g.dart index 642d49aa4..f670137e0 100644 --- a/pkgs/dartpad_shared/lib/model.g.dart +++ b/pkgs/dartpad_shared/lib/model.g.dart @@ -38,26 +38,52 @@ AnalysisIssue _$AnalysisIssueFromJson(Map json) => AnalysisIssue( kind: json['kind'] as String, message: json['message'] as String, + location: Location.fromJson(json['location'] as Map), correction: json['correction'] as String?, url: json['url'] as String?, - charStart: json['charStart'] as int? ?? -1, - charLength: json['charLength'] as int? ?? 0, - line: json['line'] as int? ?? -1, - column: json['column'] as int? ?? -1, + contextMessages: (json['contextMessages'] as List?) + ?.map((e) => DiagnosticMessage.fromJson(e as Map)) + .toList(), + sourceName: json['sourceName'] as String? ?? 'main.dart', ); Map _$AnalysisIssueToJson(AnalysisIssue instance) => { 'kind': instance.kind, 'message': instance.message, + 'location': instance.location, 'correction': instance.correction, 'url': instance.url, + 'contextMessages': instance.contextMessages, + 'sourceName': instance.sourceName, + }; + +Location _$LocationFromJson(Map json) => Location( + charStart: json['charStart'] as int? ?? -1, + charLength: json['charLength'] as int? ?? 0, + line: json['line'] as int? ?? -1, + column: json['column'] as int? ?? -1, + ); + +Map _$LocationToJson(Location instance) => { 'charStart': instance.charStart, 'charLength': instance.charLength, 'line': instance.line, 'column': instance.column, }; +DiagnosticMessage _$DiagnosticMessageFromJson(Map json) => + DiagnosticMessage( + message: json['message'] as String, + location: Location.fromJson(json['location'] as Map), + ); + +Map _$DiagnosticMessageToJson(DiagnosticMessage instance) => + { + 'message': instance.message, + 'location': instance.location, + }; + CompileRequest _$CompileRequestFromJson(Map json) => CompileRequest( source: json['source'] as String, diff --git a/pkgs/sketch_pad/lib/editor/editor.dart b/pkgs/sketch_pad/lib/editor/editor.dart index 64394a8ef..c1e70e135 100644 --- a/pkgs/sketch_pad/lib/editor/editor.dart +++ b/pkgs/sketch_pad/lib/editor/editor.dart @@ -93,13 +93,13 @@ class _EditorWidgetState extends State implements EditorService { @override void jumpTo(services.AnalysisIssue issue) { - final line = math.max(issue.line - 1, 0); - final column = math.max(issue.column - 1, 0); + final line = math.max(issue.location.line - 1, 0); + final column = math.max(issue.location.column - 1, 0); - if (issue.line != -1) { + if (issue.location.line != -1) { codeMirror!.doc.setSelection( Position(line, column), - head: Position(line, column + issue.charLength), + head: Position(line, column + issue.location.charLength), ); } else { codeMirror?.doc.setSelection(Position(0, 0)); @@ -202,12 +202,12 @@ class _EditorWidgetState extends State implements EditorService { } for (final issue in issues) { - final line = math.max(issue.line - 1, 0); - final column = math.max(issue.column - 1, 0); + final line = math.max(issue.location.line - 1, 0); + final column = math.max(issue.location.column - 1, 0); doc.markText( Position(line, column), - Position(line, column + issue.charLength), + Position(line, column + issue.location.charLength), className: 'squiggle-${issue.kind}', title: issue.message, ); diff --git a/pkgs/sketch_pad/lib/model.dart b/pkgs/sketch_pad/lib/model.dart index 64637db70..2338efaed 100644 --- a/pkgs/sketch_pad/lib/model.dart +++ b/pkgs/sketch_pad/lib/model.dart @@ -321,7 +321,7 @@ class AppServices { } catch (error) { final message = error is ApiRequestError ? error.message : '$error'; appModel.analysisIssues.value = [ - AnalysisIssue(kind: 'error', message: message), + AnalysisIssue(kind: 'error', message: message, location: Location()), ]; appModel.packageImports.value = []; } diff --git a/pkgs/sketch_pad/lib/problems.dart b/pkgs/sketch_pad/lib/problems.dart index 1a3506573..28d806cf0 100644 --- a/pkgs/sketch_pad/lib/problems.dart +++ b/pkgs/sketch_pad/lib/problems.dart @@ -93,7 +93,7 @@ class ProblemWidget extends StatelessWidget { ), ), Text( - ' line ${issue.line}, col ${issue.column}', + ' line ${issue.location.line}, col ${issue.location.column}', maxLines: 1, overflow: TextOverflow.clip, textAlign: TextAlign.end,