| // Copyright (c) 2018, 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 'problems.dart' show DebugAbort; | |
| import 'uri_offset.dart'; | |
| /// Tracks if there has been a crash reported through [reportCrash]. Should be | |
| /// reset between each compilation by calling [resetCrashReporting]. | |
| bool hasCrashed = false; | |
| /// Tracks the first source URI that has been read and is used as a fall-back | |
| /// for [reportCrash]. Should be reset between each compilation by calling | |
| /// [resetCrashReporting]. | |
| Uri? firstSourceUri; | |
| class Crash( | |
| final Uri? uri, | |
| final int? charOffset, | |
| final Object error, | |
| final StackTrace? trace, | |
| ) { | |
| bool _hasBeenReported = false; | |
| @override | |
| String toString() { | |
| StringBuffer sb = new StringBuffer(); | |
| if (uri != null) { | |
| sb.write("Crash when compiling $uri"); | |
| if (charOffset != null && charOffset != -1) { | |
| sb.write(" at character offset $charOffset:\n"); | |
| } else { | |
| sb.write(":\n"); | |
| } | |
| } else { | |
| sb.write("Crash when compiling:\n"); | |
| } | |
| sb.write(error); | |
| sb.write("\n"); | |
| return sb.toString(); | |
| } | |
| } | |
| void resetCrashReporting() { | |
| firstSourceUri = null; | |
| hasCrashed = false; | |
| } | |
| Future<T> reportCrash<T>(error, StackTrace trace, [Uri? uri, int? charOffset]) { | |
| if (hasCrashed) { | |
| // Coverage-ignore-block(suite): Not run. | |
| return new Future<T>.error(error, trace); | |
| } | |
| if (error is Crash) { | |
| // Coverage-ignore-block(suite): Not run. | |
| trace = error.trace ?? trace; | |
| uri = error.uri ?? uri; | |
| charOffset = error.charOffset ?? charOffset; | |
| error._hasBeenReported = true; | |
| error = error.error; | |
| } | |
| uri ??= firstSourceUri; | |
| hasCrashed = true; | |
| return new Future<T>.error( | |
| new Crash(uri, charOffset, error, trace).._hasBeenReported = true, | |
| trace, | |
| ); | |
| } | |
| // Coverage-ignore(suite): Not run. | |
| String safeToString(Object object) { | |
| try { | |
| return "$object"; | |
| } catch (e) { | |
| return "Error when converting ${object.runtimeType} to string."; | |
| } | |
| } | |
| Future<T> withCrashReporting<T>( | |
| Future<T> Function() action, | |
| UriOffset? Function() currentUriOffset, | |
| ) async { | |
| resetCrashReporting(); | |
| try { | |
| return await action(); | |
| } on DebugAbort { | |
| rethrow; | |
| } catch (e, s) { | |
| if (e is Crash && | |
| // Coverage-ignore(suite): Not run. | |
| e._hasBeenReported) { | |
| rethrow; | |
| } | |
| UriOffset? uriOffset = currentUriOffset(); | |
| return reportCrash(e, s, uriOffset?.fileUri, uriOffset?.fileOffset); | |
| } | |
| } |