@@ -95,12 +95,12 @@ class _AwaitVisitor extends RecursiveAstVisitor {
95
95
@override
96
96
visitBlockFunctionBody (BlockFunctionBody node) {
97
97
// Stop visiting if it's a function body block.
98
- // Awaits inside it shouldn't matter
98
+ // Awaits inside it shouldn't matter.
99
99
}
100
100
101
101
@override
102
102
visitExpressionFunctionBody (ExpressionFunctionBody node) {
103
- // Stopping following the same logic as function body blocks
103
+ // Stopping following the same logic as function body blocks.
104
104
}
105
105
}
106
106
@@ -142,13 +142,15 @@ class _Visitor extends SimpleAstVisitor {
142
142
}
143
143
144
144
void check (AstNode node) {
145
+ /// Checks each of the [statements] before [child] for a `mounted` check,
146
+ /// and returns whether it did not find one.
145
147
bool checkStatements (AstNode child, NodeList <Statement > statements) {
146
148
var index = statements.indexOf (child as Statement );
147
149
for (var i = index - 1 ; i >= 0 ; i-- ) {
148
150
var s = statements[i];
149
151
if (isMountedCheck (s)) {
150
152
return false ;
151
- } else if (isAsync (s) ) {
153
+ } else if (s.isAsync ) {
152
154
rule.reportLint (node);
153
155
return true ;
154
156
}
@@ -180,7 +182,7 @@ class _Visitor extends SimpleAstVisitor {
180
182
}
181
183
} else if (parent is IfStatement ) {
182
184
// Only check the actual statement(s), not the IF condition
183
- if (child is Statement && parent.hasAsyncInCondition ) {
185
+ if (child is Statement && parent.condition.hasAwait ) {
184
186
rule.reportLint (node);
185
187
}
186
188
@@ -194,21 +196,6 @@ class _Visitor extends SimpleAstVisitor {
194
196
}
195
197
}
196
198
197
- bool isAsync (Statement statement) {
198
- if (statement is IfStatement ) {
199
- if (statement.hasAsyncInCondition) return true ;
200
- if (terminatesControl (statement.thenStatement)) {
201
- var elseStatement = statement.elseStatement;
202
- if (elseStatement == null || terminatesControl (elseStatement)) {
203
- return false ;
204
- }
205
- }
206
- }
207
- var visitor = _AwaitVisitor ();
208
- statement.accept (visitor);
209
- return visitor.hasAwait;
210
- }
211
-
212
199
bool isMountedCheck (Statement statement, {bool positiveCheck = false }) {
213
200
// This is intentionally naive. Using a simple 'mounted' property check
214
201
// as a signal plays nicely w/ unanticipated framework classes that provide
@@ -269,7 +256,7 @@ class _Visitor extends SimpleAstVisitor {
269
256
return true ;
270
257
}
271
258
var then = statement.thenStatement;
272
- return terminatesControl ( then) ;
259
+ return then.terminatesControl ;
273
260
}
274
261
} else if (statement is TryStatement ) {
275
262
var statements = statement.finallyBlock? .statements;
@@ -286,15 +273,6 @@ class _Visitor extends SimpleAstVisitor {
286
273
return false ;
287
274
}
288
275
289
- bool terminatesControl (Statement statement) {
290
- if (statement is Block ) {
291
- return terminatesControl (statement.statements.last);
292
- }
293
- return statement is ReturnStatement ||
294
- statement is BreakStatement ||
295
- statement is ContinueStatement ;
296
- }
297
-
298
276
@override
299
277
void visitFunctionExpressionInvocation (FunctionExpressionInvocation node) {
300
278
if (accessesContext (node.argumentList)) {
@@ -335,10 +313,47 @@ extension on BinaryExpression {
335
313
bool get isOr => operator .type == TokenType .BAR_BAR ;
336
314
}
337
315
338
- extension on IfStatement {
339
- bool get hasAsyncInCondition {
316
+ extension on Expression {
317
+ /// Whether this has an [AwaitExpression] inside.
318
+ bool get hasAwait {
319
+ var visitor = _AwaitVisitor ();
320
+ accept (visitor);
321
+ return visitor.hasAwait;
322
+ }
323
+ }
324
+
325
+ extension on Statement {
326
+ /// Whether this statement has an [AwaitExpression] inside.
327
+ bool get isAsync {
328
+ var self = this ;
329
+ if (self is IfStatement ) {
330
+ if (self.condition.hasAwait) return true ;
331
+ if (self.thenStatement.terminatesControl) {
332
+ var elseStatement = self.elseStatement;
333
+ if (elseStatement == null || elseStatement.terminatesControl) {
334
+ return false ;
335
+ }
336
+ }
337
+ }
340
338
var visitor = _AwaitVisitor ();
341
- condition. accept (visitor);
339
+ accept (visitor);
342
340
return visitor.hasAwait;
343
341
}
342
+
343
+ /// Whether this statement terminates control, via a [BreakStatement] , a
344
+ /// [ContinueStatement] , or other definite exits, as determined by
345
+ /// [ExitDetector] .
346
+ bool get terminatesControl {
347
+ var self = this ;
348
+ if (self is Block ) {
349
+ return self.statements.last.terminatesControl;
350
+ }
351
+ // TODO(srawlins): Make ExitDetector 100% functional for our needs. The
352
+ // basic (only?) difference is that it doesn't consider a `break` statement
353
+ // to be exiting.
354
+ if (self is BreakStatement || self is ContinueStatement ) {
355
+ return true ;
356
+ }
357
+ return accept (ExitDetector ()) ?? false ;
358
+ }
344
359
}
0 commit comments