First cut dartfix protocol
and address comments in https://dart-review.googlesource.com/c/sdk/+/76320
Change-Id: I5c7ab40810d4116b1d36de90b7234d0a932bae82
Reviewed-on: https://dart-review.googlesource.com/76400
Commit-Queue: Dan Rubel <danrubel@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 5cfd272..f9056d7 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -1851,6 +1851,7 @@
+
<h3>Requests</h3><dl><dt class="request"><a name="request_edit.format">edit.format</a></dt><dd><div class="box"><pre>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 af80d5a..40d0ca6 100644
--- a/pkg/analysis_server/lib/protocol/protocol_constants.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart
@@ -125,6 +125,8 @@
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_DARTFIX = 'edit.dartfix';
+const String EDIT_REQUEST_DARTFIX_INCLUDED = 'included';
const String EDIT_REQUEST_FORMAT = 'edit.format';
const String EDIT_REQUEST_FORMAT_FILE = 'file';
const String EDIT_REQUEST_FORMAT_LINE_LENGTH = 'lineLength';
@@ -171,6 +173,8 @@
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_DARTFIX_DESCRIPTION = 'description';
+const String EDIT_RESPONSE_DARTFIX_FIXES = 'fixes';
const String EDIT_RESPONSE_FORMAT_EDITS = 'edits';
const String EDIT_RESPONSE_FORMAT_SELECTION_LENGTH = 'selectionLength';
const String EDIT_RESPONSE_FORMAT_SELECTION_OFFSET = 'selectionOffset';
diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart
index b1f5dce..aa83274 100644
--- a/pkg/analysis_server/lib/protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart
@@ -6166,6 +6166,218 @@
}
/**
+ * edit.dartfix params
+ *
+ * {
+ * "included": List<FilePath>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class EditDartfixParams implements RequestParams {
+ List<String> _included;
+
+ /**
+ * A list of the files and directories for which edits should be suggested.
+ * 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
+ * FORMAT_INVALID_FILE will be generated.
+ */
+ List<String> get included => _included;
+
+ /**
+ * A list of the files and directories for which edits should be suggested.
+ * 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
+ * FORMAT_INVALID_FILE will be generated.
+ */
+ void set included(List<String> value) {
+ assert(value != null);
+ this._included = value;
+ }
+
+ EditDartfixParams(List<String> included) {
+ this.included = included;
+ }
+
+ factory EditDartfixParams.fromJson(
+ JsonDecoder jsonDecoder, String jsonPath, Object json) {
+ if (json == null) {
+ json = {};
+ }
+ if (json is Map) {
+ List<String> included;
+ if (json.containsKey("included")) {
+ included = jsonDecoder.decodeList(
+ jsonPath + ".included", json["included"], jsonDecoder.decodeString);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "included");
+ }
+ return new EditDartfixParams(included);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "edit.dartfix params", json);
+ }
+ }
+
+ factory EditDartfixParams.fromRequest(Request request) {
+ return new EditDartfixParams.fromJson(
+ new RequestDecoder(request), "params", request.params);
+ }
+
+ @override
+ Map<String, dynamic> toJson() {
+ Map<String, dynamic> result = {};
+ result["included"] = included;
+ return result;
+ }
+
+ @override
+ Request toRequest(String id) {
+ return new Request(id, "edit.dartfix", toJson());
+ }
+
+ @override
+ String toString() => json.encode(toJson());
+
+ @override
+ bool operator ==(other) {
+ if (other is EditDartfixParams) {
+ return listEqual(
+ included, other.included, (String a, String b) => a == b);
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode {
+ int hash = 0;
+ hash = JenkinsSmiHash.combine(hash, included.hashCode);
+ return JenkinsSmiHash.finish(hash);
+ }
+}
+
+/**
+ * edit.dartfix result
+ *
+ * {
+ * "description": List<String>
+ * "fixes": List<SourceFileEdit>
+ * }
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class EditDartfixResult implements ResponseResult {
+ List<String> _description;
+
+ List<SourceFileEdit> _fixes;
+
+ /**
+ * A list of human readable changes made by applying the fixes.
+ */
+ List<String> get description => _description;
+
+ /**
+ * A list of human readable changes made by applying the fixes.
+ */
+ void set description(List<String> value) {
+ assert(value != null);
+ this._description = value;
+ }
+
+ /**
+ * The suggested fixes.
+ */
+ List<SourceFileEdit> get fixes => _fixes;
+
+ /**
+ * The suggested fixes.
+ */
+ void set fixes(List<SourceFileEdit> value) {
+ assert(value != null);
+ this._fixes = value;
+ }
+
+ EditDartfixResult(List<String> description, List<SourceFileEdit> fixes) {
+ this.description = description;
+ this.fixes = fixes;
+ }
+
+ factory EditDartfixResult.fromJson(
+ JsonDecoder jsonDecoder, String jsonPath, Object json) {
+ if (json == null) {
+ json = {};
+ }
+ if (json is Map) {
+ List<String> description;
+ if (json.containsKey("description")) {
+ description = jsonDecoder.decodeList(jsonPath + ".description",
+ json["description"], jsonDecoder.decodeString);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "description");
+ }
+ List<SourceFileEdit> fixes;
+ if (json.containsKey("fixes")) {
+ fixes = jsonDecoder.decodeList(
+ jsonPath + ".fixes",
+ json["fixes"],
+ (String jsonPath, Object json) =>
+ new SourceFileEdit.fromJson(jsonDecoder, jsonPath, json));
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "fixes");
+ }
+ return new EditDartfixResult(description, fixes);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, "edit.dartfix result", json);
+ }
+ }
+
+ factory EditDartfixResult.fromResponse(Response response) {
+ return new EditDartfixResult.fromJson(
+ new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)),
+ "result",
+ response.result);
+ }
+
+ @override
+ Map<String, dynamic> toJson() {
+ Map<String, dynamic> result = {};
+ result["description"] = description;
+ result["fixes"] =
+ fixes.map((SourceFileEdit value) => value.toJson()).toList();
+ return result;
+ }
+
+ @override
+ Response toResponse(String id) {
+ return new Response(id, result: toJson());
+ }
+
+ @override
+ String toString() => json.encode(toJson());
+
+ @override
+ bool operator ==(other) {
+ if (other is EditDartfixResult) {
+ return listEqual(
+ description, other.description, (String a, String b) => a == b) &&
+ listEqual(fixes, other.fixes,
+ (SourceFileEdit a, SourceFileEdit b) => a == b);
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode {
+ int hash = 0;
+ hash = JenkinsSmiHash.combine(hash, description.hashCode);
+ hash = JenkinsSmiHash.combine(hash, fixes.hashCode);
+ return JenkinsSmiHash.finish(hash);
+ }
+}
+
+/**
* edit.format params
*
* {
diff --git a/pkg/analysis_server/test/integration/coverage.md b/pkg/analysis_server/test/integration/coverage.md
index 2dbaa43..dcec50a 100644
--- a/pkg/analysis_server/test/integration/coverage.md
+++ b/pkg/analysis_server/test/integration/coverage.md
@@ -38,6 +38,7 @@
- [x] diagnostic.getServerPort
## edit domain
+- [ ] edit.dartfix
- [x] edit.format
- [x] edit.getAssists
- [x] edit.getAvailableRefactorings
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 3433f34..0d95b2b 100644
--- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
@@ -1495,6 +1495,39 @@
}
/**
+ * 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
+ * source requires it.
+ *
+ * Parameters
+ *
+ * included: List<FilePath>
+ *
+ * A list of the files and directories for which edits should be suggested.
+ * 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 FORMAT_INVALID_FILE will be generated.
+ *
+ * Returns
+ *
+ * description: List<String>
+ *
+ * A list of human readable changes made by applying the fixes.
+ *
+ * fixes: List<SourceFileEdit>
+ *
+ * The suggested fixes.
+ */
+ Future<EditDartfixResult> sendEditDartfix(List<String> included) async {
+ var params = new EditDartfixParams(included).toJson();
+ var result = await server.send("edit.dartfix", params);
+ ResponseDecoder decoder = new ResponseDecoder(null);
+ return new EditDartfixResult.fromJson(decoder, 'result', result);
+ }
+
+ /**
* Return the set of fixes that are available for the errors at a given
* offset in a given file.
*
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index 11b741a..26ecc39 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -2122,6 +2122,28 @@
new MatchesJsonObject("diagnostic.getServerPort result", {"port": isInt}));
/**
+ * edit.dartfix params
+ *
+ * {
+ * "included": List<FilePath>
+ * }
+ */
+final Matcher isEditDartfixParams = new LazyMatcher(() => new MatchesJsonObject(
+ "edit.dartfix params", {"included": isListOf(isFilePath)}));
+
+/**
+ * edit.dartfix result
+ *
+ * {
+ * "description": List<String>
+ * "fixes": List<SourceFileEdit>
+ * }
+ */
+final Matcher isEditDartfixResult = new LazyMatcher(() => new MatchesJsonObject(
+ "edit.dartfix result",
+ {"description": isListOf(isString), "fixes": isListOf(isSourceFileEdit)}));
+
+/**
* edit.format params
*
* {
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index 8a410b7..551d5dd 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -406,6 +406,20 @@
public void diagnostic_getServerPort(GetServerPortConsumer consumer);
/**
+ * {@code edit.dartfix}
+ *
+ * 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 source requires it.
+ *
+ * @param included A list of the files and directories for which edits should be suggested. 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 FORMAT_INVALID_FILE will be generated.
+ */
+ public void edit_dartfix(List<String> included, DartfixConsumer consumer);
+
+ /**
* {@code edit.format}
*
* Format the contents of a single file. The currently selected region of text is passed in so that
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 2334b39..d5b0623 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -1933,6 +1933,46 @@
</field>
</result>
</request>
+ <request method="dartfix" experimental="true">
+ <p>
+ 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 source requires it.
+ </p>
+ <params>
+ <field name="included">
+ <list>
+ <ref>FilePath</ref>
+ </list>
+ <p>
+ A list of the files and directories for which edits should be suggested.
+ 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 <tt>FORMAT_INVALID_FILE</tt> will be generated.
+ </p>
+ </field>
+ </params>
+ <result>
+ <field name="description">
+ <list>
+ <ref>String</ref>
+ </list>
+ <p>
+ A list of human readable changes made by applying the fixes.
+ </p>
+ </field>
+ <field name="fixes">
+ <list>
+ <ref>SourceFileEdit</ref>
+ </list>
+ <p>
+ The suggested fixes.
+ </p>
+ </field>
+ </result>
+ </request>
<request method="getFixes">
<p>
Return the set of fixes that are available for the errors at
diff --git a/pkg/analyzer_cli/lib/src/fix/driver.dart b/pkg/analyzer_cli/lib/src/fix/driver.dart
index 5bbf033..5888e26 100644
--- a/pkg/analyzer_cli/lib/src/fix/driver.dart
+++ b/pkg/analyzer_cli/lib/src/fix/driver.dart
@@ -1,3 +1,6 @@
+// Copyright (c) 2018, 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 'dart:async';
import 'package:analyzer_cli/src/fix/options.dart';
diff --git a/pkg/analyzer_cli/lib/src/fix/options.dart b/pkg/analyzer_cli/lib/src/fix/options.dart
index 802eac1..0cb29c0 100644
--- a/pkg/analyzer_cli/lib/src/fix/options.dart
+++ b/pkg/analyzer_cli/lib/src/fix/options.dart
@@ -1,3 +1,6 @@
+// Copyright (c) 2018, 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 'dart:io';
import 'package:analyzer/src/util/sdk.dart';
diff --git a/pkg/analyzer_cli/lib/src/fix/server.dart b/pkg/analyzer_cli/lib/src/fix/server.dart
index 31467ab..66f031c 100644
--- a/pkg/analyzer_cli/lib/src/fix/server.dart
+++ b/pkg/analyzer_cli/lib/src/fix/server.dart
@@ -1,3 +1,6 @@
+// Copyright (c) 2018, 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 'dart:async';
import 'dart:convert';
import 'dart:io';