Skip to content

Commit f879240

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Extract RemoveUnusedElement and RemoveUnusedField producers.
There is an exception that we see internally, and I'd like to try to refactor the code a bit. [email protected] Change-Id: I276e009437fd3cac82391126bde95c73225bca0c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/138784 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 54e96f6 commit f879240

File tree

3 files changed

+164
-144
lines changed

3 files changed

+164
-144
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ abstract class CorrectionProducer {
5353

5454
TypeProvider get typeProvider => _context.typeProvider;
5555

56+
CompilationUnit get unit => _context.unit;
57+
5658
CorrectionUtils get utils => _context.utils;
5759

5860
Future<void> compute(DartChangeBuilder builder);
@@ -94,6 +96,7 @@ class CorrectionProducerContext {
9496
final int selectionLength;
9597
final int selectionEnd;
9698

99+
final CompilationUnit unit;
97100
final CorrectionUtils utils;
98101
final String file;
99102

@@ -118,6 +121,7 @@ class CorrectionProducerContext {
118121
sessionHelper = AnalysisSessionHelper(resolvedResult.session),
119122
typeProvider = resolvedResult.typeProvider,
120123
selectionEnd = (selectionOffset ?? 0) + (selectionLength ?? 0),
124+
unit = resolvedResult.unit,
121125
utils = CorrectionUtils(resolvedResult);
122126

123127
AstNode get node => _node;
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Copyright (c) 2020, 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/dart/abstract_producer.dart';
6+
import 'package:analysis_server/src/services/correction/fix.dart';
7+
import 'package:analyzer/dart/ast/ast.dart';
8+
import 'package:analyzer/dart/ast/visitor.dart';
9+
import 'package:analyzer/dart/element/element.dart';
10+
import 'package:analyzer/source/source_range.dart';
11+
import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
12+
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
13+
import 'package:analyzer_plugin/utilities/range_factory.dart';
14+
15+
class RemoveUnusedElement extends _RemoveUnused {
16+
@override
17+
FixKind get fixKind => DartFixKind.REMOVE_UNUSED_ELEMENT;
18+
19+
@override
20+
Future<void> compute(DartChangeBuilder builder) async {
21+
final sourceRanges = <SourceRange>[];
22+
final referencedNode = node.parent;
23+
if (referencedNode is ClassDeclaration ||
24+
referencedNode is EnumDeclaration ||
25+
referencedNode is FunctionDeclaration ||
26+
referencedNode is FunctionTypeAlias ||
27+
referencedNode is MethodDeclaration ||
28+
referencedNode is VariableDeclaration) {
29+
final element = referencedNode is Declaration
30+
? referencedNode.declaredElement
31+
: (referencedNode as NamedCompilationUnitMember).declaredElement;
32+
final references = _findAllReferences(unit, element);
33+
// todo (pq): consider filtering for references that are limited to within the class.
34+
if (references.length == 1) {
35+
var sourceRange;
36+
if (referencedNode is VariableDeclaration) {
37+
VariableDeclarationList parent = referencedNode.parent;
38+
if (parent.variables.length == 1) {
39+
sourceRange = utils.getLinesRange(range.node(parent.parent));
40+
} else {
41+
sourceRange = range.nodeInList(parent.variables, referencedNode);
42+
}
43+
} else {
44+
sourceRange = utils.getLinesRange(range.node(referencedNode));
45+
}
46+
sourceRanges.add(sourceRange);
47+
}
48+
}
49+
50+
await builder.addFileEdit(file, (builder) {
51+
for (var sourceRange in sourceRanges) {
52+
builder.addDeletion(sourceRange);
53+
}
54+
});
55+
}
56+
}
57+
58+
class RemoveUnusedField extends _RemoveUnused {
59+
@override
60+
FixKind get fixKind => DartFixKind.REMOVE_UNUSED_FIELD;
61+
62+
@override
63+
Future<void> compute(DartChangeBuilder builder) async {
64+
final declaration = node.parent;
65+
if (declaration is! VariableDeclaration) {
66+
return;
67+
}
68+
final element = (declaration as VariableDeclaration).declaredElement;
69+
if (element is! FieldElement) {
70+
return;
71+
}
72+
73+
final sourceRanges = <SourceRange>[];
74+
final references = _findAllReferences(unit, element);
75+
for (var reference in references) {
76+
// todo (pq): consider scoping this to parent or parent.parent.
77+
final referenceNode = reference.thisOrAncestorMatching((node) =>
78+
node is VariableDeclaration ||
79+
node is ExpressionStatement ||
80+
node is ConstructorFieldInitializer ||
81+
node is FieldFormalParameter);
82+
if (referenceNode == null) {
83+
return;
84+
}
85+
var sourceRange;
86+
if (referenceNode is VariableDeclaration) {
87+
VariableDeclarationList parent = referenceNode.parent;
88+
if (parent.variables.length == 1) {
89+
sourceRange = utils.getLinesRange(range.node(parent.parent));
90+
} else {
91+
sourceRange = range.nodeInList(parent.variables, referenceNode);
92+
}
93+
} else if (referenceNode is ConstructorFieldInitializer) {
94+
ConstructorDeclaration cons =
95+
referenceNode.parent as ConstructorDeclaration;
96+
// A() : _f = 0;
97+
if (cons.initializers.length == 1) {
98+
sourceRange = range.endEnd(cons.parameters, referenceNode);
99+
} else {
100+
sourceRange = range.nodeInList(cons.initializers, referenceNode);
101+
}
102+
} else if (referenceNode is FieldFormalParameter) {
103+
FormalParameterList params =
104+
referenceNode.parent as FormalParameterList;
105+
if (params.parameters.length == 1) {
106+
sourceRange =
107+
range.endStart(params.leftParenthesis, params.rightParenthesis);
108+
} else {
109+
sourceRange = range.nodeInList(params.parameters, referenceNode);
110+
}
111+
} else {
112+
sourceRange = utils.getLinesRange(range.node(referenceNode));
113+
}
114+
sourceRanges.add(sourceRange);
115+
}
116+
117+
await builder.addFileEdit(file, (builder) {
118+
for (var sourceRange in sourceRanges) {
119+
builder.addDeletion(sourceRange);
120+
}
121+
});
122+
}
123+
}
124+
125+
class _ElementReferenceCollector extends RecursiveAstVisitor<void> {
126+
final Element element;
127+
final List<SimpleIdentifier> references = [];
128+
129+
_ElementReferenceCollector(this.element);
130+
131+
@override
132+
void visitSimpleIdentifier(SimpleIdentifier node) {
133+
final staticElement = node.staticElement;
134+
if (staticElement == element) {
135+
references.add(node);
136+
} else if (staticElement is PropertyAccessorElement) {
137+
if (staticElement.variable == element) {
138+
references.add(node);
139+
}
140+
} else if (staticElement is FieldFormalParameterElement) {
141+
if (staticElement.field == element) {
142+
references.add(node);
143+
}
144+
}
145+
}
146+
}
147+
148+
abstract class _RemoveUnused extends CorrectionProducer {
149+
List<SimpleIdentifier> _findAllReferences(AstNode root, Element element) {
150+
var collector = _ElementReferenceCollector(element);
151+
root.accept(collector);
152+
return collector.references;
153+
}
154+
}

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

Lines changed: 6 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import 'package:analysis_server/src/services/correction/dart/convert_to_where_ty
2121
import 'package:analysis_server/src/services/correction/dart/inline_typedef.dart';
2222
import 'package:analysis_server/src/services/correction/dart/remove_dead_if_null.dart';
2323
import 'package:analysis_server/src/services/correction/dart/remove_if_null_operator.dart';
24+
import 'package:analysis_server/src/services/correction/dart/remove_unused.dart';
2425
import 'package:analysis_server/src/services/correction/dart/replace_with_eight_digit_hex.dart';
2526
import 'package:analysis_server/src/services/correction/dart/wrap_in_future.dart';
2627
import 'package:analysis_server/src/services/correction/fix.dart';
@@ -35,7 +36,6 @@ import 'package:analyzer/dart/analysis/features.dart';
3536
import 'package:analyzer/dart/ast/ast.dart';
3637
import 'package:analyzer/dart/ast/precedence.dart';
3738
import 'package:analyzer/dart/ast/token.dart';
38-
import 'package:analyzer/dart/ast/visitor.dart';
3939
import 'package:analyzer/dart/element/element.dart';
4040
import 'package:analyzer/dart/element/nullability_suffix.dart';
4141
import 'package:analyzer/dart/element/type.dart';
@@ -374,12 +374,6 @@ class FixProcessor extends BaseProcessor {
374374
if (errorCode == HintCode.UNUSED_CATCH_STACK) {
375375
await _addFix_removeUnusedCatchStack();
376376
}
377-
if (errorCode == HintCode.UNUSED_ELEMENT) {
378-
await _addFix_removeUnusedElement();
379-
}
380-
if (errorCode == HintCode.UNUSED_FIELD) {
381-
await _addFix_removeUnusedField();
382-
}
383377
if (errorCode == HintCode.UNUSED_IMPORT) {
384378
await _addFix_removeUnusedImport();
385379
}
@@ -3752,110 +3746,6 @@ class FixProcessor extends BaseProcessor {
37523746
}
37533747
}
37543748

3755-
Future<void> _addFix_removeUnusedElement() async {
3756-
final sourceRanges = <SourceRange>[];
3757-
final referencedNode = node.parent;
3758-
if (referencedNode is ClassDeclaration ||
3759-
referencedNode is EnumDeclaration ||
3760-
referencedNode is FunctionDeclaration ||
3761-
referencedNode is FunctionTypeAlias ||
3762-
referencedNode is MethodDeclaration ||
3763-
referencedNode is VariableDeclaration) {
3764-
final element = referencedNode is Declaration
3765-
? referencedNode.declaredElement
3766-
: (referencedNode as NamedCompilationUnitMember).declaredElement;
3767-
final references = _findAllReferences(unit, element);
3768-
// todo (pq): consider filtering for references that are limited to within the class.
3769-
if (references.length == 1) {
3770-
var sourceRange;
3771-
if (referencedNode is VariableDeclaration) {
3772-
VariableDeclarationList parent = referencedNode.parent;
3773-
if (parent.variables.length == 1) {
3774-
sourceRange = utils.getLinesRange(range.node(parent.parent));
3775-
} else {
3776-
sourceRange = range.nodeInList(parent.variables, referencedNode);
3777-
}
3778-
} else {
3779-
sourceRange = utils.getLinesRange(range.node(referencedNode));
3780-
}
3781-
sourceRanges.add(sourceRange);
3782-
}
3783-
}
3784-
3785-
if (sourceRanges.isNotEmpty) {
3786-
final changeBuilder = _newDartChangeBuilder();
3787-
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
3788-
for (var sourceRange in sourceRanges) {
3789-
builder.addDeletion(sourceRange);
3790-
}
3791-
});
3792-
_addFixFromBuilder(changeBuilder, DartFixKind.REMOVE_UNUSED_ELEMENT);
3793-
}
3794-
}
3795-
3796-
Future<void> _addFix_removeUnusedField() async {
3797-
final declaration = node.parent;
3798-
if (declaration is! VariableDeclaration) {
3799-
return;
3800-
}
3801-
final element = (declaration as VariableDeclaration).declaredElement;
3802-
if (element is! FieldElement) {
3803-
return;
3804-
}
3805-
3806-
final sourceRanges = <SourceRange>[];
3807-
final references = _findAllReferences(unit, element);
3808-
for (var reference in references) {
3809-
// todo (pq): consider scoping this to parent or parent.parent.
3810-
final referenceNode = reference.thisOrAncestorMatching((node) =>
3811-
node is VariableDeclaration ||
3812-
node is ExpressionStatement ||
3813-
node is ConstructorFieldInitializer ||
3814-
node is FieldFormalParameter);
3815-
if (referenceNode == null) {
3816-
return;
3817-
}
3818-
var sourceRange;
3819-
if (referenceNode is VariableDeclaration) {
3820-
VariableDeclarationList parent = referenceNode.parent;
3821-
if (parent.variables.length == 1) {
3822-
sourceRange = utils.getLinesRange(range.node(parent.parent));
3823-
} else {
3824-
sourceRange = range.nodeInList(parent.variables, referenceNode);
3825-
}
3826-
} else if (referenceNode is ConstructorFieldInitializer) {
3827-
ConstructorDeclaration cons =
3828-
referenceNode.parent as ConstructorDeclaration;
3829-
// A() : _f = 0;
3830-
if (cons.initializers.length == 1) {
3831-
sourceRange = range.endEnd(cons.parameters, referenceNode);
3832-
} else {
3833-
sourceRange = range.nodeInList(cons.initializers, referenceNode);
3834-
}
3835-
} else if (referenceNode is FieldFormalParameter) {
3836-
FormalParameterList params =
3837-
referenceNode.parent as FormalParameterList;
3838-
if (params.parameters.length == 1) {
3839-
sourceRange =
3840-
range.endStart(params.leftParenthesis, params.rightParenthesis);
3841-
} else {
3842-
sourceRange = range.nodeInList(params.parameters, referenceNode);
3843-
}
3844-
} else {
3845-
sourceRange = utils.getLinesRange(range.node(referenceNode));
3846-
}
3847-
sourceRanges.add(sourceRange);
3848-
}
3849-
3850-
final changeBuilder = _newDartChangeBuilder();
3851-
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
3852-
for (var sourceRange in sourceRanges) {
3853-
builder.addDeletion(sourceRange);
3854-
}
3855-
});
3856-
_addFixFromBuilder(changeBuilder, DartFixKind.REMOVE_UNUSED_FIELD);
3857-
}
3858-
38593749
Future<void> _addFix_removeUnusedImport() async {
38603750
// prepare ImportDirective
38613751
ImportDirective importDirective =
@@ -4714,7 +4604,11 @@ class FixProcessor extends BaseProcessor {
47144604
}
47154605

47164606
var errorCode = error.errorCode;
4717-
if (errorCode == StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION) {
4607+
if (errorCode == HintCode.UNUSED_ELEMENT) {
4608+
await compute(RemoveUnusedElement());
4609+
} else if (errorCode == HintCode.UNUSED_FIELD) {
4610+
await compute(RemoveUnusedField());
4611+
} else if (errorCode == StaticWarningCode.DEAD_NULL_AWARE_EXPRESSION) {
47184612
await compute(RemoveDeadIfNull());
47194613
} else if (errorCode is LintCode) {
47204614
String name = errorCode.name;
@@ -4844,12 +4738,6 @@ class FixProcessor extends BaseProcessor {
48444738
_addFixFromBuilder(changeBuilder, DartFixKind.CREATE_METHOD, args: [name]);
48454739
}
48464740

4847-
List<SimpleIdentifier> _findAllReferences(AstNode root, Element element) {
4848-
var collector = _ElementReferenceCollector(element);
4849-
root.accept(collector);
4850-
return collector.references;
4851-
}
4852-
48534741
/// Return the class, enum or mixin declaration for the given [element].
48544742
Future<ClassOrMixinDeclaration> _getClassDeclaration(
48554743
ClassElement element) async {
@@ -5235,32 +5123,6 @@ class _ClosestElementFinder {
52355123
}
52365124
}
52375125

5238-
class _ElementReferenceCollector extends RecursiveAstVisitor<void> {
5239-
final Element element;
5240-
final List<SimpleIdentifier> references = [];
5241-
5242-
_ElementReferenceCollector(this.element);
5243-
5244-
@override
5245-
void visitSimpleIdentifier(SimpleIdentifier node) {
5246-
final staticElement = node.staticElement;
5247-
if (staticElement == element) {
5248-
references.add(node);
5249-
}
5250-
// Implicit Setter.
5251-
else if (staticElement is PropertyAccessorElement) {
5252-
if (staticElement.variable == element) {
5253-
references.add(node);
5254-
}
5255-
// Field Formals.
5256-
} else if (staticElement is FieldFormalParameterElement) {
5257-
if (staticElement.field == element) {
5258-
references.add(node);
5259-
}
5260-
}
5261-
}
5262-
}
5263-
52645126
/// [ExecutableElement], its parameters, and operations on them.
52655127
class _ExecutableParameters {
52665128
final AnalysisSessionHelper sessionHelper;

0 commit comments

Comments
 (0)