Skip to content
This repository was archived by the owner on Nov 20, 2024. It is now read-only.

Commit 21ff58a

Browse files
authored
use_build_context_synchronously: more docs, extensions (#4248)
1 parent d55f100 commit 21ff58a

File tree

1 file changed

+47
-32
lines changed

1 file changed

+47
-32
lines changed

lib/src/rules/use_build_context_synchronously.dart

+47-32
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,12 @@ class _AwaitVisitor extends RecursiveAstVisitor {
9595
@override
9696
visitBlockFunctionBody(BlockFunctionBody node) {
9797
// Stop visiting if it's a function body block.
98-
// Awaits inside it shouldn't matter
98+
// Awaits inside it shouldn't matter.
9999
}
100100

101101
@override
102102
visitExpressionFunctionBody(ExpressionFunctionBody node) {
103-
// Stopping following the same logic as function body blocks
103+
// Stopping following the same logic as function body blocks.
104104
}
105105
}
106106

@@ -142,13 +142,15 @@ class _Visitor extends SimpleAstVisitor {
142142
}
143143

144144
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.
145147
bool checkStatements(AstNode child, NodeList<Statement> statements) {
146148
var index = statements.indexOf(child as Statement);
147149
for (var i = index - 1; i >= 0; i--) {
148150
var s = statements[i];
149151
if (isMountedCheck(s)) {
150152
return false;
151-
} else if (isAsync(s)) {
153+
} else if (s.isAsync) {
152154
rule.reportLint(node);
153155
return true;
154156
}
@@ -180,7 +182,7 @@ class _Visitor extends SimpleAstVisitor {
180182
}
181183
} else if (parent is IfStatement) {
182184
// 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) {
184186
rule.reportLint(node);
185187
}
186188

@@ -194,21 +196,6 @@ class _Visitor extends SimpleAstVisitor {
194196
}
195197
}
196198

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-
212199
bool isMountedCheck(Statement statement, {bool positiveCheck = false}) {
213200
// This is intentionally naive. Using a simple 'mounted' property check
214201
// as a signal plays nicely w/ unanticipated framework classes that provide
@@ -269,7 +256,7 @@ class _Visitor extends SimpleAstVisitor {
269256
return true;
270257
}
271258
var then = statement.thenStatement;
272-
return terminatesControl(then);
259+
return then.terminatesControl;
273260
}
274261
} else if (statement is TryStatement) {
275262
var statements = statement.finallyBlock?.statements;
@@ -286,15 +273,6 @@ class _Visitor extends SimpleAstVisitor {
286273
return false;
287274
}
288275

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-
298276
@override
299277
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
300278
if (accessesContext(node.argumentList)) {
@@ -335,10 +313,47 @@ extension on BinaryExpression {
335313
bool get isOr => operator.type == TokenType.BAR_BAR;
336314
}
337315

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+
}
340338
var visitor = _AwaitVisitor();
341-
condition.accept(visitor);
339+
accept(visitor);
342340
return visitor.hasAwait;
343341
}
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+
}
344359
}

0 commit comments

Comments
 (0)