Skip to content

Commit d4fd853

Browse files
pqcommit-bot@chromium.org
authored andcommitted
fix for unused_element
Change-Id: Id72c792dff73a08a10f03f494bf3adc39b91b872 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/117521 Commit-Queue: Phil Quitslund <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 6e76bda commit d4fd853

File tree

4 files changed

+206
-8
lines changed

4 files changed

+206
-8
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ class DartFixKind {
318318
'REMOVE_UNUSED_CATCH_CLAUSE', 50, "Remove unused 'catch' clause");
319319
static const REMOVE_UNUSED_CATCH_STACK = const FixKind(
320320
'REMOVE_UNUSED_CATCH_STACK', 50, "Remove unused stack trace variable");
321+
static const REMOVE_UNUSED_ELEMENT =
322+
const FixKind('REMOVE_UNUSED_ELEMENT', 50, "Remove unused element");
321323
static const REMOVE_UNUSED_FIELD =
322324
const FixKind('REMOVE_UNUSED_FIELD', 50, "Remove unused field");
323325
static const REMOVE_UNUSED_IMPORT = const FixKind(

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

+45-8
Original file line numberDiff line numberDiff line change
@@ -372,16 +372,12 @@ class FixProcessor extends BaseProcessor {
372372
if (errorCode == HintCode.UNUSED_CATCH_STACK) {
373373
await _addFix_removeUnusedCatchStack();
374374
}
375-
376-
// todo (pq): add support for elements.
377-
if (errorCode ==
378-
HintCode
379-
.UNUSED_FIELD /* ||
380-
errorCode == HintCode.UNUSED_ELEMENT */
381-
) {
375+
if (errorCode == HintCode.UNUSED_ELEMENT) {
376+
await _addFix_removeUnusedElement();
377+
}
378+
if (errorCode == HintCode.UNUSED_FIELD) {
382379
await _addFix_removeUnusedField();
383380
}
384-
385381
if (errorCode == HintCode.UNUSED_IMPORT) {
386382
await _addFix_removeUnusedImport();
387383
}
@@ -3589,6 +3585,47 @@ class FixProcessor extends BaseProcessor {
35893585
_addFixFromBuilder(changeBuilder, DartFixKind.REMOVE_UNUSED_FIELD);
35903586
}
35913587

3588+
Future<void> _addFix_removeUnusedElement() async {
3589+
final sourceRanges = <SourceRange>[];
3590+
final referencedNode = node.parent;
3591+
if (referencedNode is ClassDeclaration ||
3592+
referencedNode is EnumDeclaration ||
3593+
referencedNode is FunctionDeclaration ||
3594+
referencedNode is FunctionTypeAlias ||
3595+
referencedNode is MethodDeclaration ||
3596+
referencedNode is VariableDeclaration) {
3597+
final element = referencedNode is Declaration
3598+
? referencedNode.declaredElement
3599+
: (referencedNode as NamedCompilationUnitMember).declaredElement;
3600+
final references = _findAllReferences(unit, element);
3601+
// todo (pq): consider filtering for references that are limited to within the class.
3602+
if (references.length == 1) {
3603+
var sourceRange;
3604+
if (referencedNode is VariableDeclaration) {
3605+
VariableDeclarationList parent = referencedNode.parent;
3606+
if (parent.variables.length == 1) {
3607+
sourceRange = utils.getLinesRange(range.node(parent.parent));
3608+
} else {
3609+
sourceRange = range.nodeInList(parent.variables, node);
3610+
}
3611+
} else {
3612+
sourceRange = utils.getLinesRange(range.node(referencedNode));
3613+
}
3614+
sourceRanges.add(sourceRange);
3615+
}
3616+
}
3617+
3618+
if (sourceRanges.isNotEmpty) {
3619+
final changeBuilder = _newDartChangeBuilder();
3620+
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
3621+
for (var sourceRange in sourceRanges) {
3622+
builder.addDeletion(sourceRange);
3623+
}
3624+
});
3625+
_addFixFromBuilder(changeBuilder, DartFixKind.REMOVE_UNUSED_ELEMENT);
3626+
}
3627+
}
3628+
35923629
Future<void> _addFix_removeUnusedImport() async {
35933630
// prepare ImportDirective
35943631
ImportDirective importDirective =
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// Copyright (c) 2019, 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:analyzer_plugin/utilities/fixes/fixes.dart';
7+
import 'package:test_reflective_loader/test_reflective_loader.dart';
8+
9+
import 'fix_processor.dart';
10+
11+
main() {
12+
defineReflectiveSuite(() {
13+
defineReflectiveTests(RemoveUnusedElementTest);
14+
});
15+
}
16+
17+
@reflectiveTest
18+
class RemoveUnusedElementTest extends FixProcessorTest {
19+
@override
20+
FixKind get kind => DartFixKind.REMOVE_UNUSED_ELEMENT;
21+
22+
test_class_notUsed_inClassMember() async {
23+
await resolveTestUnit(r'''
24+
class _A {
25+
static staticMethod() {
26+
new _A();
27+
}
28+
}
29+
''');
30+
// todo (pq): consider supporting the case where references are limited to within the class.
31+
await assertNoFix();
32+
}
33+
34+
test_class_notUsed_isExpression() async {
35+
await resolveTestUnit(r'''
36+
class _A {}
37+
main(p) {
38+
if (p is _A) {
39+
}
40+
}
41+
''');
42+
// We don't know what to do with the reference.
43+
await assertNoFix();
44+
}
45+
46+
test_class_notUsed_noReference() async {
47+
await resolveTestUnit(r'''
48+
class _A {
49+
}
50+
''');
51+
await assertHasFix(r'''
52+
''');
53+
}
54+
55+
test_enum_notUsed_noReference() async {
56+
await resolveTestUnit(r'''
57+
enum _MyEnum {A, B, C}
58+
''');
59+
await assertHasFix(r'''
60+
''');
61+
}
62+
63+
test_functionLocal_notUsed_noReference() async {
64+
await resolveTestUnit(r'''
65+
main() {
66+
f() {}
67+
}
68+
''');
69+
await assertHasFix(r'''
70+
main() {
71+
}
72+
''');
73+
}
74+
75+
test_functionTop_notUsed_noReference() async {
76+
await resolveTestUnit(r'''
77+
_f() {}
78+
main() {
79+
}
80+
''');
81+
await assertHasFix(r'''
82+
main() {
83+
}
84+
''');
85+
}
86+
87+
test_functionTypeAlias_notUsed_noReference() async {
88+
await resolveTestUnit(r'''
89+
typedef _F(a, b);
90+
main() {
91+
}
92+
''');
93+
await assertHasFix(r'''
94+
main() {
95+
}
96+
''');
97+
}
98+
99+
test_getter_notUsed_noReference() async {
100+
await resolveTestUnit(r'''
101+
class A {
102+
get _g => null;
103+
}
104+
''');
105+
await assertHasFix(r'''
106+
class A {
107+
}
108+
''');
109+
}
110+
111+
test_method_notUsed_noReference() async {
112+
await resolveTestUnit(r'''
113+
class A {
114+
static _m() {}
115+
}
116+
''');
117+
await assertHasFix(r'''
118+
class A {
119+
}
120+
''');
121+
}
122+
123+
test_setter_notUsed_noReference() async {
124+
await resolveTestUnit(r'''
125+
class A {
126+
set _s(x) {}
127+
}
128+
''');
129+
await assertHasFix(r'''
130+
class A {
131+
}
132+
''');
133+
}
134+
135+
test_topLevelVariable_notUsed() async {
136+
await resolveTestUnit(r'''
137+
int _a = 1;
138+
main() {
139+
_a = 2;
140+
}
141+
''');
142+
// Reference.
143+
await assertNoFix();
144+
}
145+
146+
test_topLevelVariable_notUsed_noReference() async {
147+
await resolveTestUnit(r'''
148+
int _a = 1;
149+
main() {
150+
}
151+
''');
152+
await assertHasFix(r'''
153+
main() {
154+
}
155+
''');
156+
}
157+
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ import 'remove_unnecessary_const_test.dart' as remove_unnecessary_const;
102102
import 'remove_unnecessary_new_test.dart' as remove_unnecessary_new;
103103
import 'remove_unused_catch_clause_test.dart' as remove_unused_catch_clause;
104104
import 'remove_unused_catch_stack_test.dart' as remove_unused_catch_stack;
105+
import 'remove_unused_element_test.dart' as remove_unused_element;
105106
import 'remove_unused_field_test.dart' as remove_unused_field;
106107
import 'remove_unused_import_test.dart' as remove_unused_import;
107108
import 'remove_unused_label_test.dart' as remove_unused_label;
@@ -221,6 +222,7 @@ main() {
221222
remove_unnecessary_new.main();
222223
remove_unused_catch_clause.main();
223224
remove_unused_catch_stack.main();
225+
remove_unused_element.main();
224226
remove_unused_field.main();
225227
remove_unused_import.main();
226228
remove_unused_label.main();

0 commit comments

Comments
 (0)