diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b5b04a28d18e..cd8adc14a7e1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## 2.1.0-dev.9.1 + +Cherry-pick commit 0fe448a99643e149acb2e7e32d7a30eba7dd646d to update the analysis server edit.dartfix protocol. + +Cherry-pick commit 45d070d437bb1b596516edd3717e6ee614c5f9ac to update linter to version 0.1.71. + +Cherry-pick commit 00f27a32cf52834b3e9e1f52889b6f1c83ad338c to fix usage of mixins in dart dev compiler. + +Cherry-pick commit 523353d28017fced825581ea327509c620eed67e to fix the ARM 32-bit build. + +Cherry-pick commit db4271378f56a66528a87f2f920c678162d59a35 to fix an +issue with coverage + ## 2.1.0-dev.9.0 ## 2.1.0-dev.8.0 diff --git a/DEPS b/DEPS index 3ded0c62534cb..53238472629cb 100644 --- a/DEPS +++ b/DEPS @@ -95,7 +95,7 @@ vars = { "intl_tag": "0.15.7", "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1", "json_rpc_2_tag": "2.0.9", - "linter_tag": "0.1.70", + "linter_tag": "0.1.71", "logging_tag": "0.11.3+2", "markdown_tag": "2.0.2", "matcher_tag": "0.12.3", diff --git a/build/.gitignore b/build/.gitignore index 0c6f30611cab8..869cdb4888b52 100644 --- a/build/.gitignore +++ b/build/.gitignore @@ -4,7 +4,5 @@ win_toolchain.json # Pulled Debian wheezy sysroots linux/debian_jessie_arm-sysroot linux/debian_jessie_arm64-sysroot -linux/debian_wheezy_amd64-sysroot linux/debian_jessie_amd64-sysroot -linux/debian_wheezy_arm-sysroot -linux/debian_wheezy_i386-sysroot +linux/debian_jessie_i386-sysroot diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn index 215025bc8ff76..62f7524b770f1 100644 --- a/build/config/linux/BUILD.gn +++ b/build/config/linux/BUILD.gn @@ -18,12 +18,12 @@ config("sdk") { ], "value") ] - # When using the pulled wheezy sysroot with gcc, we have to specify these + # When using the pulled Debian sysroot with gcc, we have to specify these # excplicitly. - if (dart_use_wheezy_sysroot && !is_clang) { + if (dart_use_debian_sysroot && !is_clang) { cflags += [ - "-I=/usr/include/c++/4.6", - "-I=/usr/include/c++/4.6/i486-linux-gnu", + "-I=/usr/include/c++/4.8", + "-I=/usr/include/c++/4.8/i486-linux-gnu", ] } } diff --git a/build/config/sysroot.gni b/build/config/sysroot.gni index b1acdf687c3bf..a4364ac7b7a8e 100644 --- a/build/config/sysroot.gni +++ b/build/config/sysroot.gni @@ -10,25 +10,21 @@ declare_args() { # the target toolchain. target_sysroot = "" - # Whether the Debian wheezy sysroot should be used. - dart_use_wheezy_sysroot = false + # Whether the Debian sysroot should be used. + dart_use_debian_sysroot = false } -if (is_linux && dart_use_wheezy_sysroot) { +if (is_linux && dart_use_debian_sysroot) { if (current_cpu == "x86") { - target_sysroot = rebase_path("//build/linux/debian_wheezy_i386-sysroot", root_build_dir) + target_sysroot = rebase_path("//build/linux/debian_jessie_i386-sysroot", root_build_dir) } else if (current_cpu == "x64") { - if (is_asan || is_lsan || is_msan || is_tsan) { - target_sysroot = rebase_path("//build/linux/debian_jessie_amd64-sysroot", root_build_dir) - } else { - target_sysroot = rebase_path("//build/linux/debian_wheezy_amd64-sysroot", root_build_dir) - } + target_sysroot = rebase_path("//build/linux/debian_jessie_amd64-sysroot", root_build_dir) } else if (current_cpu == "arm") { - target_sysroot = rebase_path("//build/linux/debian_wheezy_arm-sysroot", root_build_dir) + target_sysroot = rebase_path("//build/linux/debian_jessie_arm-sysroot", root_build_dir) } else if (current_cpu == "arm64") { target_sysroot = rebase_path("//build/linux/debian_jessie_arm64-sysroot", root_build_dir) } else { - print("There is no Debian wheezy sysroot present for $current_cpu") + print("There is no Debian sysroot present for $current_cpu") assert(false) } } diff --git a/build/linux/sysroot_scripts/install-sysroot.py b/build/linux/sysroot_scripts/install-sysroot.py index 88bdd62d25db8..4500023870b24 100755 --- a/build/linux/sysroot_scripts/install-sysroot.py +++ b/build/linux/sysroot_scripts/install-sysroot.py @@ -95,16 +95,15 @@ def main(args): def InstallDefaultSysrootForArch(target_arch): if target_arch == 'amd64': - InstallSysroot('Wheezy', 'amd64') InstallSysroot('Jessie', 'amd64') elif target_arch == 'arm': - InstallSysroot('Wheezy', 'arm') + InstallSysroot('Jessie', 'arm') elif target_arch == 'arm64': InstallSysroot('Jessie', 'arm64') elif target_arch == 'i386': - InstallSysroot('Wheezy', 'i386') + InstallSysroot('Jessie', 'i386') elif target_arch == 'mips': - InstallSysroot('Wheezy', 'mips') + InstallSysroot('Jessie', 'mips') else: raise Error('Unknown architecture: %s' % target_arch) diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html index 15e83c43c015c..5af3aa0f8bd39 100644 --- a/pkg/analysis_server/doc/api.html +++ b/pkg/analysis_server/doc/api.html @@ -2658,6 +2658,7 @@

Types

+
AddContentOverlay: object
@@ -4379,9 +4380,9 @@

Types

RuntimeCompletionExpression: object

An expression for which we want to know its runtime type. - In expressions like `a.b.c.where((e) => e.^)` we want to know the - runtime type of `a.b.c` to enforce it statically at the time when we - compute completion suggestions, and get better type for `e`. + In expressions like 'a.b.c.where((e) => e.^)' we want to know the + runtime type of 'a.b.c' to enforce it statically at the time when we + compute completion suggestions, and get better type for 'e'.

