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 all commits
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);
});
});
}