diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart index 3386210b660..52e06c7a633 100644 --- a/pkg/analysis_server/lib/src/services/correction/assist.dart +++ b/pkg/analysis_server/lib/src/services/correction/assist.dart @@ -189,11 +189,7 @@ class DartAssistKind { static const SORT_CHILD_PROPERTY_LAST = const AssistKind( 'dart.assist.sort.child.properties.last', 30, - "Move child property to end of arguments", - // todo (pq): migrate to (conditional) fix - associatedErrorCodes: [ - 'sort_child_properties_last', - ]); + "Move child property to end of arguments"); static const SPLIT_AND_CONDITION = const AssistKind( 'dart.assist.splitIfConjunction', 30, "Split && condition"); static const SPLIT_VARIABLE_DECLARATION = const AssistKind( diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart index 4e265d6975d..af0c95b2ded 100644 --- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart +++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart @@ -140,7 +140,11 @@ class AssistProcessor extends BaseProcessor { await _addProposal_reparentFlutterList(); await _addProposal_replaceConditionalWithIfElse(); await _addProposal_replaceIfElseWithConditional(); - await _addProposal_sortChildPropertyLast(); + if (!_containsErrorCode( + {LintNames.sort_child_properties_last}, + )) { + await _addProposal_sortChildPropertyLast(); + } await _addProposal_splitAndCondition(); await _addProposal_splitVariableDeclaration(); await _addProposal_surroundWith(); @@ -2732,42 +2736,7 @@ class AssistProcessor extends BaseProcessor { } Future _addProposal_sortChildPropertyLast() async { - NamedExpression childProp = flutter.findNamedExpression(node, 'child'); - if (childProp == null) { - childProp = flutter.findNamedExpression(node, 'children'); - } - if (childProp == null) { - return; - } - - var parent = childProp.parent?.parent; - if (parent is! InstanceCreationExpression || - !flutter.isWidgetCreation(parent)) { - return; - } - - InstanceCreationExpression creationExpression = parent; - var args = creationExpression.argumentList; - - var last = args.arguments.last; - if (last == childProp) { - // Already sorted. - return; - } - - var changeBuilder = _newDartChangeBuilder(); - await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) { - var start = childProp.beginToken.previous.end; - var end = childProp.endToken.next.end; - var childRange = range.startOffsetEndOffset(start, end); - - var childText = utils.getRangeText(childRange); - builder.addSimpleReplacement(childRange, ''); - builder.addSimpleInsertion(last.end + 1, childText); - - changeBuilder.setSelection(new Position(file, last.end + 1)); - }); - + final changeBuilder = await createBuilder_sortChildPropertyLast(); _addAssistFromBuilder( changeBuilder, DartAssistKind.SORT_CHILD_PROPERTY_LAST); } diff --git a/pkg/analysis_server/lib/src/services/correction/base_processor.dart b/pkg/analysis_server/lib/src/services/correction/base_processor.dart index 2cbd318aead..e95de5768cd 100644 --- a/pkg/analysis_server/lib/src/services/correction/base_processor.dart +++ b/pkg/analysis_server/lib/src/services/correction/base_processor.dart @@ -17,6 +17,7 @@ import 'package:analyzer/src/dart/analysis/session_helper.dart'; import 'package:analyzer/src/dart/ast/utilities.dart'; import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; import 'package:analyzer/src/generated/resolver.dart'; +import 'package:analyzer_plugin/protocol/protocol_common.dart'; import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart'; import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart'; import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart'; @@ -859,6 +860,46 @@ abstract class BaseProcessor { return changeBuilder; } + Future createBuilder_sortChildPropertyLast() async { + NamedExpression childProp = flutter.findNamedExpression(node, 'child'); + if (childProp == null) { + childProp = flutter.findNamedExpression(node, 'children'); + } + if (childProp == null) { + return null; + } + + var parent = childProp.parent?.parent; + if (parent is! InstanceCreationExpression || + !flutter.isWidgetCreation(parent)) { + return null; + } + + InstanceCreationExpression creationExpression = parent; + var args = creationExpression.argumentList; + + var last = args.arguments.last; + if (last == childProp) { + // Already sorted. + return null; + } + + var changeBuilder = _newDartChangeBuilder(); + await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) { + var start = childProp.beginToken.previous.end; + var end = childProp.endToken.next.end; + var childRange = range.startOffsetEndOffset(start, end); + + var childText = utils.getRangeText(childRange); + builder.addSimpleReplacement(childRange, ''); + builder.addSimpleInsertion(last.end + 1, childText); + + changeBuilder.setSelection(new Position(file, last.end + 1)); + }); + + return changeBuilder; + } + /// todo (pq): unify with similar behavior in fix. Future createBuilder_removeTypeAnnotation() async { VariableDeclarationList declarationList = diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart index bac44cbed10..79277ba4d04 100644 --- a/pkg/analysis_server/lib/src/services/correction/fix.dart +++ b/pkg/analysis_server/lib/src/services/correction/fix.dart @@ -354,6 +354,10 @@ class DartFixKind { "Replace the '.' with a '?.' in the invocation"); static const REPLACE_WITH_TEAR_OFF = const FixKind( 'REPLACE_WITH_TEAR_OFF', 50, "Replace function literal with tear-off"); + static const SORT_CHILD_PROPERTY_LAST = const FixKind( + 'SORT_CHILD_PROPERTY_LAST', + 50, + "Move child property to end of arguments"); static const UPDATE_SDK_CONSTRAINTS = const FixKind('UPDATE_SDK_CONSTRAINTS', 50, "Update the SDK constraints"); static const USE_CONST = const FixKind('USE_CONST', 50, "Change to constant"); diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart index b47ae29788f..8462ee4b568 100644 --- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart +++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart @@ -671,6 +671,9 @@ class FixProcessor extends BaseProcessor { if (name == LintNames.prefer_spread_collections) { await _addFix_convertAddAllToSpread(); } + if (name == LintNames.sort_child_properties_last) { + await _addFix_sortChildPropertiesLast(); + } if (name == LintNames.type_init_formals) { await _addFix_removeTypeAnnotation(); } @@ -3798,6 +3801,11 @@ class FixProcessor extends BaseProcessor { } } + Future _addFix_sortChildPropertiesLast() async { + final changeBuilder = await createBuilder_sortChildPropertyLast(); + _addFixFromBuilder(changeBuilder, DartFixKind.SORT_CHILD_PROPERTY_LAST); + } + Future _addFix_undefinedClass_useSimilar() async { AstNode node = this.node; // Prepare the optional import prefix name. diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart index b9fa50ed79c..b3ee6f13897 100644 --- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart +++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart @@ -49,8 +49,9 @@ class LintNames { static const String prefer_null_aware_operators = 'prefer_null_aware_operators'; static const String prefer_single_quotes = 'prefer_single_quotes'; - static const String slash_for_doc_comments = 'slash_for_doc_comments'; static const String prefer_spread_collections = 'prefer_spread_collections'; + static const String slash_for_doc_comments = 'slash_for_doc_comments'; + static const String sort_child_properties_last = 'sort_child_properties_last'; static const String type_annotate_public_apis = 'type_annotate_public_apis'; static const String type_init_formals = 'type_init_formals'; static const String unawaited_futures = 'unawaited_futures'; diff --git a/pkg/analysis_server/test/src/services/correction/assist/sort_child_property_last_test.dart b/pkg/analysis_server/test/src/services/correction/assist/sort_child_property_last_test.dart index 4cc5973b8be..b8a4916e4c4 100644 --- a/pkg/analysis_server/test/src/services/correction/assist/sort_child_property_last_test.dart +++ b/pkg/analysis_server/test/src/services/correction/assist/sort_child_property_last_test.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:analysis_server/src/services/correction/assist.dart'; +import 'package:analysis_server/src/services/linter/lint_names.dart'; import 'package:analyzer_plugin/utilities/assist/assist.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; @@ -97,4 +98,24 @@ main() { '''); assertExitPosition(after: "],"); } + + test_sort_noAssistWithLint() async { + addFlutterPackage(); + createAnalysisOptionsFile(lints: [LintNames.sort_child_properties_last]); + verifyNoTestUnitErrors = false; + await resolveTestUnit(''' +import 'package:flutter/material.dart'; +main() { + Column( + /*caret*/children: [ + Text('aaa'), + Text('bbbbbb'), + Text('ccccccccc'), + ], + crossAxisAlignment: CrossAxisAlignment.center, + ); +} +'''); + await assertNoAssist(); + } } diff --git a/pkg/analysis_server/test/src/services/correction/fix/sort_child_property_last_test.dart b/pkg/analysis_server/test/src/services/correction/fix/sort_child_property_last_test.dart new file mode 100644 index 00000000000..9a7ca7c9c3c --- /dev/null +++ b/pkg/analysis_server/test/src/services/correction/fix/sort_child_property_last_test.dart @@ -0,0 +1,56 @@ +// Copyright (c) 2019, 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/src/services/correction/fix.dart'; +import 'package:analysis_server/src/services/linter/lint_names.dart'; +import 'package:analyzer_plugin/utilities/fixes/fixes.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import 'fix_processor.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(SortChildPropertiesLastTest); + }); +} + +@reflectiveTest +class SortChildPropertiesLastTest extends FixProcessorLintTest { + @override + FixKind get kind => DartFixKind.SORT_CHILD_PROPERTY_LAST; + + @override + String get lintCode => LintNames.sort_child_properties_last; + + /// More coverage in the `sort_child_properties_last_test.dart` assist test. + test_sort() async { + addFlutterPackage(); + await resolveTestUnit(''' +import 'package:flutter/material.dart'; +main() { + Column( + /*LINT*/children: [ + Text('aaa'), + Text('bbbbbb'), + Text('ccccccccc'), + ], + crossAxisAlignment: CrossAxisAlignment.center, + ); +} +'''); + await assertHasFix(''' +import 'package:flutter/material.dart'; +main() { + Column( + crossAxisAlignment: CrossAxisAlignment.center, + /*LINT*/children: [ + Text('aaa'), + Text('bbbbbb'), + Text('ccccccccc'), + ], + ); +} +'''); + } +} diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart index 5c316f5f429..52eb44ff07b 100644 --- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart +++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart @@ -118,6 +118,7 @@ import 'replace_with_is_empty_test.dart' as replace_with_is_empty; import 'replace_with_is_not_empty_test.dart' as replace_with_is_not_empty; import 'replace_with_null_aware_test.dart' as replace_with_null_aware; import 'replace_with_tear_off_test.dart' as replace_with_tear_off; +import 'sort_child_property_last_test.dart' as sort_properties_last; import 'update_sdk_constraints_test.dart' as update_sdk_constraints; import 'use_const_test.dart' as use_const; import 'use_effective_integer_division_test.dart' @@ -230,6 +231,7 @@ main() { replace_with_is_not_empty.main(); replace_with_null_aware.main(); replace_with_tear_off.main(); + sort_properties_last.main(); update_sdk_constraints.main(); use_const.main(); use_effective_integer_division.main();