offset: int
diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart index 9d85d08bdd2eb..1280460f470c7 100644 --- a/pkg/analysis_server/lib/protocol/protocol_constants.dart +++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart @@ -173,11 +173,10 @@ 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_DARTFIX_DESCRIPTION_OF_FIXES = 'descriptionOfFixes'; -const String EDIT_RESPONSE_DARTFIX_FIXES = 'fixes'; +const String EDIT_RESPONSE_DARTFIX_EDITS = 'edits'; const String EDIT_RESPONSE_DARTFIX_HAS_ERRORS = 'hasErrors'; -const String EDIT_RESPONSE_DARTFIX_OTHER_RECOMMENDATIONS = - 'otherRecommendations'; +const String EDIT_RESPONSE_DARTFIX_OTHER_SUGGESTIONS = 'otherSuggestions'; +const String EDIT_RESPONSE_DARTFIX_SUGGESTIONS = 'suggestions'; 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 cb7d9469bd36d..3a0a480f94d5e 100644 --- a/pkg/analysis_server/lib/protocol/protocol_generated.dart +++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart @@ -5931,6 +5931,105 @@ class ConvertMethodToGetterOptions extends RefactoringOptions } } +/** + * DartFixSuggestion + * + * { + * "description": String + * "location": optional Location + * } + * + * Clients may not extend, implement or mix-in this class. + */ +class DartFixSuggestion implements HasToJson { + String _description; + + Location _location; + + /** + * A human readable description of the suggested change. + */ + String get description => _description; + + /** + * A human readable description of the suggested change. + */ + void set description(String value) { + assert(value != null); + this._description = value; + } + + /** + * The location of the suggested change. + */ + Location get location => _location; + + /** + * The location of the suggested change. + */ + void set location(Location value) { + this._location = value; + } + + DartFixSuggestion(String description, {Location location}) { + this.description = description; + this.location = location; + } + + factory DartFixSuggestion.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + if (json == null) { + json = {}; + } + if (json is Map) { + String description; + if (json.containsKey("description")) { + description = jsonDecoder.decodeString( + jsonPath + ".description", json["description"]); + } else { + throw jsonDecoder.mismatch(jsonPath, "description"); + } + Location location; + if (json.containsKey("location")) { + location = new Location.fromJson( + jsonDecoder, jsonPath + ".location", json["location"]); + } + return new DartFixSuggestion(description, location: location); + } else { + throw jsonDecoder.mismatch(jsonPath, "DartFixSuggestion", json); + } + } + + @override + Map toJson() { + Map result = {}; + result["description"] = description; + if (location != null) { + result["location"] = location.toJson(); + } + return result; + } + + @override + String toString() => json.encode(toJson()); + + @override + bool operator ==(other) { + if (other is DartFixSuggestion) { + return description == other.description && location == other.location; + } + return false; + } + + @override + int get hashCode { + int hash = 0; + hash = JenkinsSmiHash.combine(hash, description.hashCode); + hash = JenkinsSmiHash.combine(hash, location.hashCode); + return JenkinsSmiHash.finish(hash); + } +} + /** * diagnostic.getDiagnostics params * @@ -6268,60 +6367,60 @@ class EditDartfixParams implements RequestParams { * edit.dartfix result * * { - * "descriptionOfFixes": List - * "otherRecommendations": List + * "suggestions": List + * "otherSuggestions": List * "hasErrors": bool - * "fixes": List + * "edits": List * } * * Clients may not extend, implement or mix-in this class. */ class EditDartfixResult implements ResponseResult { - List _descriptionOfFixes; + List _suggestions; - List _otherRecommendations; + List _otherSuggestions; bool _hasErrors; - List _fixes; + List _edits; /** - * A list of human readable changes made by applying the fixes. + * A list of recommended changes that can be automatically made by applying + * the 'edits' included in this response. */ - List get descriptionOfFixes => _descriptionOfFixes; + List get suggestions => _suggestions; /** - * A list of human readable changes made by applying the fixes. + * A list of recommended changes that can be automatically made by applying + * the 'edits' included in this response. */ - void set descriptionOfFixes(List value) { + void set suggestions(List value) { assert(value != null); - this._descriptionOfFixes = value; + this._suggestions = value; } /** - * A list of human readable recommended changes that cannot be made - * automatically. + * A list of recommended changes that could not be automatically made. */ - List get otherRecommendations => _otherRecommendations; + List get otherSuggestions => _otherSuggestions; /** - * A list of human readable recommended changes that cannot be made - * automatically. + * A list of recommended changes that could not be automatically made. */ - void set otherRecommendations(List value) { + void set otherSuggestions(List value) { assert(value != null); - this._otherRecommendations = value; + this._otherSuggestions = value; } /** * True if the analyzed source contains errors that might impact the - * correctness of the recommended fixes that can be automatically applied. + * correctness of the recommended changes that can be automatically applied. */ bool get hasErrors => _hasErrors; /** * True if the analyzed source contains errors that might impact the - * correctness of the recommended fixes that can be automatically applied. + * correctness of the recommended changes that can be automatically applied. */ void set hasErrors(bool value) { assert(value != null); @@ -6329,27 +6428,27 @@ class EditDartfixResult implements ResponseResult { } /** - * The suggested fixes. + * A list of source edits to apply the recommended changes. */ - List get fixes => _fixes; + List get edits => _edits; /** - * The suggested fixes. + * A list of source edits to apply the recommended changes. */ - void set fixes(List value) { + void set edits(List value) { assert(value != null); - this._fixes = value; + this._edits = value; } EditDartfixResult( - List descriptionOfFixes, - List otherRecommendations, + List suggestions, + List otherSuggestions, bool hasErrors, - List fixes) { - this.descriptionOfFixes = descriptionOfFixes; - this.otherRecommendations = otherRecommendations; + List edits) { + this.suggestions = suggestions; + this.otherSuggestions = otherSuggestions; this.hasErrors = hasErrors; - this.fixes = fixes; + this.edits = edits; } factory EditDartfixResult.fromJson( @@ -6358,23 +6457,25 @@ class EditDartfixResult implements ResponseResult { json = {}; } if (json is Map) { - List descriptionOfFixes; - if (json.containsKey("descriptionOfFixes")) { - descriptionOfFixes = jsonDecoder.decodeList( - jsonPath + ".descriptionOfFixes", - json["descriptionOfFixes"], - jsonDecoder.decodeString); + List suggestions; + if (json.containsKey("suggestions")) { + suggestions = jsonDecoder.decodeList( + jsonPath + ".suggestions", + json["suggestions"], + (String jsonPath, Object json) => + new DartFixSuggestion.fromJson(jsonDecoder, jsonPath, json)); } else { - throw jsonDecoder.mismatch(jsonPath, "descriptionOfFixes"); + throw jsonDecoder.mismatch(jsonPath, "suggestions"); } - List otherRecommendations; - if (json.containsKey("otherRecommendations")) { - otherRecommendations = jsonDecoder.decodeList( - jsonPath + ".otherRecommendations", - json["otherRecommendations"], - jsonDecoder.decodeString); + List otherSuggestions; + if (json.containsKey("otherSuggestions")) { + otherSuggestions = jsonDecoder.decodeList( + jsonPath + ".otherSuggestions", + json["otherSuggestions"], + (String jsonPath, Object json) => + new DartFixSuggestion.fromJson(jsonDecoder, jsonPath, json)); } else { - throw jsonDecoder.mismatch(jsonPath, "otherRecommendations"); + throw jsonDecoder.mismatch(jsonPath, "otherSuggestions"); } bool hasErrors; if (json.containsKey("hasErrors")) { @@ -6383,18 +6484,18 @@ class EditDartfixResult implements ResponseResult { } else { throw jsonDecoder.mismatch(jsonPath, "hasErrors"); } - List fixes; - if (json.containsKey("fixes")) { - fixes = jsonDecoder.decodeList( - jsonPath + ".fixes", - json["fixes"], + List edits; + if (json.containsKey("edits")) { + edits = jsonDecoder.decodeList( + jsonPath + ".edits", + json["edits"], (String jsonPath, Object json) => new SourceFileEdit.fromJson(jsonDecoder, jsonPath, json)); } else { - throw jsonDecoder.mismatch(jsonPath, "fixes"); + throw jsonDecoder.mismatch(jsonPath, "edits"); } return new EditDartfixResult( - descriptionOfFixes, otherRecommendations, hasErrors, fixes); + suggestions, otherSuggestions, hasErrors, edits); } else { throw jsonDecoder.mismatch(jsonPath, "edit.dartfix result", json); } @@ -6410,11 +6511,14 @@ class EditDartfixResult implements ResponseResult { @override Map toJson() { Map result = {}; - result["descriptionOfFixes"] = descriptionOfFixes; - result["otherRecommendations"] = otherRecommendations; + result["suggestions"] = + suggestions.map((DartFixSuggestion value) => value.toJson()).toList(); + result["otherSuggestions"] = otherSuggestions + .map((DartFixSuggestion value) => value.toJson()) + .toList(); result["hasErrors"] = hasErrors; - result["fixes"] = - fixes.map((SourceFileEdit value) => value.toJson()).toList(); + result["edits"] = + edits.map((SourceFileEdit value) => value.toJson()).toList(); return result; } @@ -6429,12 +6533,12 @@ class EditDartfixResult implements ResponseResult { @override bool operator ==(other) { if (other is EditDartfixResult) { - return listEqual(descriptionOfFixes, other.descriptionOfFixes, - (String a, String b) => a == b) && - listEqual(otherRecommendations, other.otherRecommendations, - (String a, String b) => a == b) && + return listEqual(suggestions, other.suggestions, + (DartFixSuggestion a, DartFixSuggestion b) => a == b) && + listEqual(otherSuggestions, other.otherSuggestions, + (DartFixSuggestion a, DartFixSuggestion b) => a == b) && hasErrors == other.hasErrors && - listEqual(fixes, other.fixes, + listEqual(edits, other.edits, (SourceFileEdit a, SourceFileEdit b) => a == b); } return false; @@ -6443,10 +6547,10 @@ class EditDartfixResult implements ResponseResult { @override int get hashCode { int hash = 0; - hash = JenkinsSmiHash.combine(hash, descriptionOfFixes.hashCode); - hash = JenkinsSmiHash.combine(hash, otherRecommendations.hashCode); + hash = JenkinsSmiHash.combine(hash, suggestions.hashCode); + hash = JenkinsSmiHash.combine(hash, otherSuggestions.hashCode); hash = JenkinsSmiHash.combine(hash, hasErrors.hashCode); - hash = JenkinsSmiHash.combine(hash, fixes.hashCode); + hash = JenkinsSmiHash.combine(hash, edits.hashCode); return JenkinsSmiHash.finish(hash); } } diff --git a/pkg/analysis_server/lib/src/edit/edit_dartfix.dart b/pkg/analysis_server/lib/src/edit/edit_dartfix.dart index 3a8e3449d0abb..6673fb475f341 100644 --- a/pkg/analysis_server/lib/src/edit/edit_dartfix.dart +++ b/pkg/analysis_server/lib/src/edit/edit_dartfix.dart @@ -23,7 +23,7 @@ import 'package:analyzer/src/lint/linter_visitor.dart'; import 'package:analyzer/src/lint/registry.dart'; import 'package:analyzer/src/services/lint.dart'; import 'package:analyzer_plugin/protocol/protocol_common.dart' - show SourceChange, SourceEdit, SourceFileEdit; + show Location, SourceChange, SourceEdit, SourceFileEdit; import 'package:front_end/src/fasta/fasta_codes.dart'; import 'package:front_end/src/scanner/token.dart'; import 'package:source_span/src/span.dart'; @@ -34,14 +34,14 @@ class EditDartFix { final fixFolders = []; final fixFiles = []; - List descriptionOfFixes; - List otherRecommendations; + List suggestions; + List otherSuggestions; SourceChange sourceChange; EditDartFix(this.server, this.request); - void addFix(String description, SourceChange change) { - descriptionOfFixes.add(description); + void addFix(String description, Location location, SourceChange change) { + suggestions.add(new DartFixSuggestion(description, location: location)); for (SourceFileEdit fileEdit in change.edits) { for (SourceEdit sourceEdit in fileEdit.edits) { sourceChange.addEdit(fileEdit.file, fileEdit.fileStamp, sourceEdit); @@ -49,8 +49,9 @@ class EditDartFix { } } - void addRecommendation(String recommendation) { - otherRecommendations.add(recommendation); + void addRecommendation(String description, [Location location]) { + otherSuggestions + .add(new DartFixSuggestion(description, location: location)); } Future compute() async { @@ -125,8 +126,8 @@ class EditDartFix { for (String rootPath in contextManager.includedPaths) { resources.add(resourceProvider.getResource(rootPath)); } - descriptionOfFixes = []; - otherRecommendations = []; + suggestions = []; + otherSuggestions = []; sourceChange = new SourceChange('dartfix'); bool hasErrors = false; while (resources.isNotEmpty) { @@ -186,8 +187,8 @@ class EditDartFix { await fix.applyRemainingFixes(); } - return new EditDartfixResult(descriptionOfFixes, otherRecommendations, - hasErrors, sourceChange.edits) + return new EditDartfixResult( + suggestions, otherSuggestions, hasErrors, sourceChange.edits) .toResponse(request.id); } @@ -204,7 +205,6 @@ class EditDartFix { return false; } - final location = '${locationDescription(result, error.offset)}'; final dartContext = new DartFixContextImpl( new FixContextImpl( server.resourceProvider, result.driver, error, result.errors), @@ -212,12 +212,13 @@ class EditDartFix { result.unit); final processor = new FixProcessor(dartContext); Fix fix = await processor.computeFix(); + final location = locationFor(result, error.offset, error.length); if (fix != null) { - addFix('${fix.change.message} in $location', fix.change); + addFix(fix.change.message, location, fix.change); } else { // TODO(danrubel): Determine why the fix could not be applied // and report that in the description. - addRecommendation('Could not fix "${error.message}" in $location'); + addRecommendation('Could not fix "${error.message}"', location); } return true; } @@ -240,29 +241,11 @@ class EditDartFix { return false; } - /// Return a human readable description of the specified offset and file. - String locationDescription(AnalysisResult result, int offset) { - // TODO(danrubel): Pass the location back to the client along with the - // message indicating what was or was not automatically fixed - // rather than interpreting and integrating the location into the message. - final description = new StringBuffer(); - // Determine the relative path - for (Folder folder in fixFolders) { - if (folder.contains(result.path)) { - description.write(server.resourceProvider.pathContext - .relative(result.path, from: folder.path)); - break; - } - } - if (description.isEmpty) { - description.write(result.path); - } - // Determine the line and column number - if (offset >= 0) { - final loc = result.unit.lineInfo.getLocation(offset); - description.write(':${loc.lineNumber}'); - } - return description.toString(); + Location locationFor(AnalysisResult result, int offset, int length) { + final locInfo = result.unit.lineInfo.getLocation(offset); + final location = new Location( + result.path, offset, length, locInfo.lineNumber, locInfo.columnNumber); + return location; } } diff --git a/pkg/analysis_server/lib/src/edit/fix/prefer_int_literals_fix.dart b/pkg/analysis_server/lib/src/edit/fix/prefer_int_literals_fix.dart index 81758f9d24318..52dda1f517f0a 100644 --- a/pkg/analysis_server/lib/src/edit/fix/prefer_int_literals_fix.dart +++ b/pkg/analysis_server/lib/src/edit/fix/prefer_int_literals_fix.dart @@ -23,18 +23,18 @@ class PreferIntLiteralsFix extends LinterFix { new EditDartFixAssistContext(dartFix, source, result.unit, literal)); List assists = await processor.computeAssist(DartAssistKind.CONVERT_TO_INT_LITERAL); - final location = dartFix.locationDescription(result, literal.offset); + final location = + dartFix.locationFor(result, literal.offset, literal.length); if (assists.isNotEmpty) { for (Assist assist in assists) { - dartFix.addFix( - 'Replace a double literal with an int literal in $location', - assist.change); + dartFix.addFix('Replace a double literal with an int literal', + location, assist.change); } } else { // TODO(danrubel): If assists is empty, then determine why // assist could not be performed and report that in the description. - dartFix.addRecommendation('Could not replace' - ' a double literal with an int literal in $location'); + dartFix.addRecommendation( + 'Could not replace a double literal with an int literal', location); } } } diff --git a/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart b/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart index 5e2aad1c85ec7..52f924a374404 100644 --- a/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart +++ b/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart @@ -41,11 +41,11 @@ class PreferMixinFix extends LinterFix { dartFix, elem.source, result.unit, declaration.name)); List assists = await processor .computeAssist(DartAssistKind.CONVERT_CLASS_TO_MIXIN); - final location = dartFix.locationDescription(result, elem.nameOffset); + final location = + dartFix.locationFor(result, elem.nameOffset, elem.nameLength); if (assists.isNotEmpty) { for (Assist assist in assists) { - dartFix.addFix( - 'Convert ${elem.displayName} to a mixin in $location', + dartFix.addFix('Convert ${elem.displayName} to a mixin', location, assist.change); } } else { @@ -53,7 +53,8 @@ class PreferMixinFix extends LinterFix { // assist could not be performed and report that in the description. dartFix.addRecommendation( 'Could not convert ${elem.displayName} to a mixin' - ' because the class contains a constructor in $location'); + ' because the class contains a constructor', + location); } } } 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 3976d6c68e000..401723d8c7ed0 100644 --- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart +++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart @@ -1517,23 +1517,24 @@ abstract class IntegrationTestMixin { * * Returns * - * descriptionOfFixes: List + * suggestions: List * - * A list of human readable changes made by applying the fixes. + * A list of recommended changes that can be automatically made by applying + * the 'edits' included in this response. * - * otherRecommendations: List + * otherSuggestions: List * - * A list of human readable recommended changes that cannot be made - * automatically. + * A list of recommended changes that could not be automatically made. * * hasErrors: bool * * True if the analyzed source contains errors that might impact the - * correctness of the recommended fixes that can be automatically applied. + * correctness of the recommended changes that can be automatically + * applied. * - * fixes: List + * edits: List * - * The suggested fixes. + * A list of source edits to apply the recommended changes. */ Future sendEditDartfix(List included) async { var params = new EditDartfixParams(included).toJson(); diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart index db9505f263256..13ba9213204c1 100644 --- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart +++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart @@ -297,6 +297,18 @@ final Matcher isContextData = "cacheEntryExceptions": isListOf(isString) })); +/** + * DartFixSuggestion + * + * { + * "description": String + * "location": optional Location + * } + */ +final Matcher isDartFixSuggestion = new LazyMatcher(() => new MatchesJsonObject( + "DartFixSuggestion", {"description": isString}, + optionalFields: {"location": isLocation})); + /** * Element * @@ -2131,18 +2143,18 @@ final Matcher isEditDartfixParams = new LazyMatcher(() => new MatchesJsonObject( * edit.dartfix result * * { - * "descriptionOfFixes": List - * "otherRecommendations": List + * "suggestions": List + * "otherSuggestions": List * "hasErrors": bool - * "fixes": List + * "edits": List * } */ final Matcher isEditDartfixResult = new LazyMatcher(() => new MatchesJsonObject("edit.dartfix result", { - "descriptionOfFixes": isListOf(isString), - "otherRecommendations": isListOf(isString), + "suggestions": isListOf(isDartFixSuggestion), + "otherSuggestions": isListOf(isDartFixSuggestion), "hasErrors": isBool, - "fixes": isListOf(isSourceFileEdit) + "edits": isListOf(isSourceFileEdit) })); /** diff --git a/pkg/analysis_server/tool/spec/generated/java/types/DartFixSuggestion.java b/pkg/analysis_server/tool/spec/generated/java/types/DartFixSuggestion.java new file mode 100644 index 0000000000000..7a106f82f0133 --- /dev/null +++ b/pkg/analysis_server/tool/spec/generated/java/types/DartFixSuggestion.java @@ -0,0 +1,128 @@ +/* + * 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. + * + * This file has been automatically generated. Please do not edit it manually. + * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files". + */ +package org.dartlang.analysis.server.protocol; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import com.google.common.collect.Lists; +import com.google.dart.server.utilities.general.JsonUtilities; +import com.google.dart.server.utilities.general.ObjectUtilities; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import java.util.ArrayList; +import java.util.Iterator; +import org.apache.commons.lang3.StringUtils; + +/** + * A suggestion from an edit.dartfix request. + * + * @coverage dart.server.generated.types + */ +@SuppressWarnings("unused") +public class DartFixSuggestion { + + public static final DartFixSuggestion[] EMPTY_ARRAY = new DartFixSuggestion[0]; + + public static final List EMPTY_LIST = Lists.newArrayList(); + + /** + * A human readable description of the suggested change. + */ + private final String description; + + /** + * The location of the suggested change. + */ + private final Location location; + + /** + * Constructor for {@link DartFixSuggestion}. + */ + public DartFixSuggestion(String description, Location location) { + this.description = description; + this.location = location; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DartFixSuggestion) { + DartFixSuggestion other = (DartFixSuggestion) obj; + return + ObjectUtilities.equals(other.description, description) && + ObjectUtilities.equals(other.location, location); + } + return false; + } + + public static DartFixSuggestion fromJson(JsonObject jsonObject) { + String description = jsonObject.get("description").getAsString(); + Location location = jsonObject.get("location") == null ? null : Location.fromJson(jsonObject.get("location").getAsJsonObject()); + return new DartFixSuggestion(description, location); + } + + public static List fromJsonArray(JsonArray jsonArray) { + if (jsonArray == null) { + return EMPTY_LIST; + } + ArrayList list = new ArrayList(jsonArray.size()); + Iterator iterator = jsonArray.iterator(); + while (iterator.hasNext()) { + list.add(fromJson(iterator.next().getAsJsonObject())); + } + return list; + } + + /** + * A human readable description of the suggested change. + */ + public String getDescription() { + return description; + } + + /** + * The location of the suggested change. + */ + public Location getLocation() { + return location; + } + + @Override + public int hashCode() { + HashCodeBuilder builder = new HashCodeBuilder(); + builder.append(description); + builder.append(location); + return builder.toHashCode(); + } + + public JsonObject toJson() { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("description", description); + if (location != null) { + jsonObject.add("location", location.toJson()); + } + return jsonObject; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("["); + builder.append("description="); + builder.append(description + ", "); + builder.append("location="); + builder.append(location); + builder.append("]"); + return builder.toString(); + } + +} diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpression.java b/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpression.java index eb6b0f0400ce8..b2d6b705f596b 100644 --- a/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpression.java +++ b/pkg/analysis_server/tool/spec/generated/java/types/RuntimeCompletionExpression.java @@ -24,9 +24,9 @@ import org.apache.commons.lang3.StringUtils; /** - * An expression for which we want to know its runtime type. In expressions like `a.b.c.where((e) - * => e.^)` we want to know the runtime type of `a.b.c` to enforce it statically at the time - * when we compute completion suggestions, and get better type for `e`. + * An expression for which we want to know its runtime type. In expressions like 'a.b.c.where((e) + * => e.^)' we want to know the runtime type of 'a.b.c' to enforce it statically at the time + * when we compute completion suggestions, and get better type for 'e'. * * @coverage dart.server.generated.types */ diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html index 8eced61be0bb1..2f66a93e494a4 100644 --- a/pkg/analysis_server/tool/spec/spec_input.html +++ b/pkg/analysis_server/tool/spec/spec_input.html @@ -1958,35 +1958,36 @@

Options

- + - String + DartFixSuggestion

- A list of human readable changes made by applying the fixes. + A list of recommended changes that can be automatically made + by applying the 'edits' included in this response.

- + - String + DartFixSuggestion

- A list of human readable recommended changes that cannot be made automatically. + A list of recommended changes that could not be automatically made.

bool

True if the analyzed source contains errors that might impact the correctness - of the recommended fixes that can be automatically applied. + of the recommended changes that can be automatically applied.

- + SourceFileEdit

- The suggested fixes. + A list of source edits to apply the recommended changes.

@@ -3313,9 +3314,9 @@

Types

An expression for which we want to know its runtime type. - In expressions like `a.b.c.where((e) => e.^)` we want to know the - runtime type of `a.b.c` to enforce it statically at the time when we - compute completion suggestions, and get better type for `e`. + In expressions like 'a.b.c.where((e) => e.^)' we want to know the + runtime type of 'a.b.c' to enforce it statically at the time when we + compute completion suggestions, and get better type for 'e'.

@@ -4232,6 +4233,25 @@

Types

request.

+ +

+ A suggestion from an edit.dartfix request. +

+ + + String +

+ A human readable description of the suggested change. +

+
+ + Location +

+ The location of the suggested change. +

+
+
+

A single result from a search request. 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 9d85d08bdd2eb..1280460f470c7 100644 --- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart +++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart @@ -173,11 +173,10 @@ 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_DARTFIX_DESCRIPTION_OF_FIXES = 'descriptionOfFixes'; -const String EDIT_RESPONSE_DARTFIX_FIXES = 'fixes'; +const String EDIT_RESPONSE_DARTFIX_EDITS = 'edits'; const String EDIT_RESPONSE_DARTFIX_HAS_ERRORS = 'hasErrors'; -const String EDIT_RESPONSE_DARTFIX_OTHER_RECOMMENDATIONS = - 'otherRecommendations'; +const String EDIT_RESPONSE_DARTFIX_OTHER_SUGGESTIONS = 'otherSuggestions'; +const String EDIT_RESPONSE_DARTFIX_SUGGESTIONS = 'suggestions'; 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_client/lib/src/protocol/protocol_generated.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart index 2bbf169d20865..9fabb4c83ad2b 100644 --- a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart +++ b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart @@ -5931,6 +5931,105 @@ class ConvertMethodToGetterOptions extends RefactoringOptions } } +/** + * DartFixSuggestion + * + * { + * "description": String + * "location": optional Location + * } + * + * Clients may not extend, implement or mix-in this class. + */ +class DartFixSuggestion implements HasToJson { + String _description; + + Location _location; + + /** + * A human readable description of the suggested change. + */ + String get description => _description; + + /** + * A human readable description of the suggested change. + */ + void set description(String value) { + assert(value != null); + this._description = value; + } + + /** + * The location of the suggested change. + */ + Location get location => _location; + + /** + * The location of the suggested change. + */ + void set location(Location value) { + this._location = value; + } + + DartFixSuggestion(String description, {Location location}) { + this.description = description; + this.location = location; + } + + factory DartFixSuggestion.fromJson( + JsonDecoder jsonDecoder, String jsonPath, Object json) { + if (json == null) { + json = {}; + } + if (json is Map) { + String description; + if (json.containsKey("description")) { + description = jsonDecoder.decodeString( + jsonPath + ".description", json["description"]); + } else { + throw jsonDecoder.mismatch(jsonPath, "description"); + } + Location location; + if (json.containsKey("location")) { + location = new Location.fromJson( + jsonDecoder, jsonPath + ".location", json["location"]); + } + return new DartFixSuggestion(description, location: location); + } else { + throw jsonDecoder.mismatch(jsonPath, "DartFixSuggestion", json); + } + } + + @override + Map toJson() { + Map result = {}; + result["description"] = description; + if (location != null) { + result["location"] = location.toJson(); + } + return result; + } + + @override + String toString() => json.encode(toJson()); + + @override + bool operator ==(other) { + if (other is DartFixSuggestion) { + return description == other.description && location == other.location; + } + return false; + } + + @override + int get hashCode { + int hash = 0; + hash = JenkinsSmiHash.combine(hash, description.hashCode); + hash = JenkinsSmiHash.combine(hash, location.hashCode); + return JenkinsSmiHash.finish(hash); + } +} + /** * diagnostic.getDiagnostics params * @@ -6268,60 +6367,60 @@ class EditDartfixParams implements RequestParams { * edit.dartfix result * * { - * "descriptionOfFixes": List - * "otherRecommendations": List + * "suggestions": List + * "otherSuggestions": List * "hasErrors": bool - * "fixes": List + * "edits": List * } * * Clients may not extend, implement or mix-in this class. */ class EditDartfixResult implements ResponseResult { - List _descriptionOfFixes; + List _suggestions; - List _otherRecommendations; + List _otherSuggestions; bool _hasErrors; - List _fixes; + List _edits; /** - * A list of human readable changes made by applying the fixes. + * A list of recommended changes that can be automatically made by applying + * the 'edits' included in this response. */ - List get descriptionOfFixes => _descriptionOfFixes; + List get suggestions => _suggestions; /** - * A list of human readable changes made by applying the fixes. + * A list of recommended changes that can be automatically made by applying + * the 'edits' included in this response. */ - void set descriptionOfFixes(List value) { + void set suggestions(List value) { assert(value != null); - this._descriptionOfFixes = value; + this._suggestions = value; } /** - * A list of human readable recommended changes that cannot be made - * automatically. + * A list of recommended changes that could not be automatically made. */ - List get otherRecommendations => _otherRecommendations; + List get otherSuggestions => _otherSuggestions; /** - * A list of human readable recommended changes that cannot be made - * automatically. + * A list of recommended changes that could not be automatically made. */ - void set otherRecommendations(List value) { + void set otherSuggestions(List value) { assert(value != null); - this._otherRecommendations = value; + this._otherSuggestions = value; } /** * True if the analyzed source contains errors that might impact the - * correctness of the recommended fixes that can be automatically applied. + * correctness of the recommended changes that can be automatically applied. */ bool get hasErrors => _hasErrors; /** * True if the analyzed source contains errors that might impact the - * correctness of the recommended fixes that can be automatically applied. + * correctness of the recommended changes that can be automatically applied. */ void set hasErrors(bool value) { assert(value != null); @@ -6329,27 +6428,27 @@ class EditDartfixResult implements ResponseResult { } /** - * The suggested fixes. + * A list of source edits to apply the recommended changes. */ - List get fixes => _fixes; + List get edits => _edits; /** - * The suggested fixes. + * A list of source edits to apply the recommended changes. */ - void set fixes(List value) { + void set edits(List value) { assert(value != null); - this._fixes = value; + this._edits = value; } EditDartfixResult( - List descriptionOfFixes, - List otherRecommendations, + List suggestions, + List otherSuggestions, bool hasErrors, - List fixes) { - this.descriptionOfFixes = descriptionOfFixes; - this.otherRecommendations = otherRecommendations; + List edits) { + this.suggestions = suggestions; + this.otherSuggestions = otherSuggestions; this.hasErrors = hasErrors; - this.fixes = fixes; + this.edits = edits; } factory EditDartfixResult.fromJson( @@ -6358,23 +6457,25 @@ class EditDartfixResult implements ResponseResult { json = {}; } if (json is Map) { - List descriptionOfFixes; - if (json.containsKey("descriptionOfFixes")) { - descriptionOfFixes = jsonDecoder.decodeList( - jsonPath + ".descriptionOfFixes", - json["descriptionOfFixes"], - jsonDecoder.decodeString); + List suggestions; + if (json.containsKey("suggestions")) { + suggestions = jsonDecoder.decodeList( + jsonPath + ".suggestions", + json["suggestions"], + (String jsonPath, Object json) => + new DartFixSuggestion.fromJson(jsonDecoder, jsonPath, json)); } else { - throw jsonDecoder.mismatch(jsonPath, "descriptionOfFixes"); + throw jsonDecoder.mismatch(jsonPath, "suggestions"); } - List otherRecommendations; - if (json.containsKey("otherRecommendations")) { - otherRecommendations = jsonDecoder.decodeList( - jsonPath + ".otherRecommendations", - json["otherRecommendations"], - jsonDecoder.decodeString); + List otherSuggestions; + if (json.containsKey("otherSuggestions")) { + otherSuggestions = jsonDecoder.decodeList( + jsonPath + ".otherSuggestions", + json["otherSuggestions"], + (String jsonPath, Object json) => + new DartFixSuggestion.fromJson(jsonDecoder, jsonPath, json)); } else { - throw jsonDecoder.mismatch(jsonPath, "otherRecommendations"); + throw jsonDecoder.mismatch(jsonPath, "otherSuggestions"); } bool hasErrors; if (json.containsKey("hasErrors")) { @@ -6383,18 +6484,18 @@ class EditDartfixResult implements ResponseResult { } else { throw jsonDecoder.mismatch(jsonPath, "hasErrors"); } - List fixes; - if (json.containsKey("fixes")) { - fixes = jsonDecoder.decodeList( - jsonPath + ".fixes", - json["fixes"], + List edits; + if (json.containsKey("edits")) { + edits = jsonDecoder.decodeList( + jsonPath + ".edits", + json["edits"], (String jsonPath, Object json) => new SourceFileEdit.fromJson(jsonDecoder, jsonPath, json)); } else { - throw jsonDecoder.mismatch(jsonPath, "fixes"); + throw jsonDecoder.mismatch(jsonPath, "edits"); } return new EditDartfixResult( - descriptionOfFixes, otherRecommendations, hasErrors, fixes); + suggestions, otherSuggestions, hasErrors, edits); } else { throw jsonDecoder.mismatch(jsonPath, "edit.dartfix result", json); } @@ -6410,11 +6511,14 @@ class EditDartfixResult implements ResponseResult { @override Map toJson() { Map result = {}; - result["descriptionOfFixes"] = descriptionOfFixes; - result["otherRecommendations"] = otherRecommendations; + result["suggestions"] = + suggestions.map((DartFixSuggestion value) => value.toJson()).toList(); + result["otherSuggestions"] = otherSuggestions + .map((DartFixSuggestion value) => value.toJson()) + .toList(); result["hasErrors"] = hasErrors; - result["fixes"] = - fixes.map((SourceFileEdit value) => value.toJson()).toList(); + result["edits"] = + edits.map((SourceFileEdit value) => value.toJson()).toList(); return result; } @@ -6429,12 +6533,12 @@ class EditDartfixResult implements ResponseResult { @override bool operator ==(other) { if (other is EditDartfixResult) { - return listEqual(descriptionOfFixes, other.descriptionOfFixes, - (String a, String b) => a == b) && - listEqual(otherRecommendations, other.otherRecommendations, - (String a, String b) => a == b) && + return listEqual(suggestions, other.suggestions, + (DartFixSuggestion a, DartFixSuggestion b) => a == b) && + listEqual(otherSuggestions, other.otherSuggestions, + (DartFixSuggestion a, DartFixSuggestion b) => a == b) && hasErrors == other.hasErrors && - listEqual(fixes, other.fixes, + listEqual(edits, other.edits, (SourceFileEdit a, SourceFileEdit b) => a == b); } return false; @@ -6443,10 +6547,10 @@ class EditDartfixResult implements ResponseResult { @override int get hashCode { int hash = 0; - hash = JenkinsSmiHash.combine(hash, descriptionOfFixes.hashCode); - hash = JenkinsSmiHash.combine(hash, otherRecommendations.hashCode); + hash = JenkinsSmiHash.combine(hash, suggestions.hashCode); + hash = JenkinsSmiHash.combine(hash, otherSuggestions.hashCode); hash = JenkinsSmiHash.combine(hash, hasErrors.hashCode); - hash = JenkinsSmiHash.combine(hash, fixes.hashCode); + hash = JenkinsSmiHash.combine(hash, edits.hashCode); return JenkinsSmiHash.finish(hash); } } diff --git a/pkg/dartfix/lib/src/driver.dart b/pkg/dartfix/lib/src/driver.dart index 80b6c11d10599..80e7a05ac497f 100644 --- a/pkg/dartfix/lib/src/driver.dart +++ b/pkg/dartfix/lib/src/driver.dart @@ -122,25 +122,23 @@ class Driver { } Future applyFixes(EditDartfixResult result) async { - showDescriptions('Recommended changes', result.descriptionOfFixes); - showDescriptions( - 'Recommended changes that cannot not be automatically applied', - result.otherRecommendations, - ); - if (result.descriptionOfFixes.isEmpty) { + showDescriptions('Recommended changes', result.suggestions); + showDescriptions('Recommended changes that cannot be automatically applied', + result.otherSuggestions); + if (result.suggestions.isEmpty) { logger.stdout(''); - logger.stdout(result.otherRecommendations.isNotEmpty - ? 'No recommended changes that cannot be automatically applied.' + logger.stdout(result.otherSuggestions.isNotEmpty + ? 'None of the recommended changes can be automatically applied.' : 'No recommended changes.'); return; } logger.stdout(''); logger.stdout(ansi.emphasized('Files to be changed:')); - for (SourceFileEdit fileEdit in result.fixes) { + for (SourceFileEdit fileEdit in result.edits) { logger.stdout(' ${_relativePath(fileEdit.file)}'); } if (shouldApplyChanges(result)) { - for (SourceFileEdit fileEdit in result.fixes) { + for (SourceFileEdit fileEdit in result.edits) { final file = new File(fileEdit.file); String code = await file.readAsString(); for (SourceEdit edit in fileEdit.edits) { @@ -152,13 +150,16 @@ class Driver { } } - void showDescriptions(String title, List descriptions) { - if (descriptions.isNotEmpty) { + void showDescriptions(String title, List suggestions) { + if (suggestions.isNotEmpty) { logger.stdout(''); logger.stdout(ansi.emphasized('$title:')); - List sorted = new List.from(descriptions)..sort(); - for (String line in sorted) { - logger.stdout(' $line'); + List sorted = new List.from(suggestions) + ..sort(compareSuggestions); + for (DartFixSuggestion suggestion in sorted) { + Location loc = suggestion.location; + logger.stdout(' ${_toSentenceFragment(suggestion.description)}' + '${loc == null ? "" : " • ${loc.startLine}:${loc.startColumn}"}'); } } } @@ -327,6 +328,14 @@ class Driver { } } + int compareSuggestions(DartFixSuggestion s1, DartFixSuggestion s2) { + int result = s1.description.compareTo(s2.description); + if (result != 0) { + return result; + } + return (s2.location?.offset ?? 0) - (s1.location?.offset ?? 0); + } + bool shouldFilterError(AnalysisError error) { // Do not show TODOs or errors that will be automatically fixed. diff --git a/pkg/dev_compiler/lib/src/analyzer/property_model.dart b/pkg/dev_compiler/lib/src/analyzer/property_model.dart index 1691857c6970f..b7dc784607fbb 100644 --- a/pkg/dev_compiler/lib/src/analyzer/property_model.dart +++ b/pkg/dev_compiler/lib/src/analyzer/property_model.dart @@ -58,22 +58,27 @@ class _LibraryVirtualFieldModel { final _extensiblePrivateClasses = HashSet(); _LibraryVirtualFieldModel.build(LibraryElement library) { - var allTypes = library.units.expand((u) => u.types).toList(); + var allClasses = Set(); + for (var libraryPart in library.units) { + allClasses.addAll(libraryPart.types); + allClasses.addAll(libraryPart.mixins); + } // The set of public types is our initial extensible type set. // From there, visit all immediate private types in this library, and so on // from those private types, marking them as extensible. - var typesToVisit = - Queue.from(allTypes.where((t) => t.isPublic)); - while (typesToVisit.isNotEmpty) { - var extensibleType = typesToVisit.removeFirst(); + var classesToVisit = + Queue.from(allClasses.where((t) => t.isPublic)); + while (classesToVisit.isNotEmpty) { + var extensibleClass = classesToVisit.removeFirst(); // For each supertype of a public type in this library, // if we encounter a private class, we mark it as being extended, and // add it to our work set if this is the first time we've visited it. - for (var type in getImmediateSuperclasses(extensibleType)) { - if (!type.isPublic && type.library == library) { - if (_extensiblePrivateClasses.add(type)) typesToVisit.add(type); + for (var superclass in getImmediateSuperclasses(extensibleClass)) { + if (!superclass.isPublic && superclass.library == library) { + if (_extensiblePrivateClasses.add(superclass)) + classesToVisit.add(superclass); } } } @@ -88,43 +93,44 @@ class _LibraryVirtualFieldModel { } var allFields = - HashMap.fromIterables(allTypes, allTypes.map(getInstanceFieldMap)); + HashMap.fromIterables(allClasses, allClasses.map(getInstanceFieldMap)); - for (var type in allTypes) { - Set supertypes = null; + for (var class_ in allClasses) { + Set superclasses; // Visit accessors in the current class, and see if they override an // otherwise private field. - for (var accessor in type.accessors) { + for (var accessor in class_.accessors) { // For getter/setter pairs only process them once. if (accessor.correspondingGetter != null) continue; // Ignore abstract or static accessors. if (accessor.isAbstract || accessor.isStatic) continue; // Ignore public accessors in extensible classes. if (accessor.isPublic && - (type.isPublic || _extensiblePrivateClasses.contains(type))) { + (class_.isPublic || _extensiblePrivateClasses.contains(class_))) { continue; } - if (supertypes == null) { - supertypes = Set(); - void collectSupertypes(ClassElement cls) { - if (!supertypes.add(cls)) return; + if (superclasses == null) { + superclasses = Set(); + void collectSuperclasses(ClassElement cls) { + if (!superclasses.add(cls)) return; var s = cls.supertype?.element; - if (s != null) collectSupertypes(s); - cls.mixins.forEach((m) => collectSupertypes(m.element)); + if (s != null) collectSuperclasses(s); + cls.mixins.forEach((m) => collectSuperclasses(m.element)); } - collectSupertypes(type); - supertypes.remove(type); - supertypes.removeWhere((c) => c.library != type.library); + collectSuperclasses(class_); + superclasses.remove(class_); + superclasses.removeWhere((c) => c.library != library); } // Look in all super classes to see if we're overriding a field in our // library, if so mark that field as overridden. var name = accessor.variable.name; - _overriddenPrivateFields.addAll( - supertypes.map((c) => allFields[c][name]).where((f) => f != null)); + _overriddenPrivateFields.addAll(superclasses + .map((c) => allFields[c][name]) + .where((f) => f != null)); } } } diff --git a/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart b/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart index e004f89bb6e8d..0921e357c3bc6 100644 --- a/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart +++ b/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart @@ -186,6 +186,7 @@ class AnalyzerToKernel { library ??= visitLibraryElement(e.library); library.addClass(class_); + class_.isMixinDeclaration = e.isMixin; class_.typeParameters .addAll(e.typeParameters.map(visitTypeParameterElement)); @@ -504,6 +505,9 @@ class AnalyzerToKernel { for (var t in u.types) { visitClassElement(t, library); } + for (var t in u.mixins) { + visitClassElement(t, library); + } for (var t in u.functionTypeAliases) { visitFunctionTypeAliasElement(t, library); } diff --git a/pkg/dev_compiler/lib/src/kernel/property_model.dart b/pkg/dev_compiler/lib/src/kernel/property_model.dart index 4242554bf65d2..df0444bc16591 100644 --- a/pkg/dev_compiler/lib/src/kernel/property_model.dart +++ b/pkg/dev_compiler/lib/src/kernel/property_model.dart @@ -92,7 +92,7 @@ class _LibraryVirtualFieldModel { HashMap.fromIterables(allClasses, allClasses.map(getInstanceFieldMap)); for (var class_ in allClasses) { - Set superclasses = null; + Set superclasses; // Visit accessors in the current class, and see if they override an // otherwise private field. @@ -124,8 +124,7 @@ class _LibraryVirtualFieldModel { collectSupertypes(class_); superclasses.remove(class_); - superclasses.removeWhere( - (s) => s.enclosingLibrary != class_.enclosingLibrary); + superclasses.removeWhere((s) => s.enclosingLibrary != library); } // Look in all super classes to see if we're overriding a field in our diff --git a/runtime/vm/source_report.cc b/runtime/vm/source_report.cc index 50b44d987b8f3..0bcef136d7fd4 100644 --- a/runtime/vm/source_report.cc +++ b/runtime/vm/source_report.cc @@ -112,15 +112,18 @@ bool SourceReport::ShouldSkipFunction(const Function& func) { } intptr_t SourceReport::GetScriptIndex(const Script& script) { + ScriptTableEntry wrapper; const String& url = String::Handle(zone(), script.url()); - ScriptTableEntry* pair = script_table_.LookupValue(&url); + wrapper.key = &url; + wrapper.script = &Script::Handle(zone(), script.raw()); + ScriptTableEntry* pair = script_table_.LookupValue(&wrapper); if (pair != NULL) { return pair->index; } ScriptTableEntry* tmp = new ScriptTableEntry(); tmp->key = &url; tmp->index = next_script_index_++; - tmp->script = &Script::Handle(zone(), script.raw()); + tmp->script = wrapper.script; script_table_entries_.Add(tmp); script_table_.Insert(tmp); ASSERT(script_table_entries_.length() == next_script_index_); @@ -139,7 +142,10 @@ void SourceReport::VerifyScriptTable() { ASSERT(i == index); const String& url2 = String::Handle(zone(), script->url()); ASSERT(url2.Equals(*url)); - ScriptTableEntry* pair = script_table_.LookupValue(&url2); + ScriptTableEntry wrapper; + wrapper.key = &url2; + wrapper.script = &Script::Handle(zone(), script->raw()); + ScriptTableEntry* pair = script_table_.LookupValue(&wrapper); ASSERT(i == pair->index); } } diff --git a/runtime/vm/source_report.h b/runtime/vm/source_report.h index 8db241894cb06..5ab147f021200 100644 --- a/runtime/vm/source_report.h +++ b/runtime/vm/source_report.h @@ -94,17 +94,17 @@ class SourceReport { // Needed for DirectChainedHashMap. struct ScriptTableTrait { typedef ScriptTableEntry* Value; - typedef const String* Key; + typedef const ScriptTableEntry* Key; typedef ScriptTableEntry* Pair; - static Key KeyOf(Pair kv) { return kv->key; } + static Key KeyOf(Pair kv) { return kv; } static Value ValueOf(Pair kv) { return kv; } - static inline intptr_t Hashcode(Key key) { return key->Hash(); } + static inline intptr_t Hashcode(Key key) { return key->key->Hash(); } static inline bool IsKeyEqual(Pair kv, Key key) { - return kv->key->Equals(*key); + return kv->script->raw() == key->script->raw(); } }; diff --git a/tests/language_2/mixin_declaration/mixin_declaration_syntax_test.dart b/tests/language_2/mixin_declaration/mixin_declaration_syntax_test.dart index 9bfc38f8d6491..aba464029ac69 100644 --- a/tests/language_2/mixin_declaration/mixin_declaration_syntax_test.dart +++ b/tests/language_2/mixin_declaration/mixin_declaration_syntax_test.dart @@ -402,4 +402,19 @@ void main() { } Expect.equals(CeOwithM().toString(), CwithM().toString()); + + { + // Regression test for private fields. + var c = PrivateFieldClass(); + Expect.equals(42, c._foo); + } +} + + +mixin PrivateFieldMixin { + int _foo = 40; +} + +class PrivateFieldClass with PrivateFieldMixin { + int get _foo => super._foo + 2; } diff --git a/tools/VERSION b/tools/VERSION index 804d4a7c04c84..4f5aa1c61074b 100644 --- a/tools/VERSION +++ b/tools/VERSION @@ -28,4 +28,4 @@ MAJOR 2 MINOR 1 PATCH 0 PRERELEASE 9 -PRERELEASE_PATCH 0 +PRERELEASE_PATCH 1 diff --git a/tools/gn.py b/tools/gn.py index 50740efed5ea7..9b348628b88a4 100755 --- a/tools/gn.py +++ b/tools/gn.py @@ -248,7 +248,7 @@ def ToGnArgs(args, mode, arch, target_os): # Setup the user-defined sysroot. if UseSysroot(args, gn_args): - gn_args['dart_use_wheezy_sysroot'] = True + gn_args['dart_use_debian_sysroot'] = True else: sysroot = TargetSysroot(args) if sysroot: diff --git a/tools/set_ia32_sysroot.sh b/tools/set_ia32_sysroot.sh index c7156cea27b25..194433040640d 100755 --- a/tools/set_ia32_sysroot.sh +++ b/tools/set_ia32_sysroot.sh @@ -4,16 +4,16 @@ # 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. -# Sets the compiler environment variables to use a downloaded wheezy sysroot +# Sets the compiler environment variables to use a downloaded Debian sysroot # when building Dart with architecture ia32. -# Run this in the same working directory that you have run +# Run this in the same working directory that you have run # sdk/tools/download_chromium_sysroot.sh in. # Must be sourced, not run in a subshell, to modify the environment. # Run with the command ". sdk/tools/set_ia32_sysroot.sh" # Only tested and used on Ubuntu trusty linux. Used to build dart with # no requirement for glibc greater than version 2.14. -export CXXFLAGS="--sysroot=$PWD/build/linux/debian_wheezy_i386-sysroot -I=/usr/include/c++/4.6 -I=/usr/include/c++/4.6/i486-linux-gnu" +export CXXFLAGS="--sysroot=$PWD/build/linux/debian_jessie_i386-sysroot -I=/usr/include/c++/4.8 -I=/usr/include/c++/4.8/i486-linux-gnu" -export LDFLAGS=--sysroot=$PWD/build/linux/debian_wheezy_i386-sysroot -export CFLAGS=--sysroot=$PWD/build/linux/debian_wheezy_i386-sysroot +export LDFLAGS=--sysroot=$PWD/build/linux/debian_jessie_i386-sysroot +export CFLAGS=--sysroot=$PWD/build/linux/debian_jessie_i386-sysroot diff --git a/tools/set_x64_sysroot.sh b/tools/set_x64_sysroot.sh index bc28961ce609c..9c199ffd3b2cd 100755 --- a/tools/set_x64_sysroot.sh +++ b/tools/set_x64_sysroot.sh @@ -4,16 +4,16 @@ # 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. -# Sets the compiler environment variables to use a downloaded wheezy sysroot +# Sets the compiler environment variables to use a downloaded Debian sysroot # when building Dart with architecture x64. -# Run this in the same working directory that you have run +# Run this in the same working directory that you have run # sdk/tools/download_chromium_sysroot.sh in. # Must be sourced, not run in a subshell, to modify the environment. # Run with the command ". sdk/tools/set_x64_sysroot.sh" # Only tested and used on Ubuntu trusty linux. Used to build dart with # no requirement for glibc greater than version 2.14. -export CXXFLAGS="--sysroot=$PWD/build/linux/debian_wheezy_amd64-sysroot -I=/usr/include/c++/4.6 -I=/usr/include/c++/4.6/x86_64-linux-gnu" +export CXXFLAGS="--sysroot=$PWD/build/linux/debian_jessie_amd64-sysroot -I=/usr/include/c++/4.8 -I=/usr/include/c++/4.8/x86_64-linux-gnu" -export LDFLAGS=--sysroot=$PWD/build/linux/debian_wheezy_amd64-sysroot -export CFLAGS=--sysroot=$PWD/build/linux/debian_wheezy_amd64-sysroot +export LDFLAGS=--sysroot=$PWD/build/linux/debian_jessie_amd64-sysroot +export CFLAGS=--sysroot=$PWD/build/linux/debian_jessie_amd64-sysroot