Skip to content

Commit b3e725c

Browse files
srawlinsCommit Queue
authored andcommitted
DAS: Rearrange code to promote variables better
The motivation here was to remove the local duplicate variable, `node_final`. This variable only existed because the variable it duplicates loses its promoted type inside the `builder.addDartFileEdit` closure. It lose its promoted type because they are multiply assigned in a while loop. This CL extracts the first portion of the `compute()` method, which is solely concerned with computing the real "target". The diff looks large because of how that portion is moved into a helper method that is _below_ the second half of `compute()`. I think each of these changes then improves readability: extracting part of a 140-line long method into one helper, and avoiding a local duplicate variable. Change-Id: Ic209e4be49863657f969eadf909ab05d13e9a254 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417680 Reviewed-by: Phil Quitslund <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent 90c0aa6 commit b3e725c

File tree

1 file changed

+86
-73
lines changed

1 file changed

+86
-73
lines changed

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

Lines changed: 86 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:analyzer/dart/ast/token.dart';
1010
import 'package:analyzer/dart/ast/visitor.dart';
1111
import 'package:analyzer/source/source_range.dart';
1212
import 'package:analyzer/src/lint/constants.dart';
13+
import 'package:analyzer_plugin/protocol/protocol_common.dart';
1314
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
1415
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
1516
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
@@ -31,35 +32,27 @@ class AddConst extends ResolvedCorrectionProducer {
3132

3233
@override
3334
Future<void> compute(ChangeBuilder builder) async {
34-
AstNode? targetNode = node;
35-
if (targetNode is SimpleIdentifier) {
36-
targetNode = targetNode.parent;
35+
var targetNode = _computeTargetNode();
36+
if (targetNode == null) {
37+
return;
3738
}
39+
3840
if (targetNode is ConstructorDeclaration) {
39-
var node_final = targetNode;
41+
var offset = targetNode.firstTokenAfterCommentAndMetadata.offset;
4042
await builder.addDartFileEdit(file, (builder) {
41-
var offset = node_final.firstTokenAfterCommentAndMetadata.offset;
4243
builder.addSimpleInsertion(offset, 'const ');
4344
});
4445
return;
4546
}
4647

47-
Future<void> addParensAndConst(AstNode node_final) async {
48-
var offset = node_final.offset;
48+
Future<void> addParensAndConst(AstNode parent) async {
49+
var offset = parent.offset;
4950
await builder.addDartFileEdit(file, (builder) {
50-
builder.addSimpleInsertion(offset + node_final.length, ')');
51+
builder.addSimpleInsertion(offset + parent.length, ')');
5152
builder.addSimpleInsertion(offset, 'const (');
5253
});
5354
}
5455

55-
if (targetNode is TypeArgumentList) {
56-
while (targetNode is! CompilationUnit && targetNode is! ConstantPattern) {
57-
targetNode = targetNode?.parent;
58-
}
59-
}
60-
if (targetNode is CompilationUnit) {
61-
return;
62-
}
6356
if (targetNode is ConstantPattern) {
6457
var expression = targetNode.expression;
6558
var canBeConst = expression.canBeConst;
@@ -69,83 +62,40 @@ class AddConst extends ResolvedCorrectionProducer {
6962
builder.addSimpleInsertion(offset, 'const ');
7063
});
7164
} else if (expression is TypeLiteral) {
72-
var node_final = targetNode.parent;
73-
if (node_final is ParenthesizedPattern) {
65+
var parent = targetNode.parent!;
66+
if (parent is ParenthesizedPattern) {
7467
await builder.addDartFileEdit(file, (builder) {
75-
builder.addSimpleInsertion(node_final.offset, 'const ');
68+
builder.addSimpleInsertion(parent.offset, 'const ');
7669
});
7770
} else {
78-
await addParensAndConst(node_final!);
71+
await addParensAndConst(parent);
7972
}
8073
}
8174
return;
8275
}
83-
if (targetNode is BinaryExpression || targetNode is PrefixExpression) {
84-
var node_final = targetNode?.parent;
85-
if (node_final?.parent is ParenthesizedPattern) {
86-
// add const
87-
var offset = node_final!.parent!.offset;
76+
if (targetNode case BinaryExpression() || PrefixExpression()) {
77+
var parent = targetNode.parent!;
78+
if (parent.parent is ParenthesizedPattern) {
79+
// Add `const`.
80+
var offset = parent.parent!.offset;
8881
await builder.addDartFileEdit(file, (builder) {
8982
builder.addSimpleInsertion(offset, 'const ');
9083
});
9184
} else {
92-
// add const and parenthesis
93-
await addParensAndConst(node_final!);
85+
// Add `const` and parentheses.
86+
await addParensAndConst(parent);
9487
}
9588
return;
9689
}
9790

98-
bool isParentConstant(
99-
DartFileEditBuilderImpl builder,
100-
Expression targetNode,
101-
) {
102-
var edits = builder.fileEdit.edits;
103-
var child = targetNode.parent;
104-
while (child is Expression ||
105-
child is ArgumentList ||
106-
child is VariableDeclaration ||
107-
child is VariableDeclarationList) {
108-
if (edits.any(
109-
(element) =>
110-
element.replacement.startsWith('const') &&
111-
element.offset == child!.offset,
112-
)) {
113-
return true;
114-
}
115-
child = child!.parent;
116-
}
117-
return false;
118-
}
119-
120-
Future<void> insertAtOffset(Expression targetNode) async {
121-
var finder = _ConstRangeFinder();
122-
targetNode.accept(finder);
123-
await builder.addDartFileEdit(file, (builder) {
124-
if (builder is DartFileEditBuilderImpl &&
125-
isParentConstant(builder, targetNode)) {
126-
return;
127-
}
128-
builder.addSimpleInsertion(targetNode.offset, 'const ');
129-
for (var range in finder.ranges) {
130-
builder.addDeletion(range);
131-
}
132-
});
133-
}
134-
13591
if (targetNode is ListLiteral) {
136-
await insertAtOffset(targetNode);
92+
await _insertBeforeNode(builder, targetNode);
13793
return;
13894
}
13995
if (targetNode is SetOrMapLiteral) {
140-
await insertAtOffset(targetNode);
96+
await _insertBeforeNode(builder, targetNode);
14197
return;
14298
}
143-
if (targetNode is NamedType) {
144-
targetNode = targetNode.parent;
145-
}
146-
if (targetNode is ConstructorName) {
147-
targetNode = targetNode.parent;
148-
}
14999
if (targetNode case InstanceCreationExpression(:var parent, :var keyword)) {
150100
var constDeclarations =
151101
getCodeStyleOptions(unitResult.file).preferConstDeclarations;
@@ -162,12 +112,35 @@ class AddConst extends ResolvedCorrectionProducer {
162112
}
163113
}
164114
if (keyword == null) {
165-
await insertAtOffset(targetNode);
115+
await _insertBeforeNode(builder, targetNode);
166116
return;
167117
}
168118
}
169119
}
170120

121+
/// Computes the node which this correction should treat as the target.
122+
AstNode? _computeTargetNode() {
123+
AstNode? targetNode = node;
124+
if (targetNode is SimpleIdentifier) {
125+
targetNode = targetNode.parent;
126+
}
127+
if (targetNode is TypeArgumentList) {
128+
while (targetNode is! CompilationUnit && targetNode is! ConstantPattern) {
129+
targetNode = targetNode?.parent;
130+
}
131+
}
132+
if (targetNode is CompilationUnit) {
133+
return null;
134+
}
135+
if (targetNode is NamedType) {
136+
targetNode = targetNode.parent;
137+
}
138+
if (targetNode is ConstructorName) {
139+
targetNode = targetNode.parent;
140+
}
141+
return targetNode;
142+
}
143+
171144
/// Considers if the given [variables] to be declared with `const` if all of
172145
/// them are contained in the list of errors that suggest using `const` (
173146
/// `prefer_const_constructors` triggers).
@@ -218,6 +191,46 @@ class AddConst extends ResolvedCorrectionProducer {
218191
// If each of the variable ranges is contained in the list of error ranges.
219192
return variablesRanges.every(errorsRanges.contains);
220193
}
194+
195+
/// Inserts `const ` before [targetNode].
196+
Future<void> _insertBeforeNode(
197+
ChangeBuilder builder,
198+
Expression targetNode,
199+
) async {
200+
var finder = _ConstRangeFinder();
201+
targetNode.accept(finder);
202+
await builder.addDartFileEdit(file, (builder) {
203+
if (builder is DartFileEditBuilderImpl &&
204+
_isAncestorConstant(builder.fileEdit.edits, targetNode)) {
205+
return;
206+
}
207+
builder.addSimpleInsertion(targetNode.offset, 'const ');
208+
for (var range in finder.ranges) {
209+
builder.addDeletion(range);
210+
}
211+
});
212+
}
213+
214+
/// Returns whether any [edits] start with 'const' and have the same offset as
215+
/// one of [targetNode]s ancestors.
216+
bool _isAncestorConstant(List<SourceEdit> edits, Expression targetNode) {
217+
var child = targetNode.parent;
218+
var editsWhichStartWithConst =
219+
edits.where((e) => e.replacement.startsWith('const')).toList();
220+
if (editsWhichStartWithConst.isEmpty) {
221+
return false;
222+
}
223+
while (child is Expression ||
224+
child is ArgumentList ||
225+
child is VariableDeclaration ||
226+
child is VariableDeclarationList) {
227+
if (editsWhichStartWithConst.any((e) => e.offset == child!.offset)) {
228+
return true;
229+
}
230+
child = child!.parent;
231+
}
232+
return false;
233+
}
221234
}
222235

223236
class _ConstRangeFinder extends RecursiveAstVisitor<void> {

0 commit comments

Comments
 (0)