Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
c742c198
Unverified
Commit
c742c198
authored
Mar 02, 2020
by
Remi Rousselet
Committed by
GitHub
Mar 02, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add debugDoingBuild flag (#51428)
parent
fe0a669c
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
323 additions
and
0 deletions
+323
-0
framework.dart
packages/flutter/lib/src/widgets/framework.dart
+57
-0
diagnostics_json_test.dart
packages/flutter/test/foundation/diagnostics_json_test.dart
+3
-0
framework_test.dart
packages/flutter/test/widgets/framework_test.dart
+263
-0
No files found.
packages/flutter/lib/src/widgets/framework.dart
View file @
c742c198
...
...
@@ -2052,6 +2052,22 @@ abstract class BuildContext {
/// managing the rendering pipeline for this context.
BuildOwner
get
owner
;
/// Whether the [widget] is currently updating the widget or render tree.
///
/// For [StatefullWidget]s and [StatelessWidget]s this flag is true while
/// their respective build methods are executing.
/// [RenderObjectWidget]s set this to true while creating or configuring their
/// associated [RenderObject]s.
/// Other [Widget] types may set this to true for conceptually similar phases
/// of their lifecycle.
///
/// When this is true, it is safe for [widget] to establish a dependency to an
/// [InheritedWidget] by calling [dependOnInheritedElement] or
/// [dependOnInheritedWidgetOfExactType].
///
/// Accessing this flag in release mode is not valid.
bool
get
debugDoingBuild
;
/// The current [RenderObject] for the widget. If the widget is a
/// [RenderObjectWidget], this is the render object that the widget created
/// for itself. Otherwise, it is the render object of the first descendant
...
...
@@ -4448,6 +4464,10 @@ abstract class ComponentElement extends Element {
Element
_child
;
bool
_debugDoingBuild
=
false
;
@override
bool
get
debugDoingBuild
=>
_debugDoingBuild
;
@override
void
mount
(
Element
parent
,
dynamic
newSlot
)
{
super
.
mount
(
parent
,
newSlot
);
...
...
@@ -4475,9 +4495,18 @@ abstract class ComponentElement extends Element {
assert
(
_debugSetAllowIgnoredCallsToMarkNeedsBuild
(
true
));
Widget
built
;
try
{
assert
(()
{
_debugDoingBuild
=
true
;
return
true
;
}());
built
=
build
();
assert
(()
{
_debugDoingBuild
=
false
;
return
true
;
}());
debugWidgetBuilderValue
(
widget
,
built
);
}
catch
(
e
,
stack
)
{
_debugDoingBuild
=
false
;
built
=
ErrorWidget
.
builder
(
_debugReportException
(
ErrorDescription
(
'building
$this
'
),
...
...
@@ -5270,6 +5299,10 @@ abstract class RenderObjectElement extends Element {
RenderObject
get
renderObject
=>
_renderObject
;
RenderObject
_renderObject
;
bool
_debugDoingBuild
=
false
;
@override
bool
get
debugDoingBuild
=>
_debugDoingBuild
;
RenderObjectElement
_ancestorRenderObjectElement
;
RenderObjectElement
_findAncestorRenderObjectElement
()
{
...
...
@@ -5326,7 +5359,15 @@ abstract class RenderObjectElement extends Element {
@override
void
mount
(
Element
parent
,
dynamic
newSlot
)
{
super
.
mount
(
parent
,
newSlot
);
assert
(()
{
_debugDoingBuild
=
true
;
return
true
;
}());
_renderObject
=
widget
.
createRenderObject
(
this
);
assert
(()
{
_debugDoingBuild
=
false
;
return
true
;
}());
assert
(()
{
_debugUpdateRenderObjectOwner
();
return
true
;
...
...
@@ -5344,7 +5385,15 @@ abstract class RenderObjectElement extends Element {
_debugUpdateRenderObjectOwner
();
return
true
;
}());
assert
(()
{
_debugDoingBuild
=
true
;
return
true
;
}());
widget
.
updateRenderObject
(
this
,
renderObject
);
assert
(()
{
_debugDoingBuild
=
false
;
return
true
;
}());
_dirty
=
false
;
}
...
...
@@ -5357,7 +5406,15 @@ abstract class RenderObjectElement extends Element {
@override
void
performRebuild
()
{
assert
(()
{
_debugDoingBuild
=
true
;
return
true
;
}());
widget
.
updateRenderObject
(
this
,
renderObject
);
assert
(()
{
_debugDoingBuild
=
false
;
return
true
;
}());
_dirty
=
false
;
}
...
...
packages/flutter/test/foundation/diagnostics_json_test.dart
View file @
c742c198
...
...
@@ -225,6 +225,9 @@ class _TestElement extends Element {
void
performRebuild
()
{
// Intentionally left empty.
}
@override
bool
get
debugDoingBuild
=>
throw
UnimplementedError
();
}
class
TestTree
extends
Object
with
DiagnosticableTreeMixin
{
...
...
packages/flutter/test/widgets/framework_test.dart
View file @
c742c198
...
...
@@ -1283,6 +1283,150 @@ void main() {
expect
(
isBuildDecorated
,
isTrue
);
expect
(
isDidChangeDependenciesDecorated
,
isFalse
);
});
group
(
'BuildContext.debugDoingbuild'
,
()
{
testWidgets
(
'StatelessWidget'
,
(
WidgetTester
tester
)
async
{
bool
debugDoingBuildOnBuild
;
await
tester
.
pumpWidget
(
StatelessWidgetSpy
(
onBuild:
(
BuildContext
context
)
{
debugDoingBuildOnBuild
=
context
.
debugDoingBuild
;
},
),
);
final
Element
context
=
tester
.
element
(
find
.
byType
(
StatelessWidgetSpy
));
expect
(
context
.
debugDoingBuild
,
isFalse
);
expect
(
debugDoingBuildOnBuild
,
isTrue
);
});
testWidgets
(
'StatefulWidget'
,
(
WidgetTester
tester
)
async
{
bool
debugDoingBuildOnBuild
;
bool
debugDoingBuildOnInitState
;
bool
debugDoingBuildOnDidChangeDependencies
;
bool
debugDoingBuildOnDidUpdateWidget
;
bool
debugDoingBuildOnDispose
;
bool
debugDoingBuildOnDeactivate
;
await
tester
.
pumpWidget
(
Inherited
(
0
,
child:
StatefulWidgetSpy
(
onInitState:
(
BuildContext
context
)
{
debugDoingBuildOnInitState
=
context
.
debugDoingBuild
;
},
onDidChangeDependencies:
(
BuildContext
context
)
{
context
.
dependOnInheritedWidgetOfExactType
<
Inherited
>();
debugDoingBuildOnDidChangeDependencies
=
context
.
debugDoingBuild
;
},
onBuild:
(
BuildContext
context
)
{
debugDoingBuildOnBuild
=
context
.
debugDoingBuild
;
},
),
),
);
final
Element
context
=
tester
.
element
(
find
.
byType
(
StatefulWidgetSpy
));
expect
(
context
.
debugDoingBuild
,
isFalse
);
expect
(
debugDoingBuildOnBuild
,
isTrue
);
expect
(
debugDoingBuildOnInitState
,
isFalse
);
expect
(
debugDoingBuildOnDidChangeDependencies
,
isFalse
);
await
tester
.
pumpWidget
(
Inherited
(
1
,
child:
StatefulWidgetSpy
(
onDidUpdateWidget:
(
BuildContext
context
)
{
debugDoingBuildOnDidUpdateWidget
=
context
.
debugDoingBuild
;
},
onDidChangeDependencies:
(
BuildContext
context
)
{
debugDoingBuildOnDidChangeDependencies
=
context
.
debugDoingBuild
;
},
onBuild:
(
BuildContext
context
)
{
debugDoingBuildOnBuild
=
context
.
debugDoingBuild
;
},
onDispose:
(
BuildContext
contex
)
{
debugDoingBuildOnDispose
=
context
.
debugDoingBuild
;
},
onDeactivate:
(
BuildContext
contex
)
{
debugDoingBuildOnDeactivate
=
context
.
debugDoingBuild
;
},
),
),
);
expect
(
context
.
debugDoingBuild
,
isFalse
);
expect
(
debugDoingBuildOnBuild
,
isTrue
);
expect
(
debugDoingBuildOnDidUpdateWidget
,
isFalse
);
expect
(
debugDoingBuildOnDidChangeDependencies
,
isFalse
);
expect
(
debugDoingBuildOnDeactivate
,
isNull
);
expect
(
debugDoingBuildOnDispose
,
isNull
);
await
tester
.
pumpWidget
(
Container
());
expect
(
context
.
debugDoingBuild
,
isFalse
);
expect
(
debugDoingBuildOnDispose
,
isFalse
);
expect
(
debugDoingBuildOnDeactivate
,
isFalse
);
});
testWidgets
(
'RenderObjectWidget'
,
(
WidgetTester
tester
)
async
{
bool
debugDoingBuildOnCreateRenderObject
;
bool
debugDoingBuildOnUpdateRenderObject
;
bool
debugDoingBuildOnDidUnmountRenderObject
;
final
ValueNotifier
<
int
>
notifier
=
ValueNotifier
<
int
>(
0
);
BuildContext
spyContext
;
Widget
build
()
{
return
ValueListenableBuilder
<
int
>(
valueListenable:
notifier
,
builder:
(
BuildContext
context
,
int
value
,
Widget
child
)
{
return
Inherited
(
value
,
child:
child
);
},
child:
RenderObjectWidgetSpy
(
onCreateRenderObjet:
(
BuildContext
context
)
{
spyContext
=
context
;
context
.
dependOnInheritedWidgetOfExactType
<
Inherited
>();
debugDoingBuildOnCreateRenderObject
=
context
.
debugDoingBuild
;
},
onUpdateRenderObject:
(
BuildContext
context
)
{
debugDoingBuildOnUpdateRenderObject
=
context
.
debugDoingBuild
;
},
onDidUmountRenderObject:
()
{
debugDoingBuildOnDidUnmountRenderObject
=
spyContext
.
debugDoingBuild
;
},
),
);
}
await
tester
.
pumpWidget
(
build
());
spyContext
=
tester
.
element
(
find
.
byType
(
RenderObjectWidgetSpy
));
expect
(
spyContext
.
debugDoingBuild
,
isFalse
);
expect
(
debugDoingBuildOnCreateRenderObject
,
isTrue
);
expect
(
debugDoingBuildOnUpdateRenderObject
,
isNull
);
expect
(
debugDoingBuildOnDidUnmountRenderObject
,
isNull
);
await
tester
.
pumpWidget
(
build
());
expect
(
spyContext
.
debugDoingBuild
,
isFalse
);
expect
(
debugDoingBuildOnUpdateRenderObject
,
isTrue
);
expect
(
debugDoingBuildOnDidUnmountRenderObject
,
isNull
);
notifier
.
value
++;
debugDoingBuildOnUpdateRenderObject
=
false
;
await
tester
.
pump
();
expect
(
spyContext
.
debugDoingBuild
,
isFalse
);
expect
(
debugDoingBuildOnUpdateRenderObject
,
isTrue
);
expect
(
debugDoingBuildOnDidUnmountRenderObject
,
isNull
);
await
tester
.
pumpWidget
(
Container
());
expect
(
spyContext
.
debugDoingBuild
,
isFalse
);
expect
(
debugDoingBuildOnDidUnmountRenderObject
,
isFalse
);
});
});
}
class
Decorate
extends
StatefulWidget
{
...
...
@@ -1354,6 +1498,9 @@ class NullChildElement extends Element {
@override
void
performRebuild
()
{
}
@override
bool
get
debugDoingBuild
=>
throw
UnimplementedError
();
}
...
...
@@ -1371,6 +1518,9 @@ class DirtyElementWithCustomBuildOwner extends Element {
@override
bool
get
dirty
=>
true
;
@override
bool
get
debugDoingBuild
=>
throw
UnimplementedError
();
}
class
Inherited
extends
InheritedWidget
{
...
...
@@ -1474,3 +1624,116 @@ class StatefulElementSpy extends StatefulElement {
super
.
rebuild
();
}
}
class
StatelessWidgetSpy
extends
StatelessWidget
{
const
StatelessWidgetSpy
({
Key
key
,
@required
this
.
onBuild
,
})
:
assert
(
onBuild
!=
null
),
super
(
key:
key
);
final
void
Function
(
BuildContext
)
onBuild
;
@override
Widget
build
(
BuildContext
context
)
{
onBuild
(
context
);
return
Container
();
}
}
class
StatefulWidgetSpy
extends
StatefulWidget
{
const
StatefulWidgetSpy
({
Key
key
,
this
.
onBuild
,
this
.
onInitState
,
this
.
onDidChangeDependencies
,
this
.
onDispose
,
this
.
onDeactivate
,
this
.
onDidUpdateWidget
,
})
:
super
(
key:
key
);
final
void
Function
(
BuildContext
)
onBuild
;
final
void
Function
(
BuildContext
)
onInitState
;
final
void
Function
(
BuildContext
)
onDidChangeDependencies
;
final
void
Function
(
BuildContext
)
onDispose
;
final
void
Function
(
BuildContext
)
onDeactivate
;
final
void
Function
(
BuildContext
)
onDidUpdateWidget
;
@override
_StatefulWidgetSpyState
createState
()
=>
_StatefulWidgetSpyState
();
}
class
_StatefulWidgetSpyState
extends
State
<
StatefulWidgetSpy
>
{
@override
void
initState
()
{
super
.
initState
();
widget
.
onInitState
?.
call
(
context
);
}
@override
void
deactivate
()
{
super
.
deactivate
();
widget
.
onDeactivate
?.
call
(
context
);
}
@override
void
dispose
()
{
super
.
dispose
();
widget
.
onDispose
?.
call
(
context
);
}
@override
void
didChangeDependencies
()
{
super
.
didChangeDependencies
();
widget
.
onDidChangeDependencies
?.
call
(
context
);
}
@override
void
didUpdateWidget
(
StatefulWidgetSpy
oldWidget
)
{
super
.
didUpdateWidget
(
oldWidget
);
widget
.
onDidUpdateWidget
?.
call
(
context
);
}
@override
Widget
build
(
BuildContext
context
)
{
widget
.
onBuild
?.
call
(
context
);
return
Container
();
}
}
class
RenderObjectWidgetSpy
extends
LeafRenderObjectWidget
{
const
RenderObjectWidgetSpy
({
Key
key
,
this
.
onCreateRenderObjet
,
this
.
onUpdateRenderObject
,
this
.
onDidUmountRenderObject
,
})
:
super
(
key:
key
);
final
void
Function
(
BuildContext
)
onCreateRenderObjet
;
final
void
Function
(
BuildContext
)
onUpdateRenderObject
;
final
void
Function
()
onDidUmountRenderObject
;
@override
RenderObject
createRenderObject
(
BuildContext
context
)
{
onCreateRenderObjet
?.
call
(
context
);
return
FakeLeafRenderObject
();
}
@override
void
updateRenderObject
(
BuildContext
context
,
RenderObject
renderObject
)
{
onUpdateRenderObject
?.
call
(
context
);
}
@override
void
didUnmountRenderObject
(
RenderObject
renderObject
)
{
super
.
didUnmountRenderObject
(
renderObject
);
onDidUmountRenderObject
?.
call
();
}
}
class
FakeLeafRenderObject
extends
RenderBox
{
@override
void
performLayout
()
{
size
=
constraints
.
biggest
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment