Reapply "When parts of the program are changed in a hot reload, but not executed during the reassemble, warn that a restart may be needed." (#12490)
This reverts commit 5e7bcbacf80875730b2002973b5d82cf5331c2a3.
`flutter run --benchmark` was triggering a different quick bailout path in the VM than `flutter run`. The failure has been fixed upstream.
diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart
index ef81678..40db37d 100644
--- a/packages/flutter_tools/lib/src/vmservice.dart
+++ b/packages/flutter_tools/lib/src/vmservice.dart
@@ -897,6 +897,24 @@
}
}
+// A function, field or class along with its source location.
+class ProgramElement {
+ ProgramElement(this.qualifiedName, this.uri, this.line, this.column);
+
+ final String qualifiedName;
+ final Uri uri;
+ final int line;
+ final int column;
+
+ @override
+ String toString() {
+ if (line == null)
+ return '$qualifiedName ($uri)';
+ else
+ return '$qualifiedName ($uri:$line)';
+ }
+}
+
/// An isolate running inside the VM. Instances of the Isolate class are always
/// canonicalized.
class Isolate extends ServiceObjectOwner {
@@ -1029,6 +1047,58 @@
}
}
+ Future<Map<String, dynamic>> getObject(Map<String, dynamic> objectRef) {
+ return invokeRpcRaw('getObject',
+ params: <String, dynamic>{'objectId': objectRef['id']});
+ }
+
+ Future<ProgramElement> _describeElement(Map<String, dynamic> elementRef) async {
+ String name = elementRef['name'];
+ Map<String, dynamic> owner = elementRef['owner'];
+ while (owner != null) {
+ final String ownerType = owner['type'];
+ if (ownerType == 'Library' || ownerType == '@Library')
+ break;
+ final String ownerName = owner['name'];
+ name = "$ownerName.$name";
+ owner = owner['owner'];
+ }
+
+ final Map<String, dynamic> fullElement = await getObject(elementRef);
+ final Map<String, dynamic> location = fullElement['location'];
+ final int tokenPos = location['tokenPos'];
+ final Map<String, dynamic> script = await getObject(location['script']);
+
+ // The engine's tag handler doesn't seem to create proper URIs.
+ Uri uri = Uri.parse(script['uri']);
+ if (uri.scheme == '')
+ uri = uri.replace(scheme: 'file');
+
+ // See https://github.com/dart-lang/sdk/blob/master/runtime/vm/service/service.md
+ for (List<int> lineTuple in script['tokenPosTable']) {
+ final int line = lineTuple[0];
+ for (int i = 1; i < lineTuple.length; i += 2) {
+ if (lineTuple[i] == tokenPos) {
+ final int column = lineTuple[i + 1];
+ return new ProgramElement(name, uri, line, column);
+ }
+ }
+ }
+ return new ProgramElement(name, uri, null, null);
+ }
+
+ // Lists program elements changed in the most recent reload that have not
+ // since executed.
+ Future<List<ProgramElement>> getUnusedChangesInLastReload() async {
+ final Map<String, dynamic> response =
+ await invokeRpcRaw('_getUnusedChangesInLastReload');
+ final List<Future<ProgramElement>> unusedElements =
+ <Future<ProgramElement>>[];
+ for (Map<String, dynamic> element in response['unused'])
+ unusedElements.add(_describeElement(element));
+ return Future.wait(unusedElements);
+ }
+
/// Resumes the isolate.
Future<Map<String, dynamic>> resume() {
return invokeRpcRaw('resume');