LCOV - code coverage report
Current view: top level - stack_trace-1.8.2/lib/src - frame.dart (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 0 87 0.0 %
Date: 2017-10-10 20:17:03 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
       2             : // for details. All rights reserved. Use of this source code is governed by a
       3             : // BSD-style license that can be found in the LICENSE file.
       4             : 
       5             : import 'package:path/path.dart' as path;
       6             : 
       7             : import 'trace.dart';
       8             : import 'unparsed_frame.dart';
       9             : 
      10             : // #1      Foo._bar (file:///home/nweiz/code/stuff.dart:42:21)
      11             : // #1      Foo._bar (file:///home/nweiz/code/stuff.dart:42)
      12             : // #1      Foo._bar (file:///home/nweiz/code/stuff.dart)
      13             : final _vmFrame = new RegExp(r'^#\d+\s+(\S.*) \((.+?)((?::\d+){0,2})\)$');
      14             : 
      15             : //     at Object.stringify (native)
      16             : //     at VW.call$0 (http://pub.dartlang.org/stuff.dart.js:560:28)
      17             : //     at VW.call$0 (eval as fn
      18             : //         (http://pub.dartlang.org/stuff.dart.js:560:28), efn:3:28)
      19             : //     at http://pub.dartlang.org/stuff.dart.js:560:28
      20             : final _v8Frame =
      21             :     new RegExp(r'^\s*at (?:(\S.*?)(?: \[as [^\]]+\])? \((.*)\)|(.*))$');
      22             : 
      23             : // http://pub.dartlang.org/stuff.dart.js:560:28
      24             : final _v8UrlLocation = new RegExp(r'^(.*):(\d+):(\d+)|native$');
      25             : 
      26             : // eval as function (http://pub.dartlang.org/stuff.dart.js:560:28), efn:3:28
      27             : // eval as function (http://pub.dartlang.org/stuff.dart.js:560:28)
      28             : // eval as function (eval as otherFunction
      29             : //     (http://pub.dartlang.org/stuff.dart.js:560:28))
      30             : final _v8EvalLocation =
      31             :     new RegExp(r'^eval at (?:\S.*?) \((.*)\)(?:, .*?:\d+:\d+)?$');
      32             : 
      33             : // .VW.call$0@http://pub.dartlang.org/stuff.dart.js:560
      34             : // .VW.call$0("arg")@http://pub.dartlang.org/stuff.dart.js:560
      35             : // .VW.call$0/name<@http://pub.dartlang.org/stuff.dart.js:560
      36             : // .VW.call$0@http://pub.dartlang.org/stuff.dart.js:560:36
      37             : // http://pub.dartlang.org/stuff.dart.js:560
      38             : final _firefoxSafariFrame = new RegExp(r'^'
      39             :     r'(?:' // Member description. Not present in some Safari frames.
      40             :     r'([^@(/]*)' // The actual name of the member.
      41             :     r'(?:\(.*\))?' // Arguments to the member, sometimes captured by Firefox.
      42             :     r'((?:/[^/]*)*)' // Extra characters indicating a nested closure.
      43             :     r'(?:\(.*\))?' // Arguments to the closure.
      44             :     r'@'
      45             :     r')?'
      46             :     r'(.*?)' // The frame's URL.
      47             :     r':'
      48             :     r'(\d*)' // The line number. Empty in Safari if it's unknown.
      49             :     r'(?::(\d*))?' // The column number. Not present in older browsers and
      50             :     // empty in Safari if it's unknown.
      51             :     r'$');
      52             : 
      53             : // foo/bar.dart 10:11 Foo._bar
      54             : // foo/bar.dart 10:11 (anonymous function).dart.fn
      55             : // http://dartlang.org/foo/bar.dart Foo._bar
      56             : // data:... 10:11 Foo._bar
      57             : final _friendlyFrame = new RegExp(r'^(\S+)(?: (\d+)(?::(\d+))?)?\s+([^\d].*)$');
      58             : 
      59             : /// A regular expression that matches asynchronous member names generated by the
      60             : /// VM.
      61             : final _asyncBody = new RegExp(r'<(<anonymous closure>|[^>]+)_async_body>');
      62             : 
      63             : final _initialDot = new RegExp(r"^\.");
      64             : 
      65             : /// A single stack frame. Each frame points to a precise location in Dart code.
      66             : class Frame {
      67             :   /// The URI of the file in which the code is located.
      68             :   ///
      69             :   /// This URI will usually have the scheme `dart`, `file`, `http`, or `https`.
      70             :   final Uri uri;
      71             : 
      72             :   /// The line number on which the code location is located.
      73             :   ///
      74             :   /// This can be null, indicating that the line number is unknown or
      75             :   /// unimportant.
      76             :   final int line;
      77             : 
      78             :   /// The column number of the code location.
      79             :   ///
      80             :   /// This can be null, indicating that the column number is unknown or
      81             :   /// unimportant.
      82             :   final int column;
      83             : 
      84             :   /// The name of the member in which the code location occurs.
      85             :   ///
      86             :   /// Anonymous closures are represented as `<fn>` in this member string.
      87             :   final String member;
      88             : 
      89             :   /// Whether this stack frame comes from the Dart core libraries.
      90           0 :   bool get isCore => uri.scheme == 'dart';
      91             : 
      92             :   /// Returns a human-friendly description of the library that this stack frame
      93             :   /// comes from.
      94             :   ///
      95             :   /// This will usually be the string form of [uri], but a relative URI will be
      96             :   /// used if possible. Data URIs will be truncated.
      97             :   String get library {
      98           0 :     if (uri.scheme == 'data') return "data:...";
      99           0 :     return path.prettyUri(uri);
     100             :   }
     101             : 
     102             :   /// Returns the name of the package this stack frame comes from, or `null` if
     103             :   /// this stack frame doesn't come from a `package:` URL.
     104             :   String get package {
     105           0 :     if (uri.scheme != 'package') return null;
     106           0 :     return uri.path.split('/').first;
     107             :   }
     108             : 
     109             :   /// A human-friendly description of the code location.
     110             :   String get location {
     111           0 :     if (line == null) return library;
     112           0 :     if (column == null) return '$library $line';
     113           0 :     return '$library $line:$column';
     114             :   }
     115             : 
     116             :   /// Returns a single frame of the current stack.
     117             :   ///
     118             :   /// By default, this will return the frame above the current method. If
     119             :   /// [level] is `0`, it will return the current method's frame; if [level] is
     120             :   /// higher than `1`, it will return higher frames.
     121             :   factory Frame.caller([int level = 1]) {
     122           0 :     if (level < 0) {
     123           0 :       throw new ArgumentError("Argument [level] must be greater than or equal "
     124             :           "to 0.");
     125             :     }
     126             : 
     127           0 :     return new Trace.current(level + 1).frames.first;
     128             :   }
     129             : 
     130             :   /// Parses a string representation of a Dart VM stack frame.
     131           0 :   factory Frame.parseVM(String frame) => _catchFormatException(frame, () {
     132             :         // The VM sometimes folds multiple stack frames together and replaces them
     133             :         // with "...".
     134           0 :         if (frame == '...') {
     135           0 :           return new Frame(new Uri(), null, null, '...');
     136             :         }
     137             : 
     138           0 :         var match = _vmFrame.firstMatch(frame);
     139           0 :         if (match == null) return new UnparsedFrame(frame);
     140             : 
     141             :         // Get the pieces out of the regexp match. Function, URI and line should
     142             :         // always be found. The column is optional.
     143           0 :         var member = match[1]
     144           0 :             .replaceAll(_asyncBody, "<async>")
     145           0 :             .replaceAll("<anonymous closure>", "<fn>");
     146           0 :         var uri = Uri.parse(match[2]);
     147             : 
     148           0 :         var lineAndColumn = match[3].split(':');
     149             :         var line =
     150           0 :             lineAndColumn.length > 1 ? int.parse(lineAndColumn[1]) : null;
     151             :         var column =
     152           0 :             lineAndColumn.length > 2 ? int.parse(lineAndColumn[2]) : null;
     153           0 :         return new Frame(uri, line, column, member);
     154             :       });
     155             : 
     156             :   /// Parses a string representation of a Chrome/V8 stack frame.
     157           0 :   factory Frame.parseV8(String frame) => _catchFormatException(frame, () {
     158           0 :         var match = _v8Frame.firstMatch(frame);
     159           0 :         if (match == null) return new UnparsedFrame(frame);
     160             : 
     161             :         // v8 location strings can be arbitrarily-nested, since it adds a layer of
     162             :         // nesting for each eval performed on that line.
     163             :         parseLocation(location, member) {
     164           0 :           var evalMatch = _v8EvalLocation.firstMatch(location);
     165             :           while (evalMatch != null) {
     166           0 :             location = evalMatch[1];
     167           0 :             evalMatch = _v8EvalLocation.firstMatch(location);
     168             :           }
     169             : 
     170           0 :           if (location == 'native') {
     171           0 :             return new Frame(Uri.parse('native'), null, null, member);
     172             :           }
     173             : 
     174           0 :           var urlMatch = _v8UrlLocation.firstMatch(location);
     175           0 :           if (urlMatch == null) return new UnparsedFrame(frame);
     176             : 
     177           0 :           return new Frame(_uriOrPathToUri(urlMatch[1]), int.parse(urlMatch[2]),
     178           0 :               int.parse(urlMatch[3]), member);
     179             :         }
     180             : 
     181             :         // V8 stack frames can be in two forms.
     182           0 :         if (match[2] != null) {
     183             :           // The first form looks like " at FUNCTION (LOCATION)". V8 proper lists
     184             :           // anonymous functions within eval as "<anonymous>", while IE10 lists them
     185             :           // as "Anonymous function".
     186           0 :           return parseLocation(
     187           0 :               match[2],
     188           0 :               match[1]
     189           0 :                   .replaceAll("<anonymous>", "<fn>")
     190           0 :                   .replaceAll("Anonymous function", "<fn>")
     191           0 :                   .replaceAll("(anonymous function)", "<fn>"));
     192             :         } else {
     193             :           // The second form looks like " at LOCATION", and is used for anonymous
     194             :           // functions.
     195           0 :           return parseLocation(match[3], "<fn>");
     196             :         }
     197             :       });
     198             : 
     199             :   /// Parses a string representation of a JavaScriptCore stack trace.
     200           0 :   factory Frame.parseJSCore(String frame) => new Frame.parseV8(frame);
     201             : 
     202             :   /// Parses a string representation of an IE stack frame.
     203             :   ///
     204             :   /// IE10+ frames look just like V8 frames. Prior to IE10, stack traces can't
     205             :   /// be retrieved.
     206           0 :   factory Frame.parseIE(String frame) => new Frame.parseV8(frame);
     207             : 
     208             :   /// Parses a string representation of a Firefox stack frame.
     209           0 :   factory Frame.parseFirefox(String frame) => _catchFormatException(frame, () {
     210           0 :         var match = _firefoxSafariFrame.firstMatch(frame);
     211           0 :         if (match == null) return new UnparsedFrame(frame);
     212             : 
     213             :         // Normally this is a URI, but in a jsshell trace it can be a path.
     214           0 :         var uri = _uriOrPathToUri(match[3]);
     215             : 
     216             :         var member;
     217           0 :         if (match[1] != null) {
     218           0 :           member = match[1];
     219           0 :           member +=
     220           0 :               new List.filled('/'.allMatches(match[2]).length, ".<fn>").join();
     221           0 :           if (member == '') member = '<fn>';
     222             : 
     223             :           // Some Firefox members have initial dots. We remove them for consistency
     224             :           // with other platforms.
     225           0 :           member = member.replaceFirst(_initialDot, '');
     226             :         } else {
     227             :           member = '<fn>';
     228             :         }
     229             : 
     230           0 :         var line = match[4] == '' ? null : int.parse(match[4]);
     231             :         var column =
     232           0 :             match[5] == null || match[5] == '' ? null : int.parse(match[5]);
     233           0 :         return new Frame(uri, line, column, member);
     234             :       });
     235             : 
     236             :   /// Parses a string representation of a Safari 6.0 stack frame.
     237             :   @Deprecated("Use Frame.parseSafari instead.")
     238           0 :   factory Frame.parseSafari6_0(String frame) => new Frame.parseFirefox(frame);
     239             : 
     240             :   /// Parses a string representation of a Safari 6.1+ stack frame.
     241             :   @Deprecated("Use Frame.parseSafari instead.")
     242           0 :   factory Frame.parseSafari6_1(String frame) => new Frame.parseFirefox(frame);
     243             : 
     244             :   /// Parses a string representation of a Safari stack frame.
     245           0 :   factory Frame.parseSafari(String frame) => new Frame.parseFirefox(frame);
     246             : 
     247             :   /// Parses this package's string representation of a stack frame.
     248           0 :   factory Frame.parseFriendly(String frame) => _catchFormatException(frame, () {
     249           0 :         var match = _friendlyFrame.firstMatch(frame);
     250             :         if (match == null) {
     251           0 :           throw new FormatException(
     252           0 :               "Couldn't parse package:stack_trace stack trace line '$frame'.");
     253             :         }
     254             :         // Fake truncated data urls generated by the friendly stack trace format
     255             :         // cause Uri.parse to throw an exception so we have to special case them.
     256           0 :         var uri = match[1] == 'data:...'
     257           0 :             ? new Uri.dataFromString('')
     258           0 :             : Uri.parse(match[1]);
     259             :         // If there's no scheme, this is a relative URI. We should interpret it as
     260             :         // relative to the current working directory.
     261           0 :         if (uri.scheme == '') {
     262           0 :           uri = path.toUri(path.absolute(path.fromUri(uri)));
     263             :         }
     264             : 
     265           0 :         var line = match[2] == null ? null : int.parse(match[2]);
     266           0 :         var column = match[3] == null ? null : int.parse(match[3]);
     267           0 :         return new Frame(uri, line, column, match[4]);
     268             :       });
     269             : 
     270             :   /// A regular expression matching an absolute URI.
     271             :   static final _uriRegExp = new RegExp(r'^[a-zA-Z][-+.a-zA-Z\d]*://');
     272             : 
     273             :   /// A regular expression matching a Windows path.
     274             :   static final _windowsRegExp = new RegExp(r'^([a-zA-Z]:[\\/]|\\\\)');
     275             : 
     276             :   /// Converts [uriOrPath], which can be a URI, a Windows path, or a Posix path,
     277             :   /// to a URI (absolute if possible).
     278             :   static Uri _uriOrPathToUri(String uriOrPath) {
     279           0 :     if (uriOrPath.contains(_uriRegExp)) {
     280           0 :       return Uri.parse(uriOrPath);
     281           0 :     } else if (uriOrPath.contains(_windowsRegExp)) {
     282           0 :       return new Uri.file(uriOrPath, windows: true);
     283           0 :     } else if (uriOrPath.startsWith('/')) {
     284           0 :       return new Uri.file(uriOrPath, windows: false);
     285             :     }
     286             : 
     287             :     // As far as I've seen, Firefox and V8 both always report absolute paths in
     288             :     // their stack frames. However, if we do get a relative path, we should
     289             :     // handle it gracefully.
     290           0 :     if (uriOrPath.contains('\\')) return path.windows.toUri(uriOrPath);
     291           0 :     return Uri.parse(uriOrPath);
     292             :   }
     293             : 
     294             :   /// Runs [body] and returns its result.
     295             :   ///
     296             :   /// If [body] throws a [FormatException], returns an [UnparsedFrame] with
     297             :   /// [text] instead.
     298             :   static Frame _catchFormatException(String text, Frame body()) {
     299             :     try {
     300           0 :       return body();
     301           0 :     } on FormatException catch (_) {
     302           0 :       return new UnparsedFrame(text);
     303             :     }
     304             :   }
     305             : 
     306           0 :   Frame(this.uri, this.line, this.column, this.member);
     307             : 
     308           0 :   String toString() => '$location in $member';
     309             : }

Generated by: LCOV version 1.13