| // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'dart:async'; |
| |
| import 'package:stack_trace/stack_trace.dart'; |
| |
| import 'class.dart'; |
| import 'instance.dart'; |
| import 'object.dart'; |
| import 'scope.dart'; |
| |
| VMErrorRef newVMErrorRef(Scope scope, Map json) { |
| if (json == null) return null; |
| assert(json["type"] == "@Error" || json["type"] == "Error"); |
| return new VMErrorRef._(scope, json); |
| } |
| |
| VMErrorRef newVMError(Scope scope, Map json) { |
| if (json == null) return null; |
| assert(json["type"] == "Error"); |
| return new VMError._(scope, json); |
| } |
| |
| /// A reference to a Dart language error. |
| class VMErrorRef implements VMObjectRef { |
| final Scope _scope; |
| |
| /// The ID for the error, which is unique relative to its isolate. |
| final String _id; |
| |
| /// Whether [_id] is guaranteed to be the same for different VM service error |
| /// objects that refer to the same error. |
| final bool _fixedId; |
| |
| Uri get observatoryUrl => _scope.observatoryUrlFor(_id); |
| |
| /// The kind of error this is. |
| final VMErrorKind kind; |
| |
| /// The error message. |
| final String message; |
| |
| VMErrorRef._(this._scope, Map json) |
| : _id = json["id"], |
| _fixedId = json["fixedId"] ?? false, |
| kind = new VMErrorKind._parse(json["kind"]), |
| message = json["message"]; |
| |
| Future<VMError> load() async => |
| new VMError._(_scope, await _scope.loadObject(_id)); |
| |
| bool operator ==(other) => other is VMErrorRef && |
| (_fixedId ? _id == other._id : super == other); |
| |
| int get hashCode => _fixedId ? _id.hashCode : super.hashCode; |
| |
| String toString() => "$kind: $message"; |
| } |
| |
| /// A Dart language error. |
| class VMError extends VMErrorRef implements VMObject { |
| final VMClassRef klass; |
| |
| final int size; |
| |
| /// The exception that caused the error. |
| /// |
| /// Note that for asynchonous errors prior to VM service version 3.0, this |
| /// may be a wrapped instance of [AsyncError]. |
| final VMInstanceRef exception; |
| |
| /// The stack trace for the error. |
| /// |
| /// This can be accessed as a local trace using [getTrace]. |
| /// |
| /// Note that for asynchonous errors prior to VM service version 3.0, |
| /// [exception] may be an instance of [AsyncError], in which case that error |
| /// contains the original stack trace. |
| final VMInstanceRef stackTrace; |
| |
| VMError._(Scope scope, Map json) |
| : klass = newVMClassRef(scope, json["class"]), |
| size = json["size"], |
| exception = newVMInstanceRef(scope, json["exception"]), |
| stackTrace = newVMInstanceRef(scope, json["stacktrace"]), |
| super._(scope, json); |
| |
| /// Loads the error's stack trace as a concrete Dart stack trace. |
| /// |
| /// If the original stack trace was a [Chain], this returns a [Chain]. |
| /// Otherwise, it returns a [Trace]. |
| Future<StackTrace> getTrace() async { |
| var vmTrace = stackTrace; |
| if (exception.klass.name == '_UncaughtAsyncError') { |
| vmTrace = (await exception.load()).fields['stackTrace'].value; |
| } |
| |
| if (vmTrace is VMStackTraceInstanceRef) return vmTrace.value; |
| |
| VMStringInstanceRef contents = await vmTrace.evaluate("toString()"); |
| if (contents.isValueTruncated) contents = await contents.load(); |
| return new Chain.parse(contents.value); |
| } |
| } |
| |
| /// An enum of different kinds of Dart errors. |
| class VMErrorKind { |
| /// A Dart exception with no handler. |
| static const unhandledException = const VMErrorKind._("UnhandledException"); |
| |
| /// An error caused by invalid Dart code. |
| static const languageError = const VMErrorKind._("LanguageError"); |
| |
| /// An internal error. |
| /// |
| /// These errors should not be exposed—if seen, they should be [reported as |
| /// bugs](https://github.com/dart-lang/sdk/issues/new). |
| static const internalError = const VMErrorKind._("InternalError"); |
| |
| /// The isolate has been terminated from an external source. |
| static const terminationError = const VMErrorKind._("TerminationError"); |
| |
| /// The name of the error. |
| final String name; |
| |
| /// Parses the error from its service protocol name. |
| factory VMErrorKind._parse(String name) { |
| switch (name) { |
| case "UnhandledException": return VMErrorKind.unhandledException; |
| case "LanguageError": return VMErrorKind.languageError; |
| case "InternalError": return VMErrorKind.internalError; |
| case "TerminationError": return VMErrorKind.terminationError; |
| default: throw new StateError("Unknown VM error kind \"$name\"."); |
| } |
| } |
| |
| const VMErrorKind._(this.name); |
| |
| String toString() => name; |
| } |