Skip to content

Commit b0be7f4

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Fixes adding overrides first in bulk-fixes
Fixes: #61301 Change-Id: I73a97fc45089a6818c3255050880ed61a608194e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/444984 Reviewed-by: Samuel Rawlins <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Auto-Submit: Felipe Morschel <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]>
1 parent af074fb commit b0be7f4

File tree

5 files changed

+124
-25
lines changed

5 files changed

+124
-25
lines changed

pkg/analysis_server/integration_test/edit/bulk_fixes_test.dart

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,31 @@ class B extends A {
3737
expect(result.edits, hasLength(1));
3838
}
3939

40+
Future<void> test_bulk_fix_override_first() async {
41+
writeFile(sourcePath(file_paths.analysisOptionsYaml), '''
42+
linter:
43+
rules:
44+
- always_declare_return_types
45+
- annotate_overrides
46+
''');
47+
writeFile(sourcePath('test.dart'), '''
48+
abstract class A {
49+
void foo();
50+
}
51+
52+
class B extends A {
53+
foo() {}
54+
}
55+
''');
56+
await standardAnalysisSetup();
57+
await analysisFinished;
58+
59+
var result = await sendEditBulkFixes([sourceDirectory.path]);
60+
var edits = result.edits;
61+
expect(edits, hasLength(1));
62+
expect(edits.single.edits, hasLength(2));
63+
}
64+
4065
Future<void> test_bulk_fix_with_parts() async {
4166
writeFile(sourcePath(file_paths.analysisOptionsYaml), '''
4267
linter:
@@ -71,7 +96,7 @@ void a() {
7196
var result = await sendEditBulkFixes([sourceDirectory.path]);
7297
var edits = result.edits;
7398
expect(edits, hasLength(2));
74-
expect(edits[0].edits, hasLength(1));
75-
expect(edits[1].edits, hasLength(1));
99+
expect(edits.first.edits, hasLength(1));
100+
expect(edits.last.edits, hasLength(1));
76101
}
77102
}

pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import 'package:analyzer_plugin/protocol/protocol_common.dart'
5050
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart';
5151
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
5252
import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
53+
import 'package:linter/src/lint_codes.dart';
5354
import 'package:linter/src/lint_names.dart';
5455
import 'package:linter/src/rules/directives_ordering.dart';
5556
import 'package:meta/meta.dart';
@@ -545,7 +546,7 @@ class BulkFixProcessor {
545546
List<Diagnostic> originalDiagnostics,
546547
) sync* {
547548
var diagnostics = originalDiagnostics.toList();
548-
diagnostics.sort((a, b) => a.offset.compareTo(b.offset));
549+
diagnostics.sort(_fixOrder);
549550
for (var diagnostic in diagnostics) {
550551
if (_codes != null &&
551552
!_codes.contains(diagnostic.diagnosticCode.name.toLowerCase())) {
@@ -700,6 +701,23 @@ class BulkFixProcessor {
700701
}
701702
}
702703

704+
int _fixOrder(Diagnostic a, Diagnostic b) {
705+
var result = a.offset.compareTo(b.offset);
706+
if (result != 0) {
707+
return result;
708+
}
709+
// Special casing for `annotate_overrides` fix order
710+
// See https://github.com/dart-lang/sdk/issues/61301
711+
// Since the output for it should be before any other fixes like editing
712+
// the return type
713+
if (a.diagnosticCode == LinterLintCode.annotateOverrides) {
714+
return -1;
715+
} else if (b.diagnosticCode == LinterLintCode.annotateOverrides) {
716+
return 1;
717+
}
718+
return 0;
719+
}
720+
703721
/// Uses the change [builder] and the [fixContext] to create a fix for the
704722
/// given [diagnostic] in the compilation unit associated with the analysis
705723
/// [unitResult].

pkg/analysis_server/lib/src/services/correction/dart/add_return_type.dart

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,7 @@ class AddReturnType extends ResolvedCorrectionProducer {
6767
await builder.addDartFileEdit(file, (builder) {
6868
if (returnType is DynamicType || builder.canWriteType(returnType)) {
6969
builder.addInsertion(insertBeforeEntity.offset, (builder) {
70-
if (returnType is DynamicType) {
71-
builder.write('dynamic');
72-
} else {
73-
builder.writeType(returnType);
74-
}
70+
builder.writeType(returnType, shouldWriteDynamic: true);
7571
builder.write(' ');
7672
});
7773
}

pkg/analysis_server/test/lsp/commands/fix_all_in_workspace_test.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,46 @@ bool f() {
8383
setChangeAnnotationSupport();
8484
}
8585

86+
Future<void> test_annotatate_overrides_return_types() async {
87+
newFile(analysisOptionsPath, '''
88+
linter:
89+
rules:
90+
- always_declare_return_types
91+
- annotate_overrides
92+
''');
93+
94+
newFile(join(projectFolderPath, 'lib', 'a.dart'), '''
95+
abstract class A {
96+
void foo();
97+
}
98+
99+
class B extends A {
100+
foo() {}
101+
}
102+
''');
103+
104+
await initialize();
105+
var verifier = await verifyCommandEdits(
106+
Command(command: commandId, title: 'UNUSED'),
107+
'''
108+
>>>>>>>>>> lib/a.dart
109+
>>>>>>>>>> Add '@override' annotation: line 6
110+
>>>>>>>>>> Add return type: line 6
111+
abstract class A {
112+
void foo();
113+
}
114+
115+
class B extends A {
116+
@override
117+
void foo() {}
118+
}
119+
''',
120+
);
121+
verifier.edit.changeAnnotations?.values.forEach((annotation) {
122+
expect(annotation.needsConfirmation, expectRequiresConfirmation);
123+
});
124+
}
125+
86126
Future<void> test_documentChanges_notSupported() async {
87127
setDocumentChangesSupport(false);
88128

pkg/analysis_server/test/src/services/correction/fix/bulk_fix_processor_test.dart

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ part 'a.dart';
118118
lints: [LintNames.unnecessary_new],
119119
);
120120

121-
newFile('$testPackageLibPath/a.dart', '''
121+
newFile('$testPackageLibPath/c.dart', '''
122122
part 'test.dart';
123123
part 'b.dart';
124124
@@ -128,27 +128,28 @@ var c = C();
128128
''');
129129

130130
newFile('$testPackageLibPath/b.dart', '''
131-
part of 'a.dart';
131+
part of 'c.dart';
132132
133-
class B { }
133+
class B {}
134134
135135
var b = new B();
136136
''');
137137

138138
await resolveTestCode('''
139-
part of 'a.dart';
139+
part of 'c.dart';
140140
141-
class A { }
141+
class A {}
142142
143143
var a = new A();
144144
''');
145145

146146
expect(await computeHasFixes(), isTrue);
147-
expect(processor.changeMap.libraryMap.length, 1);
147+
processor = await computeFixes();
148+
expect(processor.changeMap.libraryMap, hasLength(2));
148149
}
149150

150-
/// https://github.com/dart-lang/sdk/issues/59572
151151
Future<void> test_hasFixes_in_part_and_library2() async {
152+
// https://github.com/dart-lang/sdk/issues/59572
152153
createAnalysisOptionsFile(
153154
experiments: experiments,
154155
lints: [LintNames.empty_statements, LintNames.prefer_const_constructors],
@@ -178,10 +179,9 @@ void a() {
178179
''');
179180

180181
expect(await computeHasFixes(), isTrue);
181-
expect(processor.changeMap.libraryMap.length, 1);
182-
expect(processor.fixDetails.length, 1);
183-
var details = processor.fixDetails;
184-
expect(details.first.fixes, hasLength(1));
182+
processor = await computeFixes();
183+
expect(processor.changeMap.libraryMap, hasLength(2));
184+
expect(processor.fixDetails.expand((d) => d.fixes), hasLength(2));
185185
}
186186

187187
Future<void> test_hasFixes_stoppedAfterFirst() async {
@@ -206,9 +206,7 @@ var a = new A();
206206
Future<void> test_noFixes() async {
207207
createAnalysisOptionsFile(
208208
experiments: experiments,
209-
lints: [
210-
'avoid_catching_errors', // NOTE: not in lintProducerMap
211-
],
209+
lints: [LintNames.avoid_catching_errors],
212210
);
213211

214212
await resolveTestCode('''
@@ -222,6 +220,30 @@ void bad() {
222220

223221
expect(await computeHasFixes(), isFalse);
224222
}
223+
224+
Future<void> test_override_first() async {
225+
createAnalysisOptionsFile(
226+
experiments: experiments,
227+
lints: [
228+
LintNames.annotate_overrides,
229+
LintNames.always_declare_return_types,
230+
],
231+
);
232+
await resolveTestCode('''
233+
abstract class A {
234+
void foo();
235+
}
236+
237+
class B extends A {
238+
foo() {}
239+
}
240+
''');
241+
242+
expect(await computeHasFixes(), isTrue);
243+
processor = await computeFixes();
244+
expect(processor.fixDetails.single.fixes, hasLength(2));
245+
expect(processor.builder.sourceChange.edits.single.edits, hasLength(2));
246+
}
225247
}
226248

227249
@reflectiveTest
@@ -230,9 +252,7 @@ class NoFixTest extends BulkFixProcessorTest {
230252
Future<void> test_noFix() async {
231253
createAnalysisOptionsFile(
232254
experiments: experiments,
233-
lints: [
234-
'avoid_catching_errors', // NOTE: not in lintProducerMap
235-
],
255+
lints: [LintNames.avoid_catching_errors],
236256
);
237257

238258
await resolveTestCode('''

0 commit comments

Comments
 (0)