Better support for async VM frames. Closes dart-lang/stack_trace#1 R=kevmoo@google.com Review URL: https://codereview.chromium.org//912043002
diff --git a/pkgs/stack_trace/CHANGELOG.md b/pkgs/stack_trace/CHANGELOG.md index 2850cfc..25abd8a 100644 --- a/pkgs/stack_trace/CHANGELOG.md +++ b/pkgs/stack_trace/CHANGELOG.md
@@ -1,3 +1,11 @@ +## 1.1.2 + +* Support VM frames without line *or* column numbers, which async/await programs + occasionally generate. + +* Replace `<<anonymous closure>_async_body>` in VM frames' members with the + terser `<async>`. + ## 1.1.1 * Widen the SDK constraint to include 1.7.0-dev.4.0.
diff --git a/pkgs/stack_trace/lib/src/frame.dart b/pkgs/stack_trace/lib/src/frame.dart index 4f5b16c..8ecd19f 100644 --- a/pkgs/stack_trace/lib/src/frame.dart +++ b/pkgs/stack_trace/lib/src/frame.dart
@@ -10,8 +10,9 @@ import 'trace.dart'; // #1 Foo._bar (file:///home/nweiz/code/stuff.dart:42:21) -final _vmFrame = new RegExp( - r'^#\d+\s+(\S.*) \((.+?):(\d+)(?::(\d+))?\)$'); +// #1 Foo._bar (file:///home/nweiz/code/stuff.dart:42) +// #1 Foo._bar (file:///home/nweiz/code/stuff.dart) +final _vmFrame = new RegExp(r'^#\d+\s+(\S.*) \((.+?)((?::\d+){0,2})\)$'); // at VW.call$0 (http://pub.dartlang.org/stuff.dart.js:560:28) // at VW.call$0 (eval as fn @@ -135,14 +136,14 @@ // Get the pieces out of the regexp match. Function, URI and line should // always be found. The column is optional. - var member = match[1].replaceAll("<anonymous closure>", "<fn>"); + var member = match[1] + .replaceAll("<<anonymous closure>_async_body>", "<async>") + .replaceAll("<anonymous closure>", "<fn>"); var uri = Uri.parse(match[2]); - var line = int.parse(match[3]); - var column = null; - var columnMatch = match[4]; - if (columnMatch != null) { - column = int.parse(columnMatch); - } + + var lineAndColumn = match[3].split(':'); + var line = lineAndColumn.length > 1 ? int.parse(lineAndColumn[1]) : null; + var column = lineAndColumn.length > 2 ? int.parse(lineAndColumn[2]) : null; return new Frame(uri, line, column, member); }
diff --git a/pkgs/stack_trace/lib/src/vm_trace.dart b/pkgs/stack_trace/lib/src/vm_trace.dart index 8116015..89474f5 100644 --- a/pkgs/stack_trace/lib/src/vm_trace.dart +++ b/pkgs/stack_trace/lib/src/vm_trace.dart
@@ -22,7 +22,9 @@ var i = 1; return frames.map((frame) { var number = padRight("#${i++}", 8); - var member = frame.member.replaceAll("<fn>", "<anonymous closure>"); + var member = frame.member + .replaceAll("<fn>", "<anonymous closure>") + .replaceAll("<async>", "<<anonymous closure>_async_body>"); var line = frame.line == null ? 0 : frame.line; var column = frame.column == null ? 0 : frame.column; return "$number$member (${frame.uri}:$line:$column)\n";
diff --git a/pkgs/stack_trace/pubspec.yaml b/pkgs/stack_trace/pubspec.yaml index 8adfb2f..2fee061 100644 --- a/pkgs/stack_trace/pubspec.yaml +++ b/pkgs/stack_trace/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.1.1 +version: 1.1.2 author: "Dart Team <misc@dartlang.org>" homepage: http://github.com/dart-lang/stack_trace description: >
diff --git a/pkgs/stack_trace/test/frame_test.dart b/pkgs/stack_trace/test/frame_test.dart index b132368..638d1d7 100644 --- a/pkgs/stack_trace/test/frame_test.dart +++ b/pkgs/stack_trace/test/frame_test.dart
@@ -30,6 +30,17 @@ expect(frame.member, equals('Foo._bar')); }); + // This can happen with async stack traces. See issue 22009. + test('parses a stack frame without line or column correctly', () { + var frame = new Frame.parseVM("#1 Foo._bar " + "(file:///home/nweiz/code/stuff.dart)"); + expect(frame.uri, + equals(Uri.parse("file:///home/nweiz/code/stuff.dart"))); + expect(frame.line, isNull); + expect(frame.column, isNull); + expect(frame.member, equals('Foo._bar')); + }); + test('converts "<anonymous closure>" to "<fn>"', () { String parsedMember(String member) => new Frame.parseVM('#0 $member (foo:0:0)').member; @@ -39,6 +50,18 @@ equals('<fn>.<fn>.bar')); }); + test('converts "<<anonymous closure>_async_body>" to "<async>"', () { + var frame = new Frame.parseVM( + '#0 Foo.<<anonymous closure>_async_body> (foo:0:0)'); + expect(frame.member, equals('Foo.<async>')); + }); + + test('converts "<<anonymous closure>_async_body>" to "<async>"', () { + var frame = new Frame.parseVM( + '#0 Foo.<<anonymous closure>_async_body> (foo:0:0)'); + expect(frame.member, equals('Foo.<async>')); + }); + test('parses a folded frame correctly', () { var frame = new Frame.parseVM('...'); @@ -52,8 +75,6 @@ expect(() => new Frame.parseVM(''), throwsFormatException); expect(() => new Frame.parseVM('#1'), throwsFormatException); expect(() => new Frame.parseVM('#1 Foo'), throwsFormatException); - expect(() => new Frame.parseVM('#1 Foo (dart:async/future.dart)'), - throwsFormatException); expect(() => new Frame.parseVM('#1 (dart:async/future.dart:10:15)'), throwsFormatException); expect(() => new Frame.parseVM('Foo (dart:async/future.dart:10:15)'),