Chain.forTrace() trims the innermost trace's VM chain
This was already being trimmed for all other stack traces, but the
innermost one requires different logic, so we missed it.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 916448c..b0c972a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,11 @@
synchronously within `Chain.capture()`. This matches the existing behavior
outside `Chain.capture()`.
+* `Chain.forTrace()` now trims the VM's stack chains for the innermost stack
+ trace within `Chain.capture()` (unless it's called synchronously, as above).
+ This avoids duplicated frames and makes the format of the innermost traces
+ consistent with the other traces in the chain.
+
## 1.8.2
* Update to use strong-mode clean Zone API.
diff --git a/lib/src/stack_zone_specification.dart b/lib/src/stack_zone_specification.dart
index 2db98b7..cd5d068 100644
--- a/lib/src/stack_zone_specification.dart
+++ b/lib/src/stack_zone_specification.dart
@@ -90,13 +90,20 @@
trace ??= StackTrace.current;
var previous = _chains[trace] ?? _currentNode;
- if (previous != null) return new _Node(trace, previous).toChain();
+ if (previous == null) {
+ // If there's no [_currentNode], we're running synchronously beneath
+ // [Chain.capture] and we should fall back to the VM's stack chaining. We
+ // can't use [Chain.from] here because it'll just call [chainFor] again.
+ if (trace is Trace) return new Chain([trace]);
+ return new LazyChain(() => new Chain.parse(trace.toString()));
+ } else {
+ if (trace is! Trace) {
+ var original = trace;
+ trace = new LazyTrace(() => new Trace.parse(_trimVMChain(original)));
+ }
- // If there's no [_currentNode], we're running synchronously beneath
- // [Chain.capture] and we should fall back to the VM's stack chaining. We
- // can't use [Chain.from] here because it'll just call [chainFor] again.
- if (trace is Trace) return new Chain([trace]);
- return new LazyChain(() => new Chain.parse(trace.toString()));
+ return new _Node(trace, previous).toChain();
+ }
}
/// Tracks the current stack chain so it can be set to [_currentChain] when
@@ -203,6 +210,29 @@
_currentNode = previousNode;
}
}
+
+ /// Like [new Trace.current], but if the current stack trace has VM chaining
+ /// enabled, this only returns the innermost sub-trace.
+ Trace _currentTrace([int level]) {
+ level ??= 0;
+ var stackTrace = StackTrace.current;
+ return new LazyTrace(() {
+ var text = _trimVMChain(stackTrace);
+ var trace = new Trace.parse(text);
+ // JS includes a frame for the call to StackTrace.current, but the VM
+ // doesn't, so we skip an extra frame in a JS context.
+ return new Trace(trace.frames.skip(level + (inJS ? 2 : 1)),
+ original: text);
+ });
+ }
+
+ /// Removes the VM's stack chains from the native [trace], since we're
+ /// generating our own and we don't want duplicate frames.
+ String _trimVMChain(StackTrace trace) {
+ var text = trace.toString();
+ var index = text.indexOf(vmChainGap);
+ return index == -1 ? text : text.substring(0, index);
+ }
}
/// A linked list node representing a single entry in a stack chain.
@@ -213,8 +243,7 @@
/// The previous node in the chain.
final _Node previous;
- _Node(StackTrace trace, [this.previous])
- : trace = trace == null ? _currentTrace() : new Trace.from(trace);
+ _Node(StackTrace trace, [this.previous]) : trace = new Trace.from(trace);
/// Converts this to a [Chain].
Chain toChain() {
@@ -227,22 +256,3 @@
return new Chain(nodes);
}
}
-
-/// Like [new Trace.current], but if the current stack trace has VM chaining
-/// enabled, this only returns the innermost sub-trace.
-Trace _currentTrace([int level]) {
- level ??= 0;
- var stackTrace = StackTrace.current;
- return new LazyTrace(() {
- // Ignore the VM's stack chains when we generate our own. Otherwise we'll
- // end up with duplicate frames all over the place.
- var text = stackTrace.toString();
- var index = text.indexOf(vmChainGap);
- if (index != -1) text = text.substring(0, index);
-
- var trace = new Trace.parse(text);
- // JS includes a frame for the call to StackTrace.current, but the VM
- // doesn't, so we skip an extra frame in a JS context.
- return new Trace(trace.frames.skip(level + (inJS ? 2 : 1)), original: text);
- });
-}
diff --git a/pubspec.yaml b/pubspec.yaml
index 79cf0b0..65d3ef6 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -7,7 +7,7 @@
#
# When the major version is upgraded, you *must* update that version constraint
# in pub to stay in sync with this.
-version: 1.8.3-dev
+version: 1.8.3
author: "Dart Team <misc@dartlang.org>"
homepage: https://github.com/dart-lang/stack_trace
description: A package for manipulating stack traces and printing them readably.
diff --git a/test/chain/vm_test.dart b/test/chain/vm_test.dart
index 6f793c4..a47cbf7 100644
--- a/test/chain/vm_test.dart
+++ b/test/chain/vm_test.dart
@@ -468,8 +468,11 @@
});
expect(chain.traces, hasLength(2));
+
+ // Assert that we've trimmed the VM's stack chains here to avoid
+ // duplication.
expect(chain.traces.first.toString(),
- equals(new Trace.from(trace).toString()));
+ equals(new Chain.parse(trace.toString()).traces.first.toString()));
expect(
chain.traces.last.frames, contains(frameMember(startsWith('main'))));
});