Commit 6aae6764 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Avoid returning null from debugDescribeChildren (#11806)

In some cases, the element tree is not clean but we are required to dump the tree anyway.
To avoid crashing in those cases, we return an explicit null node.
parent f1a23e26
...@@ -845,14 +845,10 @@ abstract class DiagnosticsNode { ...@@ -845,14 +845,10 @@ abstract class DiagnosticsNode {
for (int i = 0; i < children.length; i++) { for (int i = 0; i < children.length; i++) {
final DiagnosticsNode child = children[i]; final DiagnosticsNode child = children[i];
assert(child != null);
final TextTreeConfiguration childConfig = _childTextConfiguration(child, config); final TextTreeConfiguration childConfig = _childTextConfiguration(child, config);
if (i == children.length - 1) { if (i == children.length - 1) {
final String lastChildPrefixLineOne = '$prefixChildren${childConfig.prefixLastChildLineOne}'; final String lastChildPrefixLineOne = '$prefixChildren${childConfig.prefixLastChildLineOne}';
if (child == null) {
builder.writeRawLine('$lastChildPrefixLineOne<null>');
continue;
}
builder.writeRawLine(child.toStringDeep( builder.writeRawLine(child.toStringDeep(
lastChildPrefixLineOne, lastChildPrefixLineOne,
'$prefixChildren${childConfig.childLinkSpace}${childConfig.prefixOtherLines}', '$prefixChildren${childConfig.childLinkSpace}${childConfig.prefixOtherLines}',
...@@ -862,14 +858,8 @@ abstract class DiagnosticsNode { ...@@ -862,14 +858,8 @@ abstract class DiagnosticsNode {
builder.writeRaw('$prefixChildren${childConfig.childLinkSpace}${childConfig.footer}'); builder.writeRaw('$prefixChildren${childConfig.childLinkSpace}${childConfig.footer}');
} else { } else {
final TextTreeConfiguration nextChildStyle = _childTextConfiguration(children[i + 1], config); final TextTreeConfiguration nextChildStyle = _childTextConfiguration(children[i + 1], config);
final String childPrefixLineOne = '$prefixChildren${childConfig.prefixLineOne}'; final String childPrefixLineOne = '$prefixChildren${childConfig.prefixLineOne}';
final String childPrefixOtherLines ='$prefixChildren${nextChildStyle.linkCharacter}${childConfig.prefixOtherLines}'; final String childPrefixOtherLines ='$prefixChildren${nextChildStyle.linkCharacter}${childConfig.prefixOtherLines}';
if (child == null) {
builder.writeRawLine('$childPrefixLineOne<null>');
continue;
}
builder.writeRawLine(child.toStringDeep(childPrefixLineOne, childPrefixOtherLines)); builder.writeRawLine(child.toStringDeep(childPrefixLineOne, childPrefixOtherLines));
if (childConfig.footer.isNotEmpty) if (childConfig.footer.isNotEmpty)
builder.writeRaw('$prefixChildren${nextChildStyle.linkCharacter}${childConfig.footer}'); builder.writeRaw('$prefixChildren${nextChildStyle.linkCharacter}${childConfig.footer}');
...@@ -2139,13 +2129,18 @@ abstract class DiagnosticableTree extends Diagnosticable { ...@@ -2139,13 +2129,18 @@ abstract class DiagnosticableTree extends Diagnosticable {
/// Returns a list of [DiagnosticsNode] objects describing this node's /// Returns a list of [DiagnosticsNode] objects describing this node's
/// children. /// children.
/// ///
/// Children that are offstage should added with `style` /// Children that are offstage should be added with `style` set to
/// [DiagnosticsTreeStyle.offstage] to indicate that they are offstage. /// [DiagnosticsTreeStyle.offstage] to indicate that they are offstage.
/// ///
/// The list must not contain any null entries. If there are explicit null
/// children to report, consider [new DiagnosticsNode.message] or
/// [DiagnosticsProperty<Object>] as possible [DiagnosticsNode] objects to
/// provide.
///
/// See also: /// See also:
/// ///
/// * [RenderTable.debugDescribeChildren], which provides high quality custom /// * [RenderTable.debugDescribeChildren], which provides high quality custom
/// descriptions for child nodes. /// descriptions for its child nodes.
/// ///
/// Used by [toStringDeep], [toDiagnosticsNode] and [toStringShallow]. /// Used by [toStringDeep], [toDiagnosticsNode] and [toStringShallow].
@protected @protected
......
...@@ -353,8 +353,14 @@ class TextSpan extends DiagnosticableTree { ...@@ -353,8 +353,14 @@ class TextSpan extends DiagnosticableTree {
@override @override
List<DiagnosticsNode> debugDescribeChildren() { List<DiagnosticsNode> debugDescribeChildren() {
return children == null ? if (children == null)
const <DiagnosticsNode>[] : return const <DiagnosticsNode>[];
children.map((TextSpan child) => child?.toDiagnosticsNode()).toList(); return children.map((TextSpan child) {
if (child != null) {
return child.toDiagnosticsNode();
} else {
return new DiagnosticsNode.message('<null child>');
}
}).toList();
} }
} }
...@@ -3326,7 +3326,11 @@ abstract class Element extends DiagnosticableTree implements BuildContext { ...@@ -3326,7 +3326,11 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
List<DiagnosticsNode> debugDescribeChildren() { List<DiagnosticsNode> debugDescribeChildren() {
final List<DiagnosticsNode> children = <DiagnosticsNode>[]; final List<DiagnosticsNode> children = <DiagnosticsNode>[];
visitChildren((Element child) { visitChildren((Element child) {
children.add(child.toDiagnosticsNode()); if (child != null) {
children.add(child.toDiagnosticsNode());
} else {
children.add(new DiagnosticsNode.message('<null child>'));
}
}); });
return children; return children;
} }
......
...@@ -101,6 +101,7 @@ class _WidgetInspectorState extends State<WidgetInspector> ...@@ -101,6 +101,7 @@ class _WidgetInspectorState extends State<WidgetInspector>
final List<DiagnosticsNode> children = object.debugDescribeChildren(); final List<DiagnosticsNode> children = object.debugDescribeChildren();
for (int i = children.length - 1; i >= 0; i -= 1) { for (int i = children.length - 1; i >= 0; i -= 1) {
final DiagnosticsNode diagnostics = children[i]; final DiagnosticsNode diagnostics = children[i];
assert(diagnostics != null);
if (diagnostics.style == DiagnosticsTreeStyle.offstage || if (diagnostics.style == DiagnosticsTreeStyle.offstage ||
diagnostics.value is! RenderObject) diagnostics.value is! RenderObject)
continue; continue;
......
...@@ -30,24 +30,24 @@ void main() { ...@@ -30,24 +30,24 @@ void main() {
expect(c1 == b2, isFalse); expect(c1 == b2, isFalse);
}); });
test('TextSpan', () { test('TextSpan toStringDeep', () {
final TextSpan test = const TextSpan( final TextSpan test = const TextSpan(
text: 'a', text: 'a',
style: const TextStyle( style: const TextStyle(
fontSize: 10.0 fontSize: 10.0,
), ),
children: const <TextSpan>[ children: const <TextSpan>[
const TextSpan( const TextSpan(
text: 'b', text: 'b',
children: const <TextSpan>[ children: const <TextSpan>[
const TextSpan() const TextSpan(),
] ],
), ),
null, null,
const TextSpan( const TextSpan(
text: 'c' text: 'c',
), ),
] ],
); );
expect(test.toStringDeep(), equals( expect(test.toStringDeep(), equals(
'TextSpan:\n' 'TextSpan:\n'
...@@ -58,7 +58,7 @@ void main() { ...@@ -58,7 +58,7 @@ void main() {
' "b"\n' ' "b"\n'
' TextSpan:\n' ' TextSpan:\n'
' (empty)\n' ' (empty)\n'
' <null>\n' ' <null child>\n'
' TextSpan:\n' ' TextSpan:\n'
' "c"\n' ' "c"\n'
)); ));
......
...@@ -506,4 +506,42 @@ void main() { ...@@ -506,4 +506,42 @@ void main() {
), ),
); );
}); });
testWidgets('Element diagnostics with null child', (WidgetTester tester) async {
await tester.pumpWidget(new NullChildTest());
final NullChildElement test = tester.element<NullChildElement>(find.byType(NullChildTest));
test.includeChild = true;
expect(
tester.binding.renderViewElement.toStringDeep(),
equalsIgnoringHashCodes(
'[root](renderObject: RenderView#4a0f0)\n'
'└NullChildTest(dirty)\n'
' └<null child>\n',
),
);
test.includeChild = false;
});
}
class NullChildTest extends Widget {
@override
Element createElement() => new NullChildElement(this);
} }
class NullChildElement extends Element {
NullChildElement(Widget widget) : super(widget);
bool includeChild = false;
@override
void visitChildren(ElementVisitor visitor) {
if (includeChild)
visitor(null);
}
@override
void forgetChild(Element child) { }
@override
void performRebuild() { }
}
\ No newline at end of file
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