diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html index 3f5c00c6ebfe..7e5dc0128a6c 100644 --- a/pkg/analysis_server/doc/api.html +++ b/pkg/analysis_server/doc/api.html @@ -2083,6 +2083,7 @@
request: { "id": String "method": "edit.format" diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart index 2a888ca4f665..2ba9eea23a2d 100644 --- a/pkg/analysis_server/lib/protocol/protocol_constants.dart +++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart @@ -164,6 +164,8 @@ const String DIAGNOSTIC_REQUEST_GET_DIAGNOSTICS = 'diagnostic.getDiagnostics'; const String DIAGNOSTIC_REQUEST_GET_SERVER_PORT = 'diagnostic.getServerPort'; const String DIAGNOSTIC_RESPONSE_GET_DIAGNOSTICS_CONTEXTS = 'contexts'; const String DIAGNOSTIC_RESPONSE_GET_SERVER_PORT_PORT = 'port'; +const String EDIT_REQUEST_BULK_FIXES = 'edit.bulkFixes'; +const String EDIT_REQUEST_BULK_FIXES_INCLUDED = 'included'; const String EDIT_REQUEST_DARTFIX = 'edit.dartfix'; const String EDIT_REQUEST_DARTFIX_EXCLUDED_FIXES = 'excludedFixes'; const String EDIT_REQUEST_DARTFIX_INCLUDED = 'included'; @@ -220,6 +222,7 @@ const String EDIT_REQUEST_ORGANIZE_DIRECTIVES = 'edit.organizeDirectives'; const String EDIT_REQUEST_ORGANIZE_DIRECTIVES_FILE = 'file'; const String EDIT_REQUEST_SORT_MEMBERS = 'edit.sortMembers'; const String EDIT_REQUEST_SORT_MEMBERS_FILE = 'file'; +const String EDIT_RESPONSE_BULK_FIXES_EDITS = 'edits'; const String EDIT_RESPONSE_DARTFIX_DETAILS = 'details'; const String EDIT_RESPONSE_DARTFIX_EDITS = 'edits'; const String EDIT_RESPONSE_DARTFIX_HAS_ERRORS = 'hasErrors'; diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart index c6fe18db0859..51ece87fd712 100644 --- a/pkg/analysis_server/lib/protocol/protocol_generated.dart +++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart @@ -7115,6 +7115,180 @@ class DiagnosticGetServerPortResult implements ResponseResult { } } +/// edit.bulkFixes params +/// +/// { +/// "included": List+/// } +/// +/// Clients may not extend, implement or mix-in this class. +class EditBulkFixesParams implements RequestParams { + List _included; + + /// A list of the files and directories for which edits should be suggested. + /// + /// If a request is made with a path that is invalid, e.g. is not absolute + /// and normalized, an error of type INVALID_FILE_PATH_FORMAT will be + /// generated. If a request is made for a file which does not exist, or which + /// is not currently subject to analysis (e.g. because it is not associated + /// with any analysis root specified to analysis.setAnalysisRoots), an error + /// of type FILE_NOT_ANALYZED will be generated. + List get included => _included; + + /// A list of the files and directories for which edits should be suggested. + /// + /// If a request is made with a path that is invalid, e.g. is not absolute + /// and normalized, an error of type INVALID_FILE_PATH_FORMAT will be + /// generated. If a request is made for a file which does not exist, or which + /// is not currently subject to analysis (e.g. because it is not associated + /// with any analysis root specified to analysis.setAnalysisRoots), an error + /// of type FILE_NOT_ANALYZED will be generated. + set included(List value) { + assert(value != null); + _included = value; + } + + EditBulkFixesParams(List included) { + this.included = included; + } + + factory EditBulkFixesParams.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + json ??= {}; + if (json is Map) { + List included; + if (json.containsKey('included')) { + included = jsonDecoder.decodeList( + jsonPath + '.included', json['included'], jsonDecoder.decodeString); + } else { + throw jsonDecoder.mismatch(jsonPath, 'included'); + } + return EditBulkFixesParams(included); + } else { + throw jsonDecoder.mismatch(jsonPath, 'edit.bulkFixes params', json); + } + } + + factory EditBulkFixesParams.fromRequest(Request request) { + return EditBulkFixesParams.fromJson( + RequestDecoder(request), 'params', request.params); + } + + @override + Map toJson() { + var result = {}; + result['included'] = included; + return result; + } + + @override + Request toRequest(String id) { + return Request(id, 'edit.bulkFixes', toJson()); + } + + @override + String toString() => json.encode(toJson()); + + @override + bool operator ==(other) { + if (other is EditBulkFixesParams) { + return listEqual( + included, other.included, (String a, String b) => a == b); + } + return false; + } + + @override + int get hashCode { + var hash = 0; + hash = JenkinsSmiHash.combine(hash, included.hashCode); + return JenkinsSmiHash.finish(hash); + } +} + +/// edit.bulkFixes result +/// +/// { +/// "edits": List +/// } +/// +/// Clients may not extend, implement or mix-in this class. +class EditBulkFixesResult implements ResponseResult { + List _edits; + + /// A list of source edits to apply the recommended changes. + List get edits => _edits; + + /// A list of source edits to apply the recommended changes. + set edits(List value) { + assert(value != null); + _edits = value; + } + + EditBulkFixesResult(List edits) { + this.edits = edits; + } + + factory EditBulkFixesResult.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + json ??= {}; + if (json is Map) { + List edits; + if (json.containsKey('edits')) { + edits = jsonDecoder.decodeList( + jsonPath + '.edits', + json['edits'], + (String jsonPath, Object json) => + SourceFileEdit.fromJson(jsonDecoder, jsonPath, json)); + } else { + throw jsonDecoder.mismatch(jsonPath, 'edits'); + } + return EditBulkFixesResult(edits); + } else { + throw jsonDecoder.mismatch(jsonPath, 'edit.bulkFixes result', json); + } + } + + factory EditBulkFixesResult.fromResponse(Response response) { + return EditBulkFixesResult.fromJson( + ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), + 'result', + response.result); + } + + @override + Map toJson() { + var result = {}; + result['edits'] = + edits.map((SourceFileEdit value) => value.toJson()).toList(); + return result; + } + + @override + Response toResponse(String id) { + return Response(id, result: toJson()); + } + + @override + String toString() => json.encode(toJson()); + + @override + bool operator ==(other) { + if (other is EditBulkFixesResult) { + return listEqual( + edits, other.edits, (SourceFileEdit a, SourceFileEdit b) => a == b); + } + return false; + } + + @override + int get hashCode { + var hash = 0; + hash = JenkinsSmiHash.combine(hash, edits.hashCode); + return JenkinsSmiHash.finish(hash); + } +} + /// edit.dartfix params /// /// { diff --git a/pkg/analysis_server/lib/src/edit/edit_bulk_fixes.dart b/pkg/analysis_server/lib/src/edit/edit_bulk_fixes.dart new file mode 100644 index 000000000000..0b4caeecb03b --- /dev/null +++ b/pkg/analysis_server/lib/src/edit/edit_bulk_fixes.dart @@ -0,0 +1,19 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// 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. + +import 'package:analysis_server/protocol/protocol.dart'; +import 'package:analysis_server/protocol/protocol_generated.dart'; +import 'package:analysis_server/src/analysis_server.dart'; + +class EditBulkFixes { + final AnalysisServer server; + final Request request; + + EditBulkFixes(this.server, this.request); + + Future compute() async { + // todo (pq): implemennt + return EditBulkFixesResult([]).toResponse(request.id); + } +} diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart index 7868d544a77a..0792f83bef88 100644 --- a/pkg/analysis_server/lib/src/edit/edit_domain.dart +++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart @@ -12,6 +12,8 @@ import 'package:analysis_server/src/collections.dart'; import 'package:analyzer/src/exception/exception.dart'; import 'package:analysis_server/src/computer/import_elements_computer.dart'; import 'package:analysis_server/src/domain_abstract.dart'; +import 'package:analysis_server/src/edit/edit_bulk_fixes.dart' + show EditBulkFixes; import 'package:analysis_server/src/edit/edit_dartfix.dart' show EditDartFix; import 'package:analysis_server/src/edit/fix/dartfix_info.dart' show allFixes; import 'package:analysis_server/src/plugin/plugin_manager.dart'; @@ -92,6 +94,21 @@ class EditDomainHandler extends AbstractRequestHandler { _newRefactoringManager(); } + Future bulkFixes(Request request) async { + // + // Compute fixes + // + try { + var bulkFix = EditBulkFixes(server, request); + var response = await bulkFix.compute(); + + server.sendResponse(response); + } catch (exception, stackTrace) { + server.sendServerErrorNotification('Exception while getting bulk fixes', + CaughtException(exception, stackTrace), stackTrace); + } + } + Future dartfix(Request request) async { // TODO(danrubel): Add support for dartfix plugins @@ -356,6 +373,9 @@ class EditDomainHandler extends AbstractRequestHandler { return Response.DELAYED_RESPONSE; } else if (requestName == EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS) { return _getAvailableRefactorings(request); + } else if (requestName == EDIT_REQUEST_BULK_FIXES) { + bulkFixes(request); + return Response.DELAYED_RESPONSE; } else if (requestName == EDIT_REQUEST_GET_DARTFIX_INFO) { return getDartfixInfo(request); } else if (requestName == EDIT_REQUEST_GET_FIXES) { diff --git a/pkg/analysis_server/test/integration/coverage.md b/pkg/analysis_server/test/integration/coverage.md index 20ee12ce5666..06b628ae09e2 100644 --- a/pkg/analysis_server/test/integration/coverage.md +++ b/pkg/analysis_server/test/integration/coverage.md @@ -44,6 +44,7 @@ server calls. This file is validated by `coverage_test.dart`. - [x] diagnostic.getServerPort ## edit domain +- [x] edit.bulkFixes - [x] edit.dartfix - [x] edit.format - [x] edit.getAssists diff --git a/pkg/analysis_server/test/integration/edit/bulk_fixes_test.dart b/pkg/analysis_server/test/integration/edit/bulk_fixes_test.dart new file mode 100644 index 000000000000..922c0c8047ea --- /dev/null +++ b/pkg/analysis_server/test/integration/edit/bulk_fixes_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// 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. + +import 'package:test/test.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../support/integration_tests.dart'; + +void main() { + defineReflectiveSuite(() { + defineReflectiveTests(BulkFixesTest); + }); +} + +@reflectiveTest +class BulkFixesTest extends AbstractAnalysisServerIntegrationTest { + void setupTarget() { + writeFile(sourcePath('test.dart'), ''' +class A { + void f() {} +} +class B extends A { + void f() { } +} +'''); + standardAnalysisSetup(); + } + + @failingTest + Future test_bulk_fix_override() async { + setupTarget(); + + var result = await sendEditBulkFixes([sourceDirectory.path]); + expect(result.edits.length, 1); + } +} diff --git a/pkg/analysis_server/test/integration/edit/test_all.dart b/pkg/analysis_server/test/integration/edit/test_all.dart index 3ac606c800e4..5c3a6534d86b 100644 --- a/pkg/analysis_server/test/integration/edit/test_all.dart +++ b/pkg/analysis_server/test/integration/edit/test_all.dart @@ -4,6 +4,7 @@ import 'package:test_reflective_loader/test_reflective_loader.dart'; +import 'bulk_fixes_test.dart' as bulk_fixes_test; import 'dartfix_test.dart' as dartfix_test; import 'format_test.dart' as format_test; import 'get_assists_test.dart' as get_assists_test; @@ -24,6 +25,7 @@ import 'sort_members_test.dart' as sort_members_test; void main() { defineReflectiveSuite(() { + bulk_fixes_test.main(); dartfix_test.main(); format_test.main(); get_assists_test.main(); diff --git a/pkg/analysis_server/test/integration/support/integration_test_methods.dart b/pkg/analysis_server/test/integration/support/integration_test_methods.dart index 744785a12a6f..9799790605ad 100644 --- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart +++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart @@ -1562,6 +1562,38 @@ abstract class IntegrationTestMixin { return EditGetDartfixInfoResult.fromJson(decoder, 'result', result); } + /// Analyze the specified sources for fixes that can be applied in bulk and + /// return a set of suggested edits for those sources. These edits may + /// include changes to sources outside the set of specified sources if a + /// change in a specified source requires it. + /// + /// Parameters + /// + /// included: List + /// + /// A list of the files and directories for which edits should be + /// suggested. + /// + /// If a request is made with a path that is invalid, e.g. is not absolute + /// and normalized, an error of type INVALID_FILE_PATH_FORMAT will be + /// generated. If a request is made for a file which does not exist, or + /// which is not currently subject to analysis (e.g. because it is not + /// associated with any analysis root specified to + /// analysis.setAnalysisRoots), an error of type FILE_NOT_ANALYZED will be + /// generated. + /// + /// Returns + /// + /// edits: List + /// + /// A list of source edits to apply the recommended changes. + Future sendEditBulkFixes(List included) async { + var params = EditBulkFixesParams(included).toJson(); + var result = await server.send('edit.bulkFixes', params); + var decoder = ResponseDecoder(null); + return EditBulkFixesResult.fromJson(decoder, 'result', result); + } + /// Analyze the specified sources for recommended changes and return a set of /// suggested edits for those sources. These edits may include changes to /// sources outside the set of specified sources if a change in a specified diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart index 6764831dd9c8..f4736c1dec84 100644 --- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart +++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart @@ -2205,6 +2205,22 @@ final Matcher isDiagnosticGetServerPortParams = isNull; final Matcher isDiagnosticGetServerPortResult = LazyMatcher(() => MatchesJsonObject('diagnostic.getServerPort result', {'port': isInt})); +/// edit.bulkFixes params +/// +/// { +/// "included": List +/// } +final Matcher isEditBulkFixesParams = LazyMatcher(() => MatchesJsonObject( + 'edit.bulkFixes params', {'included': isListOf(isFilePath)})); + +/// edit.bulkFixes result +/// +/// { +/// "edits": List +/// } +final Matcher isEditBulkFixesResult = LazyMatcher(() => MatchesJsonObject( + 'edit.bulkFixes result', {'edits': isListOf(isSourceFileEdit)})); + /// edit.dartfix params /// /// { diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java index 388a2c7b9c57..ee2d9878e3d2 100644 --- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java +++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java @@ -468,6 +468,22 @@ public interface AnalysisServer { */ public void diagnostic_getServerPort(GetServerPortConsumer consumer); + /** + * {@code edit.bulkFixes} + * + * Analyze the specified sources for fixes that can be applied in bulk and return a set of + * suggested edits for those sources. These edits may include changes to sources outside the set of + * specified sources if a change in a specified source requires it. + * + * @param included A list of the files and directories for which edits should be suggested. If a + * request is made with a path that is invalid, e.g. is not absolute and normalized, an + * error of type INVALID_FILE_PATH_FORMAT will be generated. If a request is made for a + * file which does not exist, or which is not currently subject to analysis (e.g. because + * it is not associated with any analysis root specified to analysis.setAnalysisRoots), an + * error of type FILE_NOT_ANALYZED will be generated. + */ + public void edit_bulkFixes(List included, BulkFixesConsumer consumer); + /** * {@code edit.dartfix} * diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html index 81cfb216854f..5a3e9d2b4d48 100644 --- a/pkg/analysis_server/tool/spec/spec_input.html +++ b/pkg/analysis_server/tool/spec/spec_input.html @@ -2160,6 +2160,44 @@ Options
++ + Analyze the specified sources for fixes that can be applied in bulk + and return a set of suggested edits for those sources. + These edits may include changes to sources outside the set + of specified sources if a change in a specified source requires it. +
++ ++ ++ FilePath +
++ A list of the files and directories for which edits should be + suggested. +
++ If a request is made with a path that is invalid, e.g. is not absolute + and normalized, an error of type INVALID_FILE_PATH_FORMAT + will be generated. If a request is made for a file which does not + exist, or which is not currently subject to analysis (e.g. because it + is not associated with any analysis root specified to + analysis.setAnalysisRoots), an error of type + FILE_NOT_ANALYZED will be generated. +
++ ++ ++ SourceFileEdit +
++ A list of source edits to apply the recommended changes. +
+Analyze the specified sources for recommended changes diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart index 2a888ca4f665..2ba9eea23a2d 100644 --- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart +++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart @@ -164,6 +164,8 @@ const String DIAGNOSTIC_REQUEST_GET_DIAGNOSTICS = 'diagnostic.getDiagnostics'; const String DIAGNOSTIC_REQUEST_GET_SERVER_PORT = 'diagnostic.getServerPort'; const String DIAGNOSTIC_RESPONSE_GET_DIAGNOSTICS_CONTEXTS = 'contexts'; const String DIAGNOSTIC_RESPONSE_GET_SERVER_PORT_PORT = 'port'; +const String EDIT_REQUEST_BULK_FIXES = 'edit.bulkFixes'; +const String EDIT_REQUEST_BULK_FIXES_INCLUDED = 'included'; const String EDIT_REQUEST_DARTFIX = 'edit.dartfix'; const String EDIT_REQUEST_DARTFIX_EXCLUDED_FIXES = 'excludedFixes'; const String EDIT_REQUEST_DARTFIX_INCLUDED = 'included'; @@ -220,6 +222,7 @@ const String EDIT_REQUEST_ORGANIZE_DIRECTIVES = 'edit.organizeDirectives'; const String EDIT_REQUEST_ORGANIZE_DIRECTIVES_FILE = 'file'; const String EDIT_REQUEST_SORT_MEMBERS = 'edit.sortMembers'; const String EDIT_REQUEST_SORT_MEMBERS_FILE = 'file'; +const String EDIT_RESPONSE_BULK_FIXES_EDITS = 'edits'; const String EDIT_RESPONSE_DARTFIX_DETAILS = 'details'; const String EDIT_RESPONSE_DARTFIX_EDITS = 'edits'; const String EDIT_RESPONSE_DARTFIX_HAS_ERRORS = 'hasErrors'; diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart index a9a1cf018b10..29ae9ac19050 100644 --- a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart +++ b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart @@ -7115,6 +7115,180 @@ class DiagnosticGetServerPortResult implements ResponseResult { } } +/// edit.bulkFixes params +/// +/// { +/// "included": List
+/// } +/// +/// Clients may not extend, implement or mix-in this class. +class EditBulkFixesParams implements RequestParams { + List _included; + + /// A list of the files and directories for which edits should be suggested. + /// + /// If a request is made with a path that is invalid, e.g. is not absolute + /// and normalized, an error of type INVALID_FILE_PATH_FORMAT will be + /// generated. If a request is made for a file which does not exist, or which + /// is not currently subject to analysis (e.g. because it is not associated + /// with any analysis root specified to analysis.setAnalysisRoots), an error + /// of type FILE_NOT_ANALYZED will be generated. + List get included => _included; + + /// A list of the files and directories for which edits should be suggested. + /// + /// If a request is made with a path that is invalid, e.g. is not absolute + /// and normalized, an error of type INVALID_FILE_PATH_FORMAT will be + /// generated. If a request is made for a file which does not exist, or which + /// is not currently subject to analysis (e.g. because it is not associated + /// with any analysis root specified to analysis.setAnalysisRoots), an error + /// of type FILE_NOT_ANALYZED will be generated. + set included(List value) { + assert(value != null); + _included = value; + } + + EditBulkFixesParams(List included) { + this.included = included; + } + + factory EditBulkFixesParams.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + json ??= {}; + if (json is Map) { + List included; + if (json.containsKey('included')) { + included = jsonDecoder.decodeList( + jsonPath + '.included', json['included'], jsonDecoder.decodeString); + } else { + throw jsonDecoder.mismatch(jsonPath, 'included'); + } + return EditBulkFixesParams(included); + } else { + throw jsonDecoder.mismatch(jsonPath, 'edit.bulkFixes params', json); + } + } + + factory EditBulkFixesParams.fromRequest(Request request) { + return EditBulkFixesParams.fromJson( + RequestDecoder(request), 'params', request.params); + } + + @override + Map toJson() { + var result = {}; + result['included'] = included; + return result; + } + + @override + Request toRequest(String id) { + return Request(id, 'edit.bulkFixes', toJson()); + } + + @override + String toString() => json.encode(toJson()); + + @override + bool operator ==(other) { + if (other is EditBulkFixesParams) { + return listEqual( + included, other.included, (String a, String b) => a == b); + } + return false; + } + + @override + int get hashCode { + var hash = 0; + hash = JenkinsSmiHash.combine(hash, included.hashCode); + return JenkinsSmiHash.finish(hash); + } +} + +/// edit.bulkFixes result +/// +/// { +/// "edits": List +/// } +/// +/// Clients may not extend, implement or mix-in this class. +class EditBulkFixesResult implements ResponseResult { + List _edits; + + /// A list of source edits to apply the recommended changes. + List get edits => _edits; + + /// A list of source edits to apply the recommended changes. + set edits(List value) { + assert(value != null); + _edits = value; + } + + EditBulkFixesResult(List edits) { + this.edits = edits; + } + + factory EditBulkFixesResult.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + json ??= {}; + if (json is Map) { + List edits; + if (json.containsKey('edits')) { + edits = jsonDecoder.decodeList( + jsonPath + '.edits', + json['edits'], + (String jsonPath, Object json) => + SourceFileEdit.fromJson(jsonDecoder, jsonPath, json)); + } else { + throw jsonDecoder.mismatch(jsonPath, 'edits'); + } + return EditBulkFixesResult(edits); + } else { + throw jsonDecoder.mismatch(jsonPath, 'edit.bulkFixes result', json); + } + } + + factory EditBulkFixesResult.fromResponse(Response response) { + return EditBulkFixesResult.fromJson( + ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)), + 'result', + response.result); + } + + @override + Map toJson() { + var result = {}; + result['edits'] = + edits.map((SourceFileEdit value) => value.toJson()).toList(); + return result; + } + + @override + Response toResponse(String id) { + return Response(id, result: toJson()); + } + + @override + String toString() => json.encode(toJson()); + + @override + bool operator ==(other) { + if (other is EditBulkFixesResult) { + return listEqual( + edits, other.edits, (SourceFileEdit a, SourceFileEdit b) => a == b); + } + return false; + } + + @override + int get hashCode { + var hash = 0; + hash = JenkinsSmiHash.combine(hash, edits.hashCode); + return JenkinsSmiHash.finish(hash); + } +} + /// edit.dartfix params /// /// {