blob: fc3fcd73501c8f8cce8d282bc2ae4b6cb7acf4a7 [file] [edit]
// 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;
Crash(this.uri, this.charOffset, this.error, this.trace);
@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);
}
}