Skip to content
This repository was archived by the owner on Jul 16, 2023. It is now read-only.

feat: support context.mounted for use-setstate-synchronously #1164

Merged
merged 2 commits into from
Jan 28, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unreleased

* fix: export missing parts of public API.
* feat: support `context.mounted` for [`use-setstate-synchronously`](https://dcm.dev/docs/individuals/rules/flutter/use-setstate-synchronously).

## 5.5.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ MountedFact _extractMountedCheck(
bool permitAnd = true,
bool expandOr = false,
}) {
// ![this.]mounted
// ![this. || context.]mounted
if (node is PrefixExpression &&
node.operator.type == TokenType.BANG &&
_isIdentifier(_thisOr(node.operand), 'mounted')) {
_isIdentifier(_thisOrContextOr(node.operand), 'mounted')) {
return false.asFact();
}

// [this.]mounted
if (_isIdentifier(_thisOr(node), 'mounted')) {
// [this. || context.]mounted
if (_isIdentifier(_thisOrContextOr(node), 'mounted')) {
return true.asFact();
}

Expand Down Expand Up @@ -91,10 +91,17 @@ bool _isDivergent(Statement node, {bool allowControlFlow = false}) =>
node is ExpressionStatement && node.expression is ThrowExpression;

@pragma('vm:prefer-inline')
Expression _thisOr(Expression node) =>
node is PropertyAccess && node.target is ThisExpression
? node.propertyName
: node;
Expression _thisOrContextOr(Expression node) {
if (node is PropertyAccess && node.target is ThisExpression) {
return node.propertyName;
}

if (node is PrefixedIdentifier && isBuildContext(node.prefix.staticType)) {
return node.identifier;
}

return node;
}

bool _blockDiverges(Statement block, {required bool allowControlFlow}) => block
is Block
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class _FooState extends State<StatefulWidget> {
Widget build(BuildContext context) {
return FooWidget(
onChange: (value) async {
setState(() {});
await fetchData();

if (context.mounted) setState(() {});
},
);
}
}

typedef VoidCallback = void Function();

class State {
void setState(VoidCallback callback) {}
}

class BuildContext {
bool get mounted = true;
}

Future<String> fetchData() => Future.value('123');
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const _examplePath = 'use_setstate_synchronously/examples/example.dart';
const _issuesPath = 'use_setstate_synchronously/examples/known_errors.dart';
const _trySwitchPath =
'use_setstate_synchronously/examples/extras_try_switch.dart';
const _contextMountedPath =
'use_setstate_synchronously/examples/context_mounted.dart';

void main() {
group('UseSetStateSynchronouslyTest', () {
Expand Down Expand Up @@ -115,5 +117,12 @@ void main() {
],
);
});

test('reports no issues for context.mounted', () async {
final unit = await RuleTestHelper.resolveFromFile(_contextMountedPath);
final issues = UseSetStateSynchronouslyRule().check(unit);

RuleTestHelper.verifyNoIssues(issues);
});
});
}