Unverified Commit bcc8f083 authored by Dan Field's avatar Dan Field Committed by GitHub

Forbid calling findRenderObject on an unmounted element (#83962)

parent 0100285e
...@@ -2056,7 +2056,8 @@ abstract class BuildContext { ...@@ -2056,7 +2056,8 @@ abstract class BuildContext {
/// This method will only return a valid result after the build phase is /// This method will only return a valid result after the build phase is
/// complete. It is therefore not valid to call this from a build method. /// complete. It is therefore not valid to call this from a build method.
/// It should only be called from interaction event handlers (e.g. /// It should only be called from interaction event handlers (e.g.
/// gesture callbacks) or layout or paint callbacks. /// gesture callbacks) or layout or paint callbacks. It is also not valid to
/// call if [State.mounted] returns false.
/// ///
/// If the render object is a [RenderBox], which is the common case, then the /// If the render object is a [RenderBox], which is the common case, then the
/// size of the render object can be obtained from the [size] getter. This is /// size of the render object can be obtained from the [size] getter. This is
...@@ -3864,7 +3865,25 @@ abstract class Element extends DiagnosticableTree implements BuildContext { ...@@ -3864,7 +3865,25 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
} }
@override @override
RenderObject? findRenderObject() => renderObject; RenderObject? findRenderObject() {
assert(() {
if (_lifecycleState != _ElementLifecycle.active) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('Cannot get renderObject of inactive element.'),
ErrorDescription(
'In order for an element to have a valid renderObject, it must be '
'active, which means it is part of the tree.\n'
'Instead, this element is in the $_lifecycleState state.\n'
'If you called this method from a State object, consider guarding '
'it with State.mounted.',
),
describeElement('The findRenderObject() method was called for the following element'),
]);
}
return true;
}());
return renderObject;
}
@override @override
Size? get size { Size? get size {
......
...@@ -2455,6 +2455,11 @@ class InspectorSelection { ...@@ -2455,6 +2455,11 @@ class InspectorSelection {
Element? _currentElement; Element? _currentElement;
set currentElement(Element? element) { set currentElement(Element? element) {
if (element?.debugIsDefunct == true) {
_currentElement = null;
_current = null;
return;
}
if (currentElement != element) { if (currentElement != element) {
_currentElement = element; _currentElement = element;
_current = element!.findRenderObject(); _current = element!.findRenderObject();
......
...@@ -1619,6 +1619,30 @@ void main() { ...@@ -1619,6 +1619,30 @@ void main() {
await pumpWidget(Container()); await pumpWidget(Container());
expect(states, <String>['deactivate', 'dispose']); expect(states, <String>['deactivate', 'dispose']);
}); });
testWidgets('Getting the render object of an unmounted element throws', (WidgetTester tester) async {
await tester.pumpWidget(const _StatefulLeaf());
final StatefulElement element = tester.element<StatefulElement>(find.byType(_StatefulLeaf));
expect(element.state, isA<State<_StatefulLeaf>>());
expect(element.widget, isA<_StatefulLeaf>());
// Replace the widget tree to unmount the element.
await tester.pumpWidget(Container());
expect(
() => element.findRenderObject(),
throwsA(isA<FlutterError>().having(
(FlutterError error) => error.message,
'message',
equalsIgnoringHashCodes('''
Cannot get renderObject of inactive element.
In order for an element to have a valid renderObject, it must be active, which means it is part of the tree.
Instead, this element is in the _ElementLifecycle.defunct state.
If you called this method from a State object, consider guarding it with State.mounted.
The findRenderObject() method was called for the following element:
StatefulElement#00000(DEFUNCT)'''),
)),
);
});
} }
class _WidgetWithNoVisitChildren extends StatelessWidget { class _WidgetWithNoVisitChildren extends StatelessWidget {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment