analyzer: visit local variables in resolution more safely
I'm preparing for the situation where an expression of (almost) any kind
could be wrapped with a generic function instantiation, and I was very
worried that there were a lot of cases like this:
var localVariable = node.childNode;
localVariable.accept(_resolver);
// Do more with localVariable.
This is dangerous because localVariable may no longer be the same node
as `node.childNode`. I searched eerywhere I could for dangerous cases
like this. In some cases, I follow the middle statement with
`localVariable = node.childNode`, which is a common practice. In other
cases, the local variable was only referenced 2 or 3 times, and was
unnecessary. In other cases, I saw that the node strictly referred to
statements or other types of nodes, like a CatchClause. I am
reassured though that there really wasn't too much code like this.
I'd love to figure out how to enforce this statically, but haven't
found a good solution.
Change-Id: If38124dc2036b6f04879a065d66bf3ea73e68977
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/218184
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 202769a..8b33178 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1224,21 +1224,20 @@
boolExpressionVerifier.checkForNonBoolCondition(condition,
whyNotPromoted: whyNotPromoted);
- Expression thenExpression = node.thenExpression;
- InferenceContext.setTypeFromNode(thenExpression, node);
+ InferenceContext.setTypeFromNode(node.thenExpression, node);
if (flow != null) {
flow.conditional_thenBegin(condition, node);
- checkUnreachableNode(thenExpression);
+ checkUnreachableNode(node.thenExpression);
}
- thenExpression.accept(this);
- nullSafetyDeadCodeVerifier.flowEnd(thenExpression);
+ node.thenExpression.accept(this);
+ nullSafetyDeadCodeVerifier.flowEnd(node.thenExpression);
Expression elseExpression = node.elseExpression;
InferenceContext.setTypeFromNode(elseExpression, node);
if (flow != null) {
- flow.conditional_elseBegin(thenExpression);
+ flow.conditional_elseBegin(node.thenExpression);
checkUnreachableNode(elseExpression);
elseExpression.accept(this);
flow.conditional_end(node, elseExpression);
@@ -1246,6 +1245,7 @@
} else {
elseExpression.accept(this);
}
+ elseExpression = node.elseExpression;
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -1300,6 +1300,7 @@
var expression = node.expression;
InferenceContext.setType(expression, fieldType);
expression.accept(this);
+ expression = node.expression;
var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(expression);
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -1356,11 +1357,10 @@
void visitDoStatement(DoStatement node) {
checkUnreachableNode(node);
- var body = node.body;
var condition = node.condition;
flowAnalysis.flow?.doStatement_bodyBegin(node);
- body.accept(this);
+ node.body.accept(this);
flowAnalysis.flow?.doStatement_conditionBegin();
InferenceContext.setType(condition, typeProvider.boolType);
@@ -1599,10 +1599,9 @@
boolExpressionVerifier.checkForNonBoolCondition(condition,
whyNotPromoted: whyNotPromoted);
- CollectionElement thenElement = node.thenElement;
flowAnalysis.flow?.ifStatement_thenBegin(condition, node);
- thenElement.accept(this);
- nullSafetyDeadCodeVerifier.flowEnd(thenElement);
+ node.thenElement.accept(this);
+ nullSafetyDeadCodeVerifier.flowEnd(node.thenElement);
var elseElement = node.elseElement;
if (elseElement != null) {
@@ -1632,10 +1631,9 @@
boolExpressionVerifier.checkForNonBoolCondition(condition,
whyNotPromoted: whyNotPromoted);
- Statement thenStatement = node.thenStatement;
flowAnalysis.flow?.ifStatement_thenBegin(condition, node);
- thenStatement.accept(this);
- nullSafetyDeadCodeVerifier.flowEnd(thenStatement);
+ node.thenStatement.accept(this);
+ nullSafetyDeadCodeVerifier.flowEnd(node.thenStatement);
var elseStatement = node.elseStatement;
if (elseStatement != null) {
@@ -1760,6 +1758,7 @@
var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
var target = node.target;
target?.accept(this);
+ target = node.target;
if (_migratableAstInfoProvider.isMethodInvocationNullAware(node)) {
var flow = flowAnalysis.flow;
@@ -2141,9 +2140,8 @@
boolExpressionVerifier.checkForNonBoolCondition(node.condition,
whyNotPromoted: whyNotPromoted);
- Statement body = node.body;
flowAnalysis.flow?.whileStatement_bodyBegin(node, condition);
- body.accept(this);
+ node.body.accept(this);
flowAnalysis.flow?.whileStatement_end();
nullSafetyDeadCodeVerifier.flowEnd(node.body);
// TODO(brianwilkerson) If the loop can only be exited because the condition