Chain.forTrace() falls back on VM stack chains This wasn't happening previously when it was called synchronously within Chain.capture().
diff --git a/pkgs/stack_trace/CHANGELOG.md b/pkgs/stack_trace/CHANGELOG.md index e8e717e..916448c 100644 --- a/pkgs/stack_trace/CHANGELOG.md +++ b/pkgs/stack_trace/CHANGELOG.md
@@ -4,6 +4,10 @@ within `Chain.capture()`, even those that haven't been processed by `dart:async` yet. +* `Chain.forTrace()` now uses the Dart VM's stack chain information when called + synchronously within `Chain.capture()`. This matches the existing behavior + outside `Chain.capture()`. + ## 1.8.2 * Update to use strong-mode clean Zone API.
diff --git a/pkgs/stack_trace/lib/src/chain.dart b/pkgs/stack_trace/lib/src/chain.dart index 01bf06f..56c5333 100644 --- a/pkgs/stack_trace/lib/src/chain.dart +++ b/pkgs/stack_trace/lib/src/chain.dart
@@ -153,6 +153,7 @@ factory Chain.forTrace(StackTrace trace) { if (trace is Chain) return trace; if (_currentSpec != null) return _currentSpec.chainFor(trace); + if (trace is Trace) return new Chain([trace]); return new LazyChain(() => new Chain.parse(trace.toString())); }
diff --git a/pkgs/stack_trace/lib/src/stack_zone_specification.dart b/pkgs/stack_trace/lib/src/stack_zone_specification.dart index 7205a4e..2db98b7 100644 --- a/pkgs/stack_trace/lib/src/stack_zone_specification.dart +++ b/pkgs/stack_trace/lib/src/stack_zone_specification.dart
@@ -5,6 +5,7 @@ import 'dart:async'; import 'chain.dart'; +import 'lazy_chain.dart'; import 'lazy_trace.dart'; import 'trace.dart'; import 'utils.dart'; @@ -86,8 +87,16 @@ /// with [trace], this just returns a single-trace chain containing [trace]. Chain chainFor(StackTrace trace) { if (trace is Chain) return trace; - var previous = (trace == null ? null : _chains[trace]) ?? _currentNode; - return new _Node(trace, previous).toChain(); + trace ??= StackTrace.current; + + var previous = _chains[trace] ?? _currentNode; + if (previous != null) return new _Node(trace, previous).toChain(); + + // 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())); } /// Tracks the current stack chain so it can be set to [_currentChain] when
diff --git a/pkgs/stack_trace/test/chain/vm_test.dart b/pkgs/stack_trace/test/chain/vm_test.dart index 3378bc2..6f793c4 100644 --- a/pkgs/stack_trace/test/chain/vm_test.dart +++ b/pkgs/stack_trace/test/chain/vm_test.dart
@@ -18,12 +18,21 @@ void main() { group('capture() with onError catches exceptions', () { - test('thrown synchronously', () { - return captureFuture(() => throw 'error').then((chain) { - expect(chain.traces, hasLength(1)); - expect( - chain.traces.single.frames.first, frameMember(startsWith('main'))); + test('thrown synchronously', () async { + StackTrace vmTrace; + var chain = await captureFuture(() { + try { + throw 'error'; + } catch (_, stackTrace) { + vmTrace = stackTrace; + rethrow; + } }); + + // Because there's no chain context for a synchronous error, we fall back + // on the VM's stack chain tracking. + expect(chain.toString(), + equals(new Chain.parse(vmTrace.toString()).toString())); }); test('thrown in a microtask', () {