Skip to content

Commit 54981a4

Browse files
pqCommit Queue
authored andcommitted
[fix] add remove_comment producer and ignore bulk fixes
Change-Id: I0e86531a84860488d79905e4a43719465f3e7fce Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/404960 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Phil Quitslund <[email protected]>
1 parent 95f0052 commit 54981a4

File tree

9 files changed

+272
-39
lines changed

9 files changed

+272
-39
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analysis_server/src/services/correction/fix.dart';
6+
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
7+
import 'package:analyzer/source/source_range.dart';
8+
import 'package:analyzer/src/dart/ast/token.dart';
9+
import 'package:analyzer/src/utilities/extensions/ast.dart';
10+
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
11+
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
12+
13+
class RemoveComment extends ResolvedCorrectionProducer {
14+
RemoveComment({required super.context});
15+
16+
factory RemoveComment.ignore({required CorrectionProducerContext context}) =>
17+
_RemoveIgnoreComment(context: context);
18+
19+
@override
20+
CorrectionApplicability get applicability =>
21+
CorrectionApplicability.singleLocation;
22+
23+
@override
24+
FixKind get fixKind => DartFixKind.REMOVE_COMMENT;
25+
26+
@override
27+
Future<void> compute(ChangeBuilder builder) async {
28+
var diagnostic = this.diagnostic;
29+
if (diagnostic == null) return;
30+
31+
var diagnosticOffset = diagnostic.problemMessage.offset;
32+
33+
var comment = node.commentTokenCovering(diagnosticOffset);
34+
if (comment is! CommentToken) return;
35+
36+
await builder.addDartFileEdit(file, (builder) {
37+
var start = utils.getLineContentStart(comment.offset);
38+
var end = utils.getLineContentEnd(comment.end);
39+
var nextLine = utils.getLineNext(comment.end);
40+
if (nextLine != end) {
41+
// Preserve indent if there is more on the line after the comment.
42+
start = comment.offset;
43+
} else if (start != utils.getLineThis(comment.offset)) {
44+
// Preserve newline if there is more on the line before the comment.
45+
end -= utils.endOfLine.length;
46+
}
47+
builder.addDeletion(SourceRange(start, end - start));
48+
});
49+
}
50+
}
51+
52+
class _RemoveIgnoreComment extends RemoveComment {
53+
_RemoveIgnoreComment({required super.context});
54+
55+
@override
56+
CorrectionApplicability get applicability =>
57+
CorrectionApplicability.automatically;
58+
59+
@override
60+
FixKind get fixKind => DartFixKind.REMOVE_UNNECESSARY_IGNORE_COMMENT;
61+
62+
@override
63+
FixKind get multiFixKind =>
64+
DartFixKind.REMOVE_UNNECESSARY_IGNORE_COMMENT_MULTI;
65+
}

pkg/analysis_server/lib/src/services/correction/dart/remove_ignore.dart renamed to pkg/analysis_server/lib/src/services/correction/dart/remove_ignored_diagnostic.dart

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,23 @@ import 'package:analyzer/src/utilities/extensions/ast.dart';
1111
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
1212
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
1313

14-
class RemoveIgnore extends ResolvedCorrectionProducer {
14+
class RemoveIgnoredDiagnostic extends ResolvedCorrectionProducer {
1515
String _diagnosticName = '';
16-
RemoveIgnore({required super.context});
16+
RemoveIgnoredDiagnostic({required super.context});
1717

1818
@override
1919
CorrectionApplicability get applicability =>
20-
CorrectionApplicability.singleLocation;
20+
CorrectionApplicability.automatically;
2121

2222
@override
2323
List<String> get fixArguments => [_diagnosticName];
2424

2525
@override
2626
FixKind get fixKind => DartFixKind.REMOVE_IGNORED_DIAGNOSTIC;
2727

28+
@override
29+
FixKind get multiFixKind => DartFixKind.REMOVE_IGNORED_DIAGNOSTIC_MULTI;
30+
2831
@override
2932
Future<void> compute(ChangeBuilder builder) async {
3033
var diagnostic = this.diagnostic;
@@ -35,6 +38,8 @@ class RemoveIgnore extends ResolvedCorrectionProducer {
3538
var comment = node.commentTokenCovering(diagnosticOffset);
3639
if (comment is! CommentToken) return;
3740

41+
var inCommentOffset = diagnosticOffset - comment.offset;
42+
3843
SourceRange? rangeToDelete;
3944

4045
var ignoredElements = comment.ignoredElements.toList();
@@ -49,9 +54,9 @@ class RemoveIgnore extends ResolvedCorrectionProducer {
4954
var commentText = comment.lexeme;
5055
if (scanBack) {
5156
// Scan back for a preceding comma:
52-
for (var offset = ignoredElementOffset; offset > -1; --offset) {
57+
for (var offset = inCommentOffset; offset > -1; --offset) {
5358
if (commentText[offset] == ',') {
54-
var backSteps = ignoredElementOffset - offset;
59+
var backSteps = inCommentOffset - offset;
5560
rangeToDelete = SourceRange(
5661
diagnosticOffset - backSteps,
5762
_diagnosticName.length + backSteps,
@@ -61,14 +66,14 @@ class RemoveIgnore extends ResolvedCorrectionProducer {
6166
}
6267
} else {
6368
// Scan forward for a trailing comma:
64-
var chars = commentText.substring(ignoredElementOffset).indexOf(',');
69+
var chars = commentText.substring(inCommentOffset).indexOf(',');
6570
if (chars == -1) return;
6671

6772
// Eat the comma
6873
chars++;
6974

7075
// Eat a trailing space if needed
71-
if (commentText[ignoredElementOffset + chars] == ' ') chars++;
76+
if (commentText[inCommentOffset + chars] == ' ') chars++;
7277

7378
rangeToDelete = SourceRange(ignoredElementOffset, chars);
7479
}

pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2422,13 +2422,9 @@ LintCode.unnecessary_final_without_type:
24222422
LintCode.unnecessary_getters_setters:
24232423
status: hasFix
24242424
LintCode.unnecessary_ignore:
2425-
status: needsFix
2426-
notes: |-
2427-
Remove the ignore comment.
2425+
status: hasFix
24282426
LintCode.unnecessary_ignore_file:
2429-
status: needsFix
2430-
notes: |-
2431-
Remove the ignore comment.
2427+
status: hasFix
24322428
LintCode.unnecessary_ignore_name:
24332429
status: hasFix
24342430
LintCode.unnecessary_ignore_name_file:

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,11 @@ abstract final class DartFixKind {
11341134
DartFixKindPriority.inFile,
11351135
'Remove {0}commas from {1} everywhere in file',
11361136
);
1137+
static const REMOVE_COMMENT = FixKind(
1138+
'dart.fix.remove.comment',
1139+
DartFixKindPriority.standard,
1140+
'Remove the comment',
1141+
);
11371142
static const REMOVE_COMPARISON = FixKind(
11381143
'dart.fix.remove.comparison',
11391144
DartFixKindPriority.standard,
@@ -1271,6 +1276,11 @@ abstract final class DartFixKind {
12711276
DartFixKindPriority.standard,
12721277
'Remove {0}',
12731278
);
1279+
static const REMOVE_IGNORED_DIAGNOSTIC_MULTI = FixKind(
1280+
'dart.fix.remove.ignored.diagnostic.multi',
1281+
DartFixKindPriority.inFile,
1282+
'Remove unnecessary ignored diagnostics everywhere in file',
1283+
);
12741284
static const REMOVE_INVOCATION = FixKind(
12751285
'dart.fix.remove.invocation',
12761286
DartFixKindPriority.standard,
@@ -1513,6 +1523,16 @@ abstract final class DartFixKind {
15131523
DartFixKindPriority.inFile,
15141524
"Remove unnecessary 'Container's in file",
15151525
);
1526+
static const REMOVE_UNNECESSARY_IGNORE_COMMENT = FixKind(
1527+
'dart.fix.remove.ignore.comment',
1528+
DartFixKindPriority.standard,
1529+
'Remove unnecessary ignore comment',
1530+
);
1531+
static const REMOVE_UNNECESSARY_IGNORE_COMMENT_MULTI = FixKind(
1532+
'dart.fix.remove.ignore.comment.multi',
1533+
DartFixKindPriority.inFile,
1534+
'Remove unnecessary ignore comments everywhere in file',
1535+
);
15161536
static const REMOVE_UNNECESSARY_LATE = FixKind(
15171537
'dart.fix.remove.unnecessaryLate',
15181538
DartFixKindPriority.standard,

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ import 'package:analysis_server/src/services/correction/dart/remove_await.dart';
131131
import 'package:analysis_server/src/services/correction/dart/remove_break.dart';
132132
import 'package:analysis_server/src/services/correction/dart/remove_character.dart';
133133
import 'package:analysis_server/src/services/correction/dart/remove_comma.dart';
134+
import 'package:analysis_server/src/services/correction/dart/remove_comment.dart';
134135
import 'package:analysis_server/src/services/correction/dart/remove_comparison.dart';
135136
import 'package:analysis_server/src/services/correction/dart/remove_const.dart';
136137
import 'package:analysis_server/src/services/correction/dart/remove_constructor.dart';
@@ -146,7 +147,7 @@ import 'package:analysis_server/src/services/correction/dart/remove_empty_else.d
146147
import 'package:analysis_server/src/services/correction/dart/remove_empty_statement.dart';
147148
import 'package:analysis_server/src/services/correction/dart/remove_extends_clause.dart';
148149
import 'package:analysis_server/src/services/correction/dart/remove_if_null_operator.dart';
149-
import 'package:analysis_server/src/services/correction/dart/remove_ignore.dart';
150+
import 'package:analysis_server/src/services/correction/dart/remove_ignored_diagnostic.dart';
150151
import 'package:analysis_server/src/services/correction/dart/remove_initializer.dart';
151152
import 'package:analysis_server/src/services/correction/dart/remove_interpolation_braces.dart';
152153
import 'package:analysis_server/src/services/correction/dart/remove_invocation.dart';
@@ -486,11 +487,10 @@ final _builtInLintProducers = <LintCode, List<ProducerGenerator>>{
486487
LinterLintCode.unnecessary_final_with_type: [ReplaceFinalWithVar.new],
487488
LinterLintCode.unnecessary_final_without_type: [ReplaceFinalWithVar.new],
488489
LinterLintCode.unnecessary_getters_setters: [MakeFieldPublic.new],
489-
LinterLintCode.unnecessary_ignore_name: [RemoveIgnore.new],
490-
LinterLintCode.unnecessary_ignore_name_file: [RemoveIgnore.new],
491-
// TODO(pq): add =>
492-
// LinterLintCode.unnecessary_ignore: [RemoveComment.new],
493-
// LinterLintCode.unnecessary_ignore_file: [RemoveComment.new],
490+
LinterLintCode.unnecessary_ignore_name: [RemoveIgnoredDiagnostic.new],
491+
LinterLintCode.unnecessary_ignore_name_file: [RemoveIgnoredDiagnostic.new],
492+
LinterLintCode.unnecessary_ignore: [RemoveComment.ignore],
493+
LinterLintCode.unnecessary_ignore_file: [RemoveComment.ignore],
494494
LinterLintCode.unnecessary_lambdas: [ReplaceWithTearOff.new],
495495
LinterLintCode.unnecessary_late: [RemoveUnnecessaryLate.new],
496496
LinterLintCode.unnecessary_library_directive: [
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
import 'package:analysis_server/src/services/correction/fix.dart';
5+
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
6+
import 'package:linter/src/lint_names.dart';
7+
import 'package:test_reflective_loader/test_reflective_loader.dart';
8+
9+
import 'fix_processor.dart';
10+
11+
void main() {
12+
defineReflectiveSuite(() {
13+
defineReflectiveTests(RemoveUnnecessaryIgnoreCommentTest);
14+
defineReflectiveTests(RemoveUnnecessaryIgnoreCommentBulkTest);
15+
});
16+
}
17+
18+
@reflectiveTest
19+
class RemoveUnnecessaryIgnoreCommentBulkTest extends BulkFixProcessorTest {
20+
@override
21+
String get lintCode => LintNames.unnecessary_ignore;
22+
23+
Future<void> test_file() async {
24+
await resolveTestCode('''
25+
// ignore_for_file: unused_local_variable
26+
// ignore_for_file: return_of_invalid_type
27+
void f(){}
28+
''');
29+
await assertHasFix('''
30+
void f(){}
31+
''');
32+
}
33+
34+
Future<void> test_line() async {
35+
await resolveTestCode('''
36+
class C {
37+
// ignore: unused_local_variable
38+
// ignore: return_of_invalid_type
39+
void f(){}
40+
}
41+
''');
42+
await assertHasFix('''
43+
class C {
44+
void f(){}
45+
}
46+
''');
47+
}
48+
}
49+
50+
@reflectiveTest
51+
class RemoveUnnecessaryIgnoreCommentTest extends FixProcessorLintTest {
52+
@override
53+
FixKind get kind => DartFixKind.REMOVE_UNNECESSARY_IGNORE_COMMENT;
54+
@override
55+
String get lintCode => LintNames.unnecessary_ignore;
56+
Future<void> test_file() async {
57+
await resolveTestCode('''
58+
// ignore_for_file: unused_local_variable
59+
void f(){}
60+
''');
61+
await assertHasFix('''
62+
void f(){}
63+
''');
64+
}
65+
66+
Future<void> test_line() async {
67+
await resolveTestCode('''
68+
class C {
69+
// ignore: unused_local_variable
70+
void f(){}
71+
}
72+
''');
73+
await assertHasFix('''
74+
class C {
75+
void f(){}
76+
}
77+
''');
78+
}
79+
}

pkg/analysis_server/test/src/services/correction/fix/remove_ignore_test.dart renamed to pkg/analysis_server/test/src/services/correction/fix/remove_ignored_diagnostic_test.dart

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,69 @@ import 'fix_processor.dart';
1212
void main() {
1313
defineReflectiveSuite(() {
1414
defineReflectiveTests(RemoveUnnecessaryIgnoreTest);
15+
defineReflectiveTests(RemoveUnnecessaryIgnoreBulkTest);
1516
});
1617
}
1718

18-
// TODO(pq): add bulk fix tests
19+
@reflectiveTest
20+
class RemoveUnnecessaryIgnoreBulkTest extends BulkFixProcessorTest {
21+
@override
22+
String get lintCode => LintNames.unnecessary_ignore;
23+
24+
Future<void> test_file() async {
25+
await resolveTestCode('''
26+
// ignore_for_file: non_bool_negation_expression, return_of_invalid_type
27+
// ignore_for_file: unused_local_variable, return_of_invalid_type
28+
29+
int f() => null;
30+
''');
31+
await assertHasFix('''
32+
// ignore_for_file: return_of_invalid_type
33+
// ignore_for_file: return_of_invalid_type
34+
35+
int f() => null;
36+
''');
37+
}
38+
39+
Future<void> test_line() async {
40+
await resolveTestCode('''
41+
class C {
42+
// ignore: non_bool_negation_expression, return_of_invalid_type
43+
int f() => null;
44+
45+
// ignore: return_of_invalid_type, unused_local_variable
46+
int g() => null;
47+
}
48+
''');
49+
await assertHasFix('''
50+
class C {
51+
// ignore: return_of_invalid_type
52+
int f() => null;
53+
54+
// ignore: return_of_invalid_type
55+
int g() => null;
56+
}
57+
''');
58+
}
59+
60+
Future<void> test_line_multi() async {
61+
await resolveTestCode('''
62+
class C {
63+
// ignore: non_bool_negation_expression, return_of_invalid_type
64+
// ignore: return_of_invalid_type, unused_local_variable
65+
int g() => null;
66+
}
67+
''');
68+
await assertHasFix('''
69+
class C {
70+
// ignore: return_of_invalid_type
71+
// ignore: return_of_invalid_type
72+
int g() => null;
73+
}
74+
''');
75+
}
76+
}
77+
1978
@reflectiveTest
2079
class RemoveUnnecessaryIgnoreTest extends FixProcessorLintTest {
2180
@override

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ import 'remove_empty_else_test.dart' as remove_empty_else;
187187
import 'remove_empty_statement_test.dart' as remove_empty_statement;
188188
import 'remove_extends_clause_test.dart' as remove_extends_clause;
189189
import 'remove_if_null_operator_test.dart' as remove_if_null_operator;
190-
import 'remove_ignore_test.dart' as remove_ignore;
190+
import 'remove_ignore_comment_test.dart' as remove_ignore_comment;
191+
import 'remove_ignored_diagnostic_test.dart' as remove_ignored_diagnostic;
191192
import 'remove_initializer_test.dart' as remove_initializer;
192193
import 'remove_interpolation_braces_test.dart' as remove_interpolation_braces;
193194
import 'remove_invocation_test.dart' as remove_invocation;
@@ -466,7 +467,8 @@ void main() {
466467
remove_empty_statement.main();
467468
remove_extends_clause.main();
468469
remove_if_null_operator.main();
469-
remove_ignore.main();
470+
remove_ignore_comment.main();
471+
remove_ignored_diagnostic.main();
470472
remove_initializer.main();
471473
remove_interpolation_braces.main();
472474
remove_invocation.main();

0 commit comments

Comments
 (0)