Skip to content

Commit b03e7c7

Browse files
srawlinsCommit Queue
authored andcommitted
DAS: add_null_check - Rearrange code to promote variables better
The motivation here was to remove the local duplicate variable, `target_final`. This variable only existed because the variable it duplicates, `target`, loses its promoted type inside the `builder.addDartFileEdit` closure. It loses it's promoted type because it is assigned late. This CL extracts the first ~60 lines of the `compute()` method, which is solely concerned with computing the real "target". The diff looks large because of how the first ~60 lines of `compute()` 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 170-line long method into one helper, and avoiding a local duplicate variable. Change-Id: I20e2eb3479f53810d4dfcab9b88ebacb446e0f62 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/416884 Commit-Queue: Samuel Rawlins <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent d3adf41 commit b03e7c7

File tree

1 file changed

+68
-63
lines changed

1 file changed

+68
-63
lines changed

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

Lines changed: 68 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -42,67 +42,11 @@ class AddNullCheck extends ResolvedCorrectionProducer {
4242

4343
@override
4444
Future<void> compute(ChangeBuilder builder) async {
45-
Expression? target;
46-
var coveringNode = this.coveringNode;
47-
var coveringNodeParent = coveringNode?.parent;
48-
4945
if (await _isNullAware(builder, coveringNode)) {
5046
return;
5147
}
5248

53-
if (coveringNode is SimpleIdentifier) {
54-
if (coveringNodeParent is MethodInvocation) {
55-
target = coveringNodeParent.realTarget;
56-
} else if (coveringNodeParent is PrefixedIdentifier) {
57-
target = coveringNodeParent.prefix;
58-
} else if (coveringNodeParent is PropertyAccess) {
59-
target = coveringNodeParent.realTarget;
60-
} else if (coveringNodeParent is CascadeExpression &&
61-
await _isNullAware(
62-
builder,
63-
coveringNodeParent.cascadeSections.first,
64-
)) {
65-
return;
66-
} else {
67-
target = coveringNode;
68-
}
69-
} else if (coveringNode is IndexExpression) {
70-
target = coveringNode.realTarget;
71-
if (target.staticType?.nullabilitySuffix != NullabilitySuffix.question) {
72-
target = coveringNode;
73-
}
74-
} else if (coveringNode is Expression &&
75-
coveringNodeParent is FunctionExpressionInvocation) {
76-
target = coveringNode;
77-
} else if (coveringNodeParent is AssignmentExpression) {
78-
target = coveringNodeParent.rightHandSide;
79-
} else if (coveringNode is PostfixExpression) {
80-
target = coveringNode.operand;
81-
} else if (coveringNode is PrefixExpression) {
82-
target = coveringNode.operand;
83-
} else if (coveringNode is BinaryExpression) {
84-
if (coveringNode.operator.type != TokenType.QUESTION_QUESTION) {
85-
target = coveringNode.leftOperand;
86-
} else {
87-
var expectedType = coveringNode.correspondingParameter?.type;
88-
if (expectedType == null) return;
89-
90-
var leftType = coveringNode.leftOperand.staticType;
91-
var leftAssignable =
92-
leftType != null &&
93-
typeSystem.isAssignableTo(
94-
typeSystem.promoteToNonNull(leftType),
95-
expectedType,
96-
strictCasts: analysisOptions.strictCasts,
97-
);
98-
if (leftAssignable) {
99-
target = coveringNode.rightOperand;
100-
}
101-
}
102-
} else if (coveringNode is AsExpression) {
103-
target = coveringNode.expression;
104-
}
105-
49+
var target = await _computeTarget(builder);
10650
if (target == null) {
10751
return;
10852
}
@@ -199,13 +143,12 @@ class AddNullCheck extends ResolvedCorrectionProducer {
199143
return;
200144
}
201145

202-
var target_final = target;
203146
var needsParentheses = target.precedence < Precedence.postfix;
204147
await builder.addDartFileEdit(file, (builder) {
205148
if (needsParentheses) {
206-
builder.addSimpleInsertion(target_final.offset, '(');
149+
builder.addSimpleInsertion(target.offset, '(');
207150
}
208-
builder.addInsertion(target_final.end, (builder) {
151+
builder.addInsertion(target.end, (builder) {
209152
if (needsParentheses) {
210153
builder.write(')');
211154
}
@@ -214,8 +157,70 @@ class AddNullCheck extends ResolvedCorrectionProducer {
214157
});
215158
}
216159

217-
/// Return `true` if the specified [node] or one of its parents `isNullAware`,
218-
/// in which case [_replaceWithNullCheck] would also be called.
160+
/// Computes the target for which we need to add a null check.
161+
Future<Expression?> _computeTarget(ChangeBuilder builder) async {
162+
var coveringNode = this.coveringNode;
163+
var coveringNodeParent = coveringNode?.parent;
164+
165+
if (coveringNode is SimpleIdentifier) {
166+
if (coveringNodeParent is MethodInvocation) {
167+
return coveringNodeParent.realTarget;
168+
} else if (coveringNodeParent is PrefixedIdentifier) {
169+
return coveringNodeParent.prefix;
170+
} else if (coveringNodeParent is PropertyAccess) {
171+
return coveringNodeParent.realTarget;
172+
} else if (coveringNodeParent is CascadeExpression &&
173+
await _isNullAware(
174+
builder,
175+
coveringNodeParent.cascadeSections.first,
176+
)) {
177+
return null;
178+
} else {
179+
return coveringNode;
180+
}
181+
} else if (coveringNode is IndexExpression) {
182+
var target = coveringNode.realTarget;
183+
if (target.staticType?.nullabilitySuffix != NullabilitySuffix.question) {
184+
target = coveringNode;
185+
}
186+
return target;
187+
} else if (coveringNode is Expression &&
188+
coveringNodeParent is FunctionExpressionInvocation) {
189+
return coveringNode;
190+
} else if (coveringNodeParent is AssignmentExpression) {
191+
return coveringNodeParent.rightHandSide;
192+
} else if (coveringNode is PostfixExpression) {
193+
return coveringNode.operand;
194+
} else if (coveringNode is PrefixExpression) {
195+
return coveringNode.operand;
196+
} else if (coveringNode is BinaryExpression) {
197+
if (coveringNode.operator.type != TokenType.QUESTION_QUESTION) {
198+
return coveringNode.leftOperand;
199+
} else {
200+
var expectedType = coveringNode.correspondingParameter?.type;
201+
if (expectedType == null) return null;
202+
203+
var leftType = coveringNode.leftOperand.staticType;
204+
var leftAssignable =
205+
leftType != null &&
206+
typeSystem.isAssignableTo(
207+
typeSystem.promoteToNonNull(leftType),
208+
expectedType,
209+
strictCasts: analysisOptions.strictCasts,
210+
);
211+
if (leftAssignable) {
212+
return coveringNode.rightOperand;
213+
}
214+
}
215+
} else if (coveringNode is AsExpression) {
216+
return coveringNode.expression;
217+
}
218+
return null;
219+
}
220+
221+
/// Returns whether the specified [node] or, in some cases, a certain child
222+
/// node is null-aware, in which case the null-aware operator is replaced with
223+
/// a null check operator.
219224
Future<bool> _isNullAware(ChangeBuilder builder, AstNode? node) async {
220225
if (node is PropertyAccess) {
221226
if (node.isNullAware) {
@@ -241,7 +246,7 @@ class AddNullCheck extends ResolvedCorrectionProducer {
241246
return false;
242247
}
243248

244-
/// Replaces the null aware [token] with the null check operator.
249+
/// Replaces the null-aware [token] with the null check operator.
245250
Future<void> _replaceWithNullCheck(ChangeBuilder builder, Token token) async {
246251
fixKind = DartFixKind.REPLACE_WITH_NULL_AWARE;
247252
var lexeme = token.lexeme;

0 commit comments

Comments
 (0)