Version 2.14.0-289.0.dev
Merge commit 'd37dc1649b1cc3c0bb9ba347251923d081f54c59' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index fb51c91..204df98 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2021-06-24T14:38:26.203286",
+ "generated": "2021-07-02T15:48:57.033703",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -569,7 +569,7 @@
"name": "scrape",
"rootUri": "../pkg/scrape",
"packageUri": "lib/",
- "languageVersion": "2.10"
+ "languageVersion": "2.13"
},
{
"name": "sdk_library_metadata",
diff --git a/pkg/_fe_analyzer_shared/pubspec.yaml b/pkg/_fe_analyzer_shared/pubspec.yaml
index a0d6ba6..8b5f6ac 100644
--- a/pkg/_fe_analyzer_shared/pubspec.yaml
+++ b/pkg/_fe_analyzer_shared/pubspec.yaml
@@ -1,5 +1,5 @@
name: _fe_analyzer_shared
-version: 22.0.0
+version: 23.0.0
description: Logic that is shared between the front_end and analyzer packages.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/_fe_analyzer_shared
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index dfc8654..6ccdf32 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,4 +1,4 @@
-## 2.0.0-dev (Not yet released - breaking changes)
+## 2.0.0
* Removed deprecated `Scope.lookup2()`.
* Removed deprecated setters in API of AST.
* Removed deprecated `FunctionTypeAliasElement`.
@@ -11,8 +11,6 @@
* Changed `DartObject.type` from `ParameterizedType?` to `DartType?`.
* Changed `FunctionType` to implement `DartType`, not `ParameterizedType`.
* Removed `FunctionType.element` and `FunctionType.typeArguments`.
-
-## 1.8.0-dev
* Added `StringInterpolation.firstString` and `lastString`, to express
explicitly that there are always (possibly empty) strings as the first
and the last elements of an interpolation.
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 8d9ff79..d52b622 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 2.0.0-dev
+version: 2.0.0
description: This package provides a library that performs static analysis of Dart code.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
@@ -7,13 +7,13 @@
sdk: '>=2.12.0 <3.0.0'
dependencies:
- _fe_analyzer_shared: ^22.0.0
+ _fe_analyzer_shared: ^23.0.0
cli_util: ^0.3.0
collection: ^1.15.0
convert: ^3.0.0
crypto: ^3.0.0
glob: ^2.0.0
- meta: ^1.4.0
+ meta: ^1.7.0
package_config: ^2.0.0
path: ^1.8.0
pub_semver: ^2.0.0
diff --git a/pkg/dev_compiler/lib/src/kernel/asset_file_system.dart b/pkg/dev_compiler/lib/src/kernel/asset_file_system.dart
new file mode 100644
index 0000000..4d73fb2
--- /dev/null
+++ b/pkg/dev_compiler/lib/src/kernel/asset_file_system.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2021, 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.
+
+// @dart = 2.9
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:async/async.dart';
+import 'package:dev_compiler/src/kernel/retry_timeout_client.dart';
+import 'package:front_end/src/api_prototype/file_system.dart';
+import 'package:pedantic/pedantic.dart';
+
+/// A wrapper around asset server that redirects file read requests
+/// to http get requests to the asset server.
+class AssetFileSystem implements FileSystem {
+ FileSystem original;
+ final String server;
+ final String port;
+
+ AssetFileSystem(this.original, this.server, this.port);
+
+ /// Convert the uri to a server uri.
+ Uri _resourceUri(Uri uri) => Uri.parse('http://$server:$port/${uri.path}');
+
+ @override
+ FileSystemEntity entityForUri(Uri uri) {
+ if (uri.scheme == 'file') {
+ return original.entityForUri(uri);
+ }
+
+ // Pass the uri to the asset server in the debugger.
+ return AssetFileSystemEntity(this, _resourceUri(uri));
+ }
+}
+
+class AssetFileSystemEntity implements FileSystemEntity {
+ AssetFileSystem fileSystem;
+
+ @override
+ Uri uri;
+
+ AssetFileSystemEntity(this.fileSystem, this.uri);
+
+ @override
+ Future<bool> exists() async {
+ return _runWithClient((httpClient) async {
+ var response = await httpClient.headUrl(uri);
+ unawaited(_ignore(response));
+ return response.statusCode == HttpStatus.ok;
+ });
+ }
+
+ @override
+ Future<bool> existsAsyncIfPossible() => exists();
+
+ @override
+ Future<List<int>> readAsBytes() async {
+ return _runWithClient((httpClient) async {
+ var response = await httpClient.getUrl(uri);
+ if (response.statusCode != HttpStatus.ok) {
+ unawaited(_ignore(response));
+ throw FileSystemException(
+ uri, 'Asset rerver returned ${response.statusCode}');
+ }
+ return await collectBytes(response);
+ });
+ }
+
+ @override
+ Future<List<int>> readAsBytesAsyncIfPossible() => readAsBytes();
+
+ @override
+ Future<String> readAsString() async {
+ return _runWithClient((httpClient) async {
+ var response = await httpClient.getUrl(uri);
+ if (response.statusCode != HttpStatus.ok) {
+ unawaited(_ignore(response));
+ throw FileSystemException(
+ uri, 'Asset server returned ${response.statusCode}');
+ }
+ return await response.transform(utf8.decoder).join();
+ });
+ }
+
+ /// Execute the [body] with the new http client.
+ ///
+ /// Throws a [FileSystemException] on failure,
+ /// and cleans up the client on return or error.
+ Future<T> _runWithClient<T>(
+ Future<T> Function(RetryTimeoutClient httpClient) body) async {
+ RetryTimeoutClient httpClient;
+ try {
+ httpClient = RetryTimeoutClient(HttpClient(), retries: 4);
+ return await body(httpClient);
+ } on Exception catch (e, s) {
+ throw FileSystemException(uri, '$e:$s');
+ } finally {
+ httpClient?.close(force: true);
+ }
+ }
+
+ /// Make sure the response stream is listened to so that we don't leave
+ /// dangling connections, suppress errors.
+ Future<void> _ignore(HttpClientResponse response) {
+ return response
+ .listen((_) {}, cancelOnError: true)
+ .cancel()
+ .catchError((_) {});
+ }
+}
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
index a8b8b85..1cdbd66 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
@@ -21,9 +21,9 @@
show duplicateLibrariesReachable;
import 'package:kernel/target/targets.dart' show TargetFlags;
import 'package:meta/meta.dart';
-import 'package:vm/http_filesystem.dart';
import '../compiler/js_names.dart';
+import 'asset_file_system.dart';
import 'command.dart';
/// The service that handles expression compilation requests from
@@ -304,7 +304,8 @@
// Note that this doesn't actually re-load it if it's already fully loaded.
if (!await _loadAndUpdateComponent(
_fullModules[moduleName], moduleName, false)) {
- throw ArgumentError('Failed to load full dill for module $moduleName');
+ throw ArgumentError('Failed to load full dill for module $moduleName: '
+ '${_fullModules[moduleName]}');
}
var originalComponent = _moduleCache.componentForModuleName[moduleName];
@@ -568,29 +569,6 @@
}
}
-/// A wrapper around asset server that redirects file read requests
-/// to http get requests to the asset server.
-class AssetFileSystem extends HttpAwareFileSystem {
- final String server;
- final String port;
-
- AssetFileSystem(FileSystem original, this.server, this.port)
- : super(original);
-
- Uri resourceUri(Uri uri) =>
- Uri.parse('http://$server:$port/getResource?uri=${uri.toString()}');
-
- @override
- FileSystemEntity entityForUri(Uri uri) {
- if (uri.scheme == 'file') {
- return super.entityForUri(uri);
- }
-
- // Pass the uri to the asset server in the debugger.
- return HttpFileSystemEntity(this, resourceUri(uri));
- }
-}
-
/// Module cache used to load modules and look up loaded libraries.
///
/// After each build, the cache is updated with summaries for
diff --git a/pkg/dev_compiler/lib/src/kernel/retry_timeout_client.dart b/pkg/dev_compiler/lib/src/kernel/retry_timeout_client.dart
new file mode 100644
index 0000000..36a768e
--- /dev/null
+++ b/pkg/dev_compiler/lib/src/kernel/retry_timeout_client.dart
@@ -0,0 +1,114 @@
+// Copyright (c) 2021, 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.
+
+// @dart=2.9
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:math';
+
+import 'package:pedantic/pedantic.dart';
+
+/// An HTTP client wrapper that times out connections and requests and
+/// automatically retries failing requests.
+class RetryTimeoutClient {
+ /// The wrapped client.
+ final HttpClient _inner;
+
+ /// The number of times a request should be retried.
+ final int _retries;
+
+ /// The callback that determines whether a request should be retried.
+ final bool Function(HttpClientResponse) _when;
+
+ /// The callback that determines whether a request when an error is thrown.
+ final bool Function(Object, StackTrace) _whenError;
+
+ /// The callback that determines how long to wait before retrying a request.
+ final Duration Function(int) _delay;
+
+ /// The callback that determines when to cancel a connection.
+ final Duration Function(int) _connectionTimeout;
+
+ /// The callback that determines when to cancel a request.
+ final Duration Function(int) _reponseTimeout;
+
+ /// The callback to call to indicate that a request is being retried.
+ final void Function(Uri, HttpClientResponse, int) _onRetry;
+
+ /// Creates a client wrapping [_inner] that retries HTTP requests.
+ RetryTimeoutClient(
+ this._inner, {
+ int retries = 3,
+ bool Function(HttpClientResponse) when = _defaultWhen,
+ bool Function(Object, StackTrace) whenError = _defaultWhenError,
+ Duration Function(int retryCount) delay = _defaultDelay,
+ Duration Function(int retryCount) connectionTimeout = _defaultTimeout,
+ Duration Function(int retryCount) responseTimeout = _defaultTimeout,
+ void Function(Uri, HttpClientResponse, int retryCount) onRetry,
+ }) : _retries = retries,
+ _when = when,
+ _whenError = whenError,
+ _delay = delay,
+ _connectionTimeout = connectionTimeout,
+ _reponseTimeout = responseTimeout,
+ _onRetry = onRetry {
+ RangeError.checkNotNegative(_retries, 'retries');
+ }
+
+ Future<HttpClientResponse> headUrl(Uri url) {
+ return _retry(url, _inner.headUrl);
+ }
+
+ Future<HttpClientResponse> getUrl(Uri url) {
+ return _retry(url, _inner.getUrl);
+ }
+
+ Future<HttpClientResponse> _retry(
+ Uri url, Future<HttpClientRequest> Function(Uri) method) async {
+ var i = 0;
+ for (;;) {
+ HttpClientResponse response;
+ try {
+ _inner.connectionTimeout = _connectionTimeout(i);
+ var request = await method(url).timeout(
+ _reponseTimeout(i),
+ onTimeout: () =>
+ throw TimeoutException('$url, retry:$i', _reponseTimeout(i)),
+ );
+ response = await request.close();
+ } catch (error, stackTrace) {
+ if (i == _retries || !_whenError(error, stackTrace)) rethrow;
+ }
+
+ if (response != null) {
+ if (i == _retries || !_when(response)) return response;
+
+ // Make sure the response stream is listened to so that we don't leave
+ // dangling connections.
+ unawaited(response.listen((_) {}).cancel().catchError((_) {}));
+ }
+
+ await Future.delayed(_delay(i));
+ _onRetry?.call(url, response, i);
+ i++;
+ }
+ }
+
+ void close({bool force = false}) => _inner.close(force: force);
+}
+
+bool _defaultWhen(HttpClientResponse response) => response.statusCode == 503;
+
+bool _defaultWhenError(Object error, StackTrace stackTrace) =>
+ error is OSError ||
+ error is HttpException ||
+ error is SocketException ||
+ error is TimeoutException;
+
+Duration _defaultDelay(int retryCount) =>
+ const Duration(milliseconds: 500) * pow(1.5, retryCount);
+
+Duration _defaultTimeout(int retryCount) =>
+ const Duration(milliseconds: 5000) * pow(1.5, retryCount);
diff --git a/pkg/dev_compiler/pubspec.yaml b/pkg/dev_compiler/pubspec.yaml
index b0f3974..89ca585 100644
--- a/pkg/dev_compiler/pubspec.yaml
+++ b/pkg/dev_compiler/pubspec.yaml
@@ -11,6 +11,7 @@
_js_interop_checks:
path: ../_js_interop_checks
args: any
+ async: any
bazel_worker: any
build_integration:
path: ../build_integration
@@ -22,10 +23,9 @@
meta:
path: ../meta
path: any
+ pedantic: ^1.11.0
source_maps: any
source_span: any
- vm:
- path: ../vm
dev_dependencies:
browser_launcher: ^0.1.9
@@ -38,7 +38,6 @@
modular_test:
path: ../modular_test
package_config: any
- pedantic: ^1.11.0
sourcemap_testing:
path: ../sourcemap_testing
stack_trace: any
@@ -47,5 +46,7 @@
test: any
testing:
path: ../testing
+ vm:
+ path: ../vm
webkit_inspection_protocol: ^0.7.4
diff --git a/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart b/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart
index a3483ed..a11668a 100644
--- a/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart
@@ -9,7 +9,7 @@
import 'dart:io' show HttpServer;
import 'package:browser_launcher/browser_launcher.dart';
-import 'package:dev_compiler/src/kernel/expression_compiler_worker.dart';
+import 'package:dev_compiler/src/kernel/asset_file_system.dart';
import 'package:front_end/src/api_prototype/file_system.dart';
import 'package:front_end/src/api_prototype/standard_file_system.dart';
import 'package:http_multi_server/http_multi_server.dart';
@@ -17,16 +17,18 @@
import 'package:shelf/shelf_io.dart';
import 'package:test/test.dart';
-const _existingFile = 'http://localhost/existingFile';
-const _nonExistingFile = 'http://localhost/nonExistingFile';
+const _existingFile = 'existingFile';
+const _nonExistingFile = 'nonExistingFile';
const _smallFileContents = 'Hello world!';
+List<int> _smallFileBytes = utf8.encode(_smallFileContents);
String _largeFileContents() =>
- List.filled(10000, _smallFileContents).join('/n');
+ List.filled(10000, _smallFileContents).join('\n');
+List<int> _largeFileBytes() => utf8.encode(_largeFileContents());
FutureOr<Response> handler(Request request) {
- final uri = request.requestedUri.queryParameters['uri'];
+ final uri = request.requestedUri;
final headers = {
'content-length': '${utf8.encode(_smallFileContents).length}',
...request.headers,
@@ -34,21 +36,21 @@
if (request.method == 'HEAD') {
// 'exists'
- return uri == _existingFile
+ return uri.pathSegments.last == _existingFile
? Response.ok(null, headers: headers)
- : Response.notFound(uri);
+ : Response.notFound(uri.toString());
}
if (request.method == 'GET') {
// 'readAsBytes'
- return uri == _existingFile
+ return uri.pathSegments.last == _existingFile
? Response.ok(_smallFileContents, headers: headers)
- : Response.notFound(uri);
+ : Response.notFound(uri.toString());
}
return Response.internalServerError();
}
FutureOr<Response> noisyHandler(Request request) {
- final uri = request.requestedUri.queryParameters['uri'];
+ final uri = request.requestedUri;
final contents = _largeFileContents();
final headers = {
'content-length': '${utf8.encode(contents).length}',
@@ -57,9 +59,9 @@
if (request.method == 'HEAD' || request.method == 'GET') {
// 'exists' or 'readAsBytes'
- return uri == _existingFile
+ return uri.pathSegments.last == _existingFile
? Response.ok(contents, headers: headers)
- : Response.notFound(uri);
+ : Response.notFound(uri.toString());
}
return Response.internalServerError();
}
@@ -93,16 +95,37 @@
expect(await entity.exists(), false);
});
- test('can read existing file', () async {
+ test('can read existing file using readAsBytes', () async {
+ var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
+ expect(await entity.readAsBytes(), _smallFileBytes);
+ });
+
+ test('can read and decode existing file using readAsBytes', () async {
var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
expect(utf8.decode(await entity.readAsBytes()), _smallFileContents);
});
+ test('can read existing file using readAsString', () async {
+ var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
+ expect(await entity.readAsString(), _smallFileContents);
+ });
+
test('cannot read non-existing file', () async {
var entity = fileSystem.entityForUri(Uri.parse(_nonExistingFile));
await expectLater(
entity.readAsBytes(), throwsA(isA<FileSystemException>()));
});
+
+ test('can read a lot of files concurrently', () async {
+ var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
+ var futures = [
+ for (var i = 0; i < 512; i++) entity.readAsBytes(),
+ ];
+ var results = await Future.wait(futures);
+ for (var result in results) {
+ expect(utf8.decode(result), _smallFileContents);
+ }
+ }, timeout: const Timeout.factor(2));
});
group('AssetFileSystem with a noisy server', () {
@@ -131,15 +154,57 @@
expect(await entity.exists(), false);
});
- test('can read existing file', () async {
+ test('can read existing file using readAsBytes', () async {
+ var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
+ expect(await entity.readAsBytes(), _largeFileBytes());
+ });
+
+ test('can read and decode existing file using readAsBytes', () async {
var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
expect(utf8.decode(await entity.readAsBytes()), _largeFileContents());
});
+ test('can read existing file using readAsString', () async {
+ var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
+ expect(await entity.readAsString(), _largeFileContents());
+ });
+
test('cannot read non-existing file', () async {
var entity = fileSystem.entityForUri(Uri.parse(_nonExistingFile));
await expectLater(
entity.readAsBytes(), throwsA(isA<FileSystemException>()));
});
+
+ test('readAsString is faster than decoding result of readAsBytes',
+ () async {
+ var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
+
+ var elapsedReadAsString = () async {
+ var stopwatch = Stopwatch()..start();
+ await expectLater(entity.readAsString(), isNotNull);
+ return stopwatch.elapsedMilliseconds;
+ };
+
+ var elapsedReadAsBytesAndDecode = () async {
+ var stopwatch = Stopwatch()..start();
+ await expectLater(utf8.decode(await entity.readAsBytes()), isNotNull);
+ return stopwatch.elapsedMilliseconds;
+ };
+
+ await expectLater(await elapsedReadAsString(),
+ lessThan(await elapsedReadAsBytesAndDecode()));
+ });
+
+ test('can read a lot of files concurrently', () async {
+ var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
+ var futures = [
+ for (var i = 0; i < 512; i++) entity.readAsBytes(),
+ ];
+ var results = await Future.wait(futures);
+ var fileContents = _largeFileContents();
+ for (var result in results) {
+ expect(utf8.decode(result), fileContents);
+ }
+ }, timeout: const Timeout.factor(2));
});
}
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
index 7141bb4..9a06c77 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
@@ -6,20 +6,510 @@
import 'dart:async';
import 'dart:convert';
-import 'dart:io' show Directory, File, Platform, Process, stderr, stdout;
+import 'dart:io'
+ show Directory, File, HttpServer, Platform, Process, stderr, stdout;
import 'dart:isolate';
+import 'package:browser_launcher/browser_launcher.dart';
import 'package:build_integration/file_system/multi_root.dart';
+import 'package:dev_compiler/src/kernel/asset_file_system.dart';
import 'package:dev_compiler/src/kernel/expression_compiler_worker.dart';
+import 'package:front_end/src/api_prototype/file_system.dart';
import 'package:front_end/src/api_prototype/standard_file_system.dart';
import 'package:front_end/src/compute_platform_binaries_location.dart';
+import 'package:http_multi_server/http_multi_server.dart';
import 'package:path/path.dart' as p;
import 'package:pedantic/pedantic.dart';
+import 'package:shelf/shelf.dart';
+import 'package:shelf/shelf_io.dart';
import 'package:test/test.dart';
/// Verbose mode for debugging
bool get verbose => false;
+void main() async {
+ for (var moduleFormat in ['amd', 'ddc']) {
+ group('$moduleFormat module format -', () {
+ for (var soundNullSafety in [true, false]) {
+ group('${soundNullSafety ? "sound" : "unsound"} null safety -', () {
+ group('expression compiler worker on startup', () {
+ Directory tempDir;
+ ReceivePort receivePort;
+
+ setUp(() async {
+ tempDir = Directory.systemTemp.createTempSync('foo bar');
+ receivePort = ReceivePort();
+ });
+
+ tearDown(() async {
+ tempDir.deleteSync(recursive: true);
+ receivePort.close();
+ });
+
+ test('reports failure to consumer', () async {
+ expect(
+ receivePort,
+ emitsInOrder([
+ equals(isA<SendPort>()),
+ equals({
+ 'succeeded': false,
+ 'stackTrace': isNotNull,
+ 'exception': contains('Could not load SDK component'),
+ }),
+ ]));
+
+ try {
+ var badPath = 'file:///path/does/not/exist';
+ await ExpressionCompilerWorker.createAndStart(
+ [
+ '--libraries-file',
+ badPath,
+ '--dart-sdk-summary',
+ badPath,
+ '--module-format',
+ moduleFormat,
+ soundNullSafety
+ ? '--sound-null-safety'
+ : '--no-sound-null-safety',
+ if (verbose) '--verbose',
+ ],
+ sendPort: receivePort.sendPort,
+ );
+ } catch (e) {
+ throwsA(contains('Could not load SDK component'));
+ }
+ });
+ });
+
+ group('reading assets using standard file system - ', () {
+ runExpressionCompilationTests(
+ StandardFileSystemTestDriver(soundNullSafety, moduleFormat));
+ });
+
+ group('reading assets using multiroot file system - ', () {
+ runExpressionCompilationTests(
+ MultiRootFileSystemTestDriver(soundNullSafety, moduleFormat));
+ });
+
+ group('reading assets using asset file system -', () {
+ runExpressionCompilationTests(
+ AssetFileSystemTestDriver(soundNullSafety, moduleFormat));
+ });
+ });
+ }
+ });
+ }
+}
+
+void runExpressionCompilationTests(TestDriver driver) {
+ group('expression compiler worker', () {
+ setUpAll(() async {
+ await driver.setUpAll();
+ });
+
+ tearDownAll(() async {
+ await driver.tearDownAll();
+ });
+
+ setUp(() async {
+ await driver.setUp();
+ });
+
+ tearDown(() async {
+ await driver.tearDown();
+ });
+
+ test('can compile expressions in sdk', () async {
+ driver.requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': driver.inputs,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'other',
+ 'line': 107,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'other': 'other'},
+ 'libraryUri': 'dart:collection',
+ 'moduleName': 'dart_sdk',
+ });
+
+ expect(
+ driver.responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure': contains('return other;'),
+ })
+ ]));
+ }, skip: 'Evaluating expressions in SDK is not supported yet');
+
+ test('can compile expressions in a library', () async {
+ driver.requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': driver.inputs,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'formal',
+ 'line': 5,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'formal': 'formal'},
+ 'libraryUri': driver.config.testModule.libraryUri,
+ 'moduleName': driver.config.testModule.moduleName,
+ });
+
+ expect(
+ driver.responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure': contains('return formal;'),
+ })
+ ]));
+ });
+
+ test('can compile expressions in main', () async {
+ driver.requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': driver.inputs,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'count',
+ 'line': 9,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'count': 'count'},
+ 'libraryUri': driver.config.mainModule.libraryUri,
+ 'moduleName': driver.config.mainModule.moduleName,
+ });
+
+ expect(
+ driver.responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure': contains('return count;'),
+ })
+ ]));
+ });
+
+ test('can compile expressions in main (extension method)', () async {
+ driver.requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': driver.inputs,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'ret',
+ 'line': 19,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'ret': 'ret'},
+ 'libraryUri': driver.config.mainModule.libraryUri,
+ 'moduleName': driver.config.mainModule.moduleName,
+ });
+
+ expect(
+ driver.responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure': contains('return ret;'),
+ })
+ ]));
+ });
+
+ test('can compile transitive expressions in main', () async {
+ driver.requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': driver.inputs,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'B().c().getNumber()',
+ 'line': 9,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {},
+ 'libraryUri': driver.config.mainModule.libraryUri,
+ 'moduleName': driver.config.mainModule.moduleName,
+ });
+
+ expect(
+ driver.responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure':
+ contains('new test_library.B.new().c().getNumber()'),
+ })
+ ]));
+ });
+
+ test('can compile series of expressions in various libraries', () async {
+ driver.requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': driver.inputs,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'B().c().getNumber()',
+ 'line': 8,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {},
+ 'libraryUri': driver.config.mainModule.libraryUri,
+ 'moduleName': driver.config.mainModule.moduleName,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'formal',
+ 'line': 5,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'formal': 'formal'},
+ 'libraryUri': driver.config.testModule.libraryUri,
+ 'moduleName': driver.config.testModule.moduleName,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'formal',
+ 'line': 3,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'formal': 'formal'},
+ 'libraryUri': driver.config.testModule2.libraryUri,
+ 'moduleName': driver.config.testModule2.moduleName,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'formal',
+ 'line': 3,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'formal': 'formal'},
+ 'libraryUri': driver.config.testModule3.libraryUri,
+ 'moduleName': driver.config.testModule3.moduleName,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'B().printNumber()',
+ 'line': 9,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {},
+ 'libraryUri': driver.config.mainModule.libraryUri,
+ 'moduleName': driver.config.mainModule.moduleName,
+ });
+
+ expect(
+ driver.responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure':
+ contains('new test_library.B.new().c().getNumber()'),
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure': contains('return formal;'),
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure': contains('return formal;'),
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure': contains('return formal;'),
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure':
+ contains('test_library.B.new().printNumber()'),
+ })
+ ]));
+ });
+
+ test('can compile after dependency update', () async {
+ driver.requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': driver.inputs,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'B().c().getNumber()',
+ 'line': 8,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {},
+ 'libraryUri': driver.config.mainModule.libraryUri,
+ 'moduleName': driver.config.mainModule.moduleName,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'formal',
+ 'line': 5,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'formal': 'formal'},
+ 'libraryUri': driver.config.testModule.libraryUri,
+ 'moduleName': driver.config.testModule.moduleName,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'B().printNumber()',
+ 'line': 9,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {},
+ 'libraryUri': driver.config.mainModule.libraryUri,
+ 'moduleName': driver.config.mainModule.moduleName,
+ });
+
+ driver.requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': driver.inputs,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'B().c().getNumber()',
+ 'line': 8,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {},
+ 'libraryUri': driver.config.mainModule.libraryUri,
+ 'moduleName': driver.config.mainModule.moduleName,
+ });
+
+ driver.requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'formal',
+ 'line': 3,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'formal': 'formal'},
+ 'libraryUri': driver.config.testModule3.libraryUri,
+ 'moduleName': driver.config.testModule3.moduleName,
+ });
+
+ expect(
+ driver.responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure':
+ contains('new test_library.B.new().c().getNumber()'),
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure': contains('return formal;'),
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure':
+ contains('test_library.B.new().printNumber()'),
+ }),
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure':
+ contains('new test_library.B.new().c().getNumber()'),
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'infos': isEmpty,
+ 'compiledProcedure': contains('return formal;'),
+ }),
+ ]));
+ });
+ });
+}
+
class ModuleConfiguration {
final Uri root;
final String outputDir;
@@ -38,9 +528,18 @@
this.fullDillFileName,
this.summaryDillFileName});
- Uri get jsPath => root.resolve('$outputDir/$jsFileName');
- Uri get fullDillPath => root.resolve('$outputDir/$fullDillFileName');
- Uri get summaryDillPath => root.resolve('$outputDir/$summaryDillFileName');
+ Uri get jsUri => root.resolve('$outputDir/$jsFileName');
+ Uri get multiRootFullDillUri =>
+ Uri.parse('org-dartlang-app:///$outputDir/$fullDillFileName');
+ Uri get multiRootSummaryUri =>
+ Uri.parse('org-dartlang-app:///$outputDir/$summaryDillFileName');
+
+ Uri get relativeFullDillUri => Uri.parse('$outputDir/$fullDillFileName');
+ Uri get realtiveSummaryUri => Uri.parse('$outputDir/$summaryDillFileName');
+
+ String get fullDillPath => root.resolve('$outputDir/$fullDillFileName').path;
+ String get summaryDillPath =>
+ root.resolve('$outputDir/$summaryDillFileName').path;
}
class TestProjectConfiguration {
@@ -102,6 +601,75 @@
: sdkRoot.resolve('ddc_sdk.dill');
Uri get librariesPath => sdkRoot.resolve('lib/libraries.json');
+ List get inputUris => [
+ {
+ 'path': '${mainModule.multiRootFullDillUri}',
+ 'summaryPath': '${mainModule.multiRootSummaryUri}',
+ 'moduleName': mainModule.moduleName
+ },
+ {
+ 'path': '${testModule.multiRootFullDillUri}',
+ 'summaryPath': '${testModule.multiRootSummaryUri}',
+ 'moduleName': testModule.moduleName
+ },
+ {
+ 'path': '${testModule2.multiRootFullDillUri}',
+ 'summaryPath': '${testModule2.multiRootSummaryUri}',
+ 'moduleName': testModule2.moduleName
+ },
+ {
+ 'path': '${testModule3.multiRootFullDillUri}',
+ 'summaryPath': '${testModule3.multiRootSummaryUri}',
+ 'moduleName': testModule3.moduleName
+ },
+ ];
+
+ List get inputRelativeUris => [
+ {
+ 'path': '${mainModule.multiRootFullDillUri}',
+ 'summaryPath': '${mainModule.multiRootSummaryUri}',
+ 'moduleName': mainModule.moduleName
+ },
+ {
+ 'path': '${testModule.multiRootFullDillUri}',
+ 'summaryPath': '${testModule.multiRootSummaryUri}',
+ 'moduleName': testModule.moduleName
+ },
+ {
+ 'path': '${testModule2.multiRootFullDillUri}',
+ 'summaryPath': '${testModule2.multiRootSummaryUri}',
+ 'moduleName': testModule2.moduleName
+ },
+ {
+ 'path': '${testModule3.multiRootFullDillUri}',
+ 'summaryPath': '${testModule3.multiRootSummaryUri}',
+ 'moduleName': testModule3.moduleName
+ },
+ ];
+
+ List get inputPaths => [
+ {
+ 'path': mainModule.fullDillPath,
+ 'summaryPath': mainModule.summaryDillPath,
+ 'moduleName': mainModule.moduleName
+ },
+ {
+ 'path': testModule.fullDillPath,
+ 'summaryPath': testModule.summaryDillPath,
+ 'moduleName': testModule.moduleName
+ },
+ {
+ 'path': testModule2.fullDillPath,
+ 'summaryPath': testModule2.summaryDillPath,
+ 'moduleName': testModule2.moduleName
+ },
+ {
+ 'path': testModule3.fullDillPath,
+ 'summaryPath': testModule3.summaryDillPath,
+ 'moduleName': testModule3.moduleName
+ },
+ ];
+
void createTestProject() {
var pubspec = root.resolve('pubspec.yaml');
File.fromUri(pubspec)
@@ -211,539 +779,171 @@
}
}
-void main() async {
- for (var moduleFormat in ['amd', 'ddc']) {
- group('$moduleFormat module format -', () {
- for (var soundNullSafety in [true, false]) {
- group('${soundNullSafety ? "sound" : "unsound"} null safety -', () {
- group('expression compiler worker on startup', () {
- Directory tempDir;
- ReceivePort receivePort;
+abstract class TestDriver {
+ final bool soundNullSafety;
+ final String moduleFormat;
- setUp(() async {
- tempDir = Directory.systemTemp.createTempSync('foo bar');
- receivePort = ReceivePort();
- });
+ FileSystem fileSystem;
+ FileSystem assetFileSystem;
- tearDown(() async {
- tempDir.deleteSync(recursive: true);
- receivePort.close();
- });
+ Directory tempDir;
+ TestProjectConfiguration config;
+ List inputs;
- test('reports failure to consumer', () async {
- expect(
- receivePort,
- emitsInOrder([
- equals(isA<SendPort>()),
- equals({
- 'succeeded': false,
- 'stackTrace': isNotNull,
- 'exception': contains('Could not load SDK component'),
- }),
- ]));
+ StreamController<Map<String, dynamic>> requestController;
+ StreamController<Map<String, dynamic>> responseController;
+ ExpressionCompilerWorker worker;
+ Future<void> workerDone;
- try {
- var badPath = 'file:///path/does/not/exist';
- await ExpressionCompilerWorker.createAndStart(
- [
- '--libraries-file',
- badPath,
- '--dart-sdk-summary',
- badPath,
- '--module-format',
- moduleFormat,
- soundNullSafety
- ? '--sound-null-safety'
- : '--no-sound-null-safety',
- if (verbose) '--verbose',
- ],
- sendPort: receivePort.sendPort,
- );
- } catch (e) {
- throwsA(contains('Could not load SDK component'));
- }
- });
- });
+ TestDriver(this.soundNullSafety, this.moduleFormat);
- for (var summarySupport in [true, false]) {
- group('${summarySupport ? "" : "no "}debugger summary support -',
- () {
- group('expression compiler worker', () {
- ExpressionCompilerWorker worker;
- Future workerDone;
- StreamController<Map<String, dynamic>> requestController;
- StreamController<Map<String, dynamic>> responseController;
- Directory tempDir;
- TestProjectConfiguration config;
- List inputs;
+ /// Initialize file systems, inputs, and start servers if needed.
+ Future<void> start();
- setUpAll(() async {
- tempDir = Directory.systemTemp.createTempSync('foo bar');
- config = TestProjectConfiguration(
- tempDir, soundNullSafety, moduleFormat);
+ Future<void> stop() => workerDone;
- // simulate webdev
- config.createTestProject();
- var kernelGenerator = DDCKernelGenerator(config);
- await kernelGenerator.generate();
+ Future<void> setUpAll() async {
+ tempDir = Directory.systemTemp.createTempSync('foo bar');
+ config = TestProjectConfiguration(tempDir, soundNullSafety, moduleFormat);
- inputs = [
- {
- 'path': config.mainModule.fullDillPath.path,
- if (summarySupport)
- 'summaryPath': config.mainModule.summaryDillPath.path,
- 'moduleName': config.mainModule.moduleName
- },
- {
- 'path': config.testModule.fullDillPath.path,
- if (summarySupport)
- 'summaryPath': config.testModule.summaryDillPath.path,
- 'moduleName': config.testModule.moduleName
- },
- {
- 'path': config.testModule2.fullDillPath.path,
- if (summarySupport)
- 'summaryPath': config.testModule2.summaryDillPath.path,
- 'moduleName': config.testModule2.moduleName
- },
- {
- 'path': config.testModule3.fullDillPath.path,
- if (summarySupport)
- 'summaryPath': config.testModule3.summaryDillPath.path,
- 'moduleName': config.testModule3.moduleName
- },
- ];
- });
+ await start();
- tearDownAll(() async {
- tempDir.deleteSync(recursive: true);
- });
+ // Build the project.
+ config.createTestProject();
+ var kernelGenerator = DDCKernelGenerator(config);
+ await kernelGenerator.generate();
+ }
- setUp(() async {
- var fileSystem = MultiRootFileSystem('org-dartlang-app',
- [tempDir.uri], StandardFileSystem.instance);
+ Future<void> tearDownAll() async {
+ await stop();
+ tempDir.deleteSync(recursive: true);
+ }
- requestController = StreamController<Map<String, dynamic>>();
- responseController = StreamController<Map<String, dynamic>>();
- worker = await ExpressionCompilerWorker.create(
- librariesSpecificationUri: config.librariesPath,
- // We should be able to load everything from dill and not
- // require source parsing. Webdev and google3 integration
- // currently rely on that. Make the test fail on source
- // reading by not providing a packages file.
- packagesFile: null,
- sdkSummary: config.sdkSummaryPath,
- fileSystem: fileSystem,
- requestStream: requestController.stream,
- sendResponse: responseController.add,
- soundNullSafety: soundNullSafety,
- verbose: verbose,
- );
- workerDone = worker.start();
- });
+ Future<void> setUp() async {
+ requestController = StreamController<Map<String, dynamic>>();
+ responseController = StreamController<Map<String, dynamic>>();
+ worker = await ExpressionCompilerWorker.create(
+ librariesSpecificationUri: config.librariesPath,
+ // We should be able to load everything from dill and not
+ // require source parsing. Webdev and google3 integration
+ // currently rely on that. Make the test fail on source
+ // reading by not providing a packages file.
+ packagesFile: null,
+ sdkSummary: config.sdkSummaryPath,
+ fileSystem: assetFileSystem,
+ requestStream: requestController.stream,
+ sendResponse: responseController.add,
+ soundNullSafety: soundNullSafety,
+ verbose: verbose,
+ );
+ workerDone = worker.start();
+ }
- tearDown(() async {
- unawaited(requestController.close());
- await workerDone;
- unawaited(responseController.close());
- });
+ Future<void> tearDown() async {
+ unawaited(requestController.close());
+ await workerDone;
+ unawaited(responseController.close());
+ }
+}
- test('can compile expressions in sdk', () async {
- requestController.add({
- 'command': 'UpdateDeps',
- 'inputs': inputs,
- });
+class StandardFileSystemTestDriver extends TestDriver {
+ StandardFileSystemTestDriver(bool soundNullSafety, String moduleFormat)
+ : super(soundNullSafety, moduleFormat);
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'other',
- 'line': 107,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {'other': 'other'},
- 'libraryUri': 'dart:collection',
- 'moduleName': 'dart_sdk',
- });
+ @override
+ Future<void> start() async {
+ inputs = config.inputPaths;
+ fileSystem = MultiRootFileSystem(
+ 'org-dartlang-app', [tempDir.uri], StandardFileSystem.instance);
+ assetFileSystem = StandardFileSystem.instance;
+ }
+}
- expect(
- responseController.stream,
- emitsInOrder([
- equals({
- 'succeeded': true,
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains('return other;'),
- })
- ]));
- }, skip: 'Evaluating expressions in SDK is not supported yet');
+class MultiRootFileSystemTestDriver extends TestDriver {
+ MultiRootFileSystemTestDriver(bool soundNullSafety, String moduleFormat)
+ : super(soundNullSafety, moduleFormat);
- test('can compile expressions in a library', () async {
- requestController.add({
- 'command': 'UpdateDeps',
- 'inputs': inputs,
- });
+ @override
+ Future<void> start() async {
+ inputs = config.inputUris;
+ fileSystem = MultiRootFileSystem(
+ 'org-dartlang-app', [tempDir.uri], StandardFileSystem.instance);
+ assetFileSystem = fileSystem;
+ }
+}
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'formal',
- 'line': 5,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {'formal': 'formal'},
- 'libraryUri': config.testModule.libraryUri,
- 'moduleName': config.testModule.moduleName,
- });
+class AssetFileSystemTestDriver extends TestDriver {
+ TestAssetServer server;
+ int port;
- expect(
- responseController.stream,
- emitsInOrder([
- equals({
- 'succeeded': true,
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains('return formal;'),
- })
- ]));
- });
+ AssetFileSystemTestDriver(bool soundNullSafety, String moduleFormat)
+ : super(soundNullSafety, moduleFormat);
- test('can compile expressions in main', () async {
- requestController.add({
- 'command': 'UpdateDeps',
- 'inputs': inputs,
- });
+ @override
+ Future<void> start() async {
+ inputs = config.inputRelativeUris;
+ fileSystem = MultiRootFileSystem(
+ 'org-dartlang-app', [tempDir.uri], StandardFileSystem.instance);
+ port = await findUnusedPort();
+ server = TestAssetServer(fileSystem);
+ assetFileSystem = AssetFileSystem(fileSystem, 'localhost', '$port');
+ await server.start('localhost', port);
+ }
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'count',
- 'line': 9,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {'count': 'count'},
- 'libraryUri': config.mainModule.libraryUri,
- 'moduleName': config.mainModule.moduleName,
- });
+ @override
+ Future<void> stop() async {
+ server.stop();
+ await super.stop();
+ }
+}
- expect(
- responseController.stream,
- emitsInOrder([
- equals({
- 'succeeded': true,
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains('return count;'),
- })
- ]));
- });
+class TestAssetServer {
+ FileSystem fileSystem;
+ HttpServer server;
- test('can compile expressions in main (extension method)',
- () async {
- requestController.add({
- 'command': 'UpdateDeps',
- 'inputs': inputs,
- });
+ TestAssetServer(this.fileSystem);
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'ret',
- 'line': 19,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {'ret': 'ret'},
- 'libraryUri': config.mainModule.libraryUri,
- 'moduleName': config.mainModule.moduleName,
- });
+ FutureOr<Response> handler(Request request) async {
+ var requested = request.requestedUri.path;
+ final uri = Uri.parse('org-dartlang-app:/$requested');
- expect(
- responseController.stream,
- emitsInOrder([
- equals({
- 'succeeded': true,
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains('return ret;'),
- })
- ]));
- });
+ assert(requested.startsWith('/'));
+ final path = requested.substring(1);
- test('can compile transitive expressions in main', () async {
- requestController.add({
- 'command': 'UpdateDeps',
- 'inputs': inputs,
- });
+ try {
+ var entity = fileSystem.entityForUri(uri);
+ if (await entity.existsAsyncIfPossible()) {
+ if (request.method == 'HEAD') {
+ var headers = {
+ 'content-length': null,
+ ...request.headers,
+ };
+ return Response.ok(null, headers: headers);
+ }
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'B().c().getNumber()',
- 'line': 9,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {},
- 'libraryUri': config.mainModule.libraryUri,
- 'moduleName': config.mainModule.moduleName,
- });
-
- expect(
- responseController.stream,
- emitsInOrder([
- equals({
- 'succeeded': true,
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains(
- 'new test_library.B.new().c().getNumber()'),
- })
- ]));
- });
-
- test('can compile series of expressions in various libraries',
- () async {
- requestController.add({
- 'command': 'UpdateDeps',
- 'inputs': inputs,
- });
-
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'B().c().getNumber()',
- 'line': 8,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {},
- 'libraryUri': config.mainModule.libraryUri,
- 'moduleName': config.mainModule.moduleName,
- });
-
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'formal',
- 'line': 5,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {'formal': 'formal'},
- 'libraryUri': config.testModule.libraryUri,
- 'moduleName': config.testModule.moduleName,
- });
-
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'formal',
- 'line': 3,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {'formal': 'formal'},
- 'libraryUri': config.testModule2.libraryUri,
- 'moduleName': config.testModule2.moduleName,
- });
-
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'formal',
- 'line': 3,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {'formal': 'formal'},
- 'libraryUri': config.testModule3.libraryUri,
- 'moduleName': config.testModule3.moduleName,
- });
-
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'B().printNumber()',
- 'line': 9,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {},
- 'libraryUri': config.mainModule.libraryUri,
- 'moduleName': config.mainModule.moduleName,
- });
-
- expect(
- responseController.stream,
- emitsInOrder([
- equals({
- 'succeeded': true,
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains(
- 'new test_library.B.new().c().getNumber()'),
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains('return formal;'),
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains('return formal;'),
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains('return formal;'),
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure':
- contains('test_library.B.new().printNumber()'),
- })
- ]));
- });
-
- test('can compile after dependency update', () async {
- requestController.add({
- 'command': 'UpdateDeps',
- 'inputs': inputs,
- });
-
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'B().c().getNumber()',
- 'line': 8,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {},
- 'libraryUri': config.mainModule.libraryUri,
- 'moduleName': config.mainModule.moduleName,
- });
-
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'formal',
- 'line': 5,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {'formal': 'formal'},
- 'libraryUri': config.testModule.libraryUri,
- 'moduleName': config.testModule.moduleName,
- });
-
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'B().printNumber()',
- 'line': 9,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {},
- 'libraryUri': config.mainModule.libraryUri,
- 'moduleName': config.mainModule.moduleName,
- });
-
- requestController.add({
- 'command': 'UpdateDeps',
- 'inputs': inputs,
- });
-
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'B().c().getNumber()',
- 'line': 8,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {},
- 'libraryUri': config.mainModule.libraryUri,
- 'moduleName': config.mainModule.moduleName,
- });
-
- requestController.add({
- 'command': 'CompileExpression',
- 'expression': 'formal',
- 'line': 3,
- 'column': 1,
- 'jsModules': {},
- 'jsScope': {'formal': 'formal'},
- 'libraryUri': config.testModule3.libraryUri,
- 'moduleName': config.testModule3.moduleName,
- });
-
- expect(
- responseController.stream,
- emitsInOrder([
- equals({
- 'succeeded': true,
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains(
- 'new test_library.B.new().c().getNumber()'),
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains('return formal;'),
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure':
- contains('test_library.B.new().printNumber()'),
- }),
- equals({
- 'succeeded': true,
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains(
- 'new test_library.B.new().c().getNumber()'),
- }),
- equals({
- 'succeeded': true,
- 'errors': isEmpty,
- 'warnings': isEmpty,
- 'infos': isEmpty,
- 'compiledProcedure': contains('return formal;'),
- }),
- ]));
- });
- });
- });
- }
- });
+ if (request.method == 'GET') {
+ // 'readAsBytes'
+ var contents = await entity.readAsBytesAsyncIfPossible();
+ var headers = {
+ 'content-length': '${contents.length}',
+ ...request.headers,
+ };
+ return Response.ok(contents, headers: headers);
+ }
}
- });
+ return Response.notFound(path);
+ } catch (e, s) {
+ return Response.internalServerError(body: '$e:$s');
+ }
+ }
+
+ Future<void> start(String hostname, int port) async {
+ server = await HttpMultiServer.bind(hostname, port);
+ serveRequests(server, handler);
+ }
+
+ void stop() {
+ server?.close(force: true);
}
}
@@ -766,7 +966,7 @@
dartdevc,
config.testModule3.libraryUri,
'-o',
- config.testModule3.jsPath.toFilePath(),
+ config.testModule3.jsUri.toFilePath(),
'--source-map',
'--experimental-emit-debug-metadata',
'--emit-debug-symbols',
@@ -795,7 +995,7 @@
dartdevc,
config.testModule2.libraryUri,
'-o',
- config.testModule2.jsPath.toFilePath(),
+ config.testModule2.jsUri.toFilePath(),
'--source-map',
'--experimental-emit-debug-metadata',
'--emit-debug-symbols',
@@ -824,9 +1024,10 @@
dartdevc,
config.testModule.libraryUri,
'--summary',
- '${config.testModule2.summaryDillPath}=${config.testModule2.moduleName}',
+ '${config.testModule2.multiRootSummaryUri}='
+ '${config.testModule2.moduleName}',
'-o',
- config.testModule.jsPath.toFilePath(),
+ config.testModule.jsUri.toFilePath(),
'--source-map',
'--experimental-emit-debug-metadata',
'--emit-debug-symbols',
@@ -855,11 +1056,13 @@
dartdevc,
config.mainModule.libraryUri,
'--summary',
- '${config.testModule3.summaryDillPath}=${config.testModule3.moduleName}',
+ '${config.testModule3.multiRootSummaryUri}='
+ '${config.testModule3.moduleName}',
'--summary',
- '${config.testModule.summaryDillPath}=${config.testModule.moduleName}',
+ '${config.testModule.multiRootSummaryUri}='
+ '${config.testModule.moduleName}',
'-o',
- config.mainModule.jsPath.toFilePath(),
+ config.mainModule.jsUri.toFilePath(),
'--source-map',
'--experimental-emit-debug-metadata',
'--emit-debug-symbols',
diff --git a/pkg/meta/CHANGELOG.md b/pkg/meta/CHANGELOG.md
index f038761..15da3e3 100644
--- a/pkg/meta/CHANGELOG.md
+++ b/pkg/meta/CHANGELOG.md
@@ -1,4 +1,9 @@
-## 2.0.0
+## 1.7.0
+
+* Restore `TargetKindExtension` and `get displayString`.
+ We published `analyzer 1.7.2` that is compatible with `TargetKindExtension`.
+
+## 2.0.0 - removed
* Restore `TargetKindExtension` and `get displayString`.
diff --git a/pkg/meta/pubspec.yaml b/pkg/meta/pubspec.yaml
index b407064..b7e00f8 100644
--- a/pkg/meta/pubspec.yaml
+++ b/pkg/meta/pubspec.yaml
@@ -1,5 +1,6 @@
name: meta
-version: 2.0.0
+# Note, because version `2.0.0` was mistakenly released, the next major version must be `3.x.y`.
+version: 1.7.0
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/meta
description: >-
Annotations that developers can use to express the intentions that otherwise
diff --git a/pkg/scrape/example/build_control_flow.dart b/pkg/scrape/example/build_control_flow.dart
index bdd851a..04f6ed5 100644
--- a/pkg/scrape/example/build_control_flow.dart
+++ b/pkg/scrape/example/build_control_flow.dart
@@ -86,7 +86,7 @@
}
}
- bool _isReturn(Statement statement) {
+ bool _isReturn(Statement? statement) {
// Ignore empty "else" clauses.
if (statement == null) return true;
@@ -99,7 +99,7 @@
return false;
}
- bool _isAdd(Statement statement) {
+ bool _isAdd(Statement? statement) {
// Ignore empty "else" clauses.
if (statement == null) return true;
diff --git a/pkg/scrape/example/class_reuse.dart b/pkg/scrape/example/class_reuse.dart
index 8fb60c6..6f5e766 100644
--- a/pkg/scrape/example/class_reuse.dart
+++ b/pkg/scrape/example/class_reuse.dart
@@ -24,20 +24,23 @@
record('Declarations', 'class');
}
- if (node.extendsClause != null) {
+ var extendsClause = node.extendsClause;
+ if (extendsClause != null) {
record('Uses', 'extend');
- record('Superclass names', node.extendsClause.superclass.toString());
+ record('Superclass names', extendsClause.superclass.toString());
}
- if (node.withClause != null) {
- for (var mixin in node.withClause.mixinTypes) {
+ var withClause = node.withClause;
+ if (withClause != null) {
+ for (var mixin in withClause.mixinTypes) {
record('Uses', 'mixin');
record('Mixin names', mixin.toString());
}
}
- if (node.implementsClause != null) {
- for (var type in node.implementsClause.interfaces) {
+ var implementsClause = node.implementsClause;
+ if (implementsClause != null) {
+ for (var type in implementsClause.interfaces) {
record('Uses', 'implement');
record('Superinterface names', type.toString());
}
diff --git a/pkg/scrape/example/generic_classes.dart b/pkg/scrape/example/generic_classes.dart
index 09ecc32..d58a714 100644
--- a/pkg/scrape/example/generic_classes.dart
+++ b/pkg/scrape/example/generic_classes.dart
@@ -23,7 +23,7 @@
if (node.typeParameters == null) {
record('Classes', 0);
} else {
- record('Classes', node.typeParameters.typeParameters.length);
+ record('Classes', node.typeParameters!.typeParameters.length);
}
super.visitClassDeclaration(node);
}
diff --git a/pkg/scrape/example/nesting.dart b/pkg/scrape/example/nesting.dart
index 6541d6d..93c11da 100644
--- a/pkg/scrape/example/nesting.dart
+++ b/pkg/scrape/example/nesting.dart
@@ -34,7 +34,7 @@
..runCommandLine(arguments);
var methods = buildMethods.keys.toList();
- methods.sort((a, b) => buildMethods[b].compareTo(buildMethods[a]));
+ methods.sort((a, b) => buildMethods[b]!.compareTo(buildMethods[a]!));
for (var method in methods) {
print('${buildMethods[method].toString().padLeft(3)}: $method');
}
@@ -48,7 +48,7 @@
bool _pushed = false;
int _deepestNesting = 0;
- NestingVisitor({bool allCode}) : _allCode = allCode ?? false;
+ NestingVisitor({bool? allCode}) : _allCode = allCode ?? false;
@override
void beforeVisitBuildMethod(Declaration node) {
@@ -65,7 +65,7 @@
void visitArgumentList(ArgumentList node) {
// Only argument lists with trailing commas get indentation.
if (node.arguments.isNotEmpty &&
- node.arguments.last.endToken.next.type == TokenType.COMMA) {
+ node.arguments.last.endToken.next!.type == TokenType.COMMA) {
String name;
var parent = node.parent;
if (parent is MethodInvocation) {
diff --git a/pkg/scrape/example/null_aware.dart b/pkg/scrape/example/null_aware.dart
index 4437bd2..d2902c2 100644
--- a/pkg/scrape/example/null_aware.dart
+++ b/pkg/scrape/example/null_aware.dart
@@ -22,7 +22,7 @@
@override
void visitMethodInvocation(MethodInvocation node) {
if (node.operator != null &&
- node.operator.type == TokenType.QUESTION_PERIOD) {
+ node.operator!.type == TokenType.QUESTION_PERIOD) {
_nullAware(node);
}
@@ -52,7 +52,7 @@
parent.target == node ||
parent is MethodInvocation &&
parent.operator != null &&
- parent.operator.type == TokenType.QUESTION_PERIOD &&
+ parent.operator!.type == TokenType.QUESTION_PERIOD &&
parent.target == node) {
// This node is not the root of a null-aware chain, so skip it.
return;
@@ -60,15 +60,15 @@
// This node is the root of a null-aware chain. See how long the chain is.
var length = 0;
- var chain = node;
+ AstNode? chain = node;
while (true) {
if (chain is PropertyAccess &&
chain.operator.type == TokenType.QUESTION_PERIOD) {
- chain = (chain as PropertyAccess).target;
+ chain = chain.target;
} else if (chain is MethodInvocation &&
chain.operator != null &&
- chain.operator.type == TokenType.QUESTION_PERIOD) {
- chain = (chain as MethodInvocation).target;
+ chain.operator!.type == TokenType.QUESTION_PERIOD) {
+ chain = chain.target;
} else {
break;
}
@@ -242,14 +242,14 @@
// Find the surrounding statement containing the null-aware.
while (node is Expression) {
- node = node.parent;
+ node = node.parent!;
}
printNode(node);
}
void _checkCondition(AstNode node) {
- String expression;
+ String? expression;
// Look at the expression that immediately wraps the null-aware to see if
// it deals with it somehow, like "foo?.bar ?? otherwise".
@@ -262,17 +262,16 @@
parent.operator.type == TokenType.QUESTION_QUESTION) &&
(parent.rightOperand is NullLiteral ||
parent.rightOperand is BooleanLiteral)) {
- var binary = parent as BinaryExpression;
- expression = 'foo?.bar ${binary.operator} ${binary.rightOperand}';
+ expression = 'foo?.bar ${parent.operator} ${parent.rightOperand}';
// This does handle it, so see the context where it appears.
- node = parent as Expression;
+ node = parent;
if (node is ParenthesizedExpression) node = node.parent as Expression;
parent = node.parent;
if (parent is ParenthesizedExpression) parent = parent.parent;
}
- String context;
+ String? context;
if (parent is IfStatement && node == parent.condition) {
context = 'if';
} else if (parent is BinaryExpression &&
diff --git a/pkg/scrape/example/spread_sizes.dart b/pkg/scrape/example/spread_sizes.dart
index d1257e1..af39416 100644
--- a/pkg/scrape/example/spread_sizes.dart
+++ b/pkg/scrape/example/spread_sizes.dart
@@ -34,13 +34,13 @@
super.visitMethodInvocation(node);
}
- void _countCall(Expression node, SimpleIdentifier name, Expression target,
+ void _countCall(Expression node, SimpleIdentifier name, Expression? target,
ArgumentList args) {
if (name.name != 'addAll') return;
// See if the target is a collection literal.
while (target is MethodInvocation) {
- target = (target as MethodInvocation).target;
+ target = target.target;
}
if (target is ListLiteral || target is SetOrMapLiteral) {
diff --git a/pkg/scrape/example/strings.dart b/pkg/scrape/example/strings.dart
index a89fcef..a0454ed 100644
--- a/pkg/scrape/example/strings.dart
+++ b/pkg/scrape/example/strings.dart
@@ -54,7 +54,7 @@
@override
void visitPartOfDirective(PartOfDirective node) {
- if (node.uri != null) _record('Directive', node.uri);
+ if (node.uri != null) _record('Directive', node.uri!);
// Don't recurse so that we don't treat the URI as a string expression.
}
diff --git a/pkg/scrape/lib/scrape.dart b/pkg/scrape/lib/scrape.dart
index 32ab6715..1665006 100644
--- a/pkg/scrape/lib/scrape.dart
+++ b/pkg/scrape/lib/scrape.dart
@@ -25,7 +25,7 @@
final List<ScrapeVisitor Function()> _visitorFactories = [];
/// What percent of files should be processed.
- int _percent;
+ int? _percent;
/// Process package test files.
bool _includeTests = true;
@@ -82,9 +82,9 @@
/// that many times.
void addHistogram(String name,
{SortOrder order = SortOrder.descending,
- bool showBar,
- bool showAll,
- int minCount}) {
+ bool? showBar,
+ bool? showAll,
+ int? minCount}) {
_histograms.putIfAbsent(
name,
() => Histogram(
@@ -96,7 +96,7 @@
/// Add an occurrence of [item] to [histogram].
void record(String histogram, Object item) {
- _histograms[histogram].add(item);
+ _histograms[histogram]!.add(item);
}
/// Run the scrape using the given set of command line arguments.
@@ -247,10 +247,10 @@
if (entry.path.endsWith('.pbenum.dart')) continue;
}
- if (_percent != null && random.nextInt(100) >= _percent) continue;
+ if (_percent != null && random.nextInt(100) >= _percent!) continue;
var relative = p.relative(entry.path, from: path);
- _parseFile(entry as File, relative);
+ _parseFile(entry, relative);
}
}
diff --git a/pkg/scrape/lib/src/histogram.dart b/pkg/scrape/lib/src/histogram.dart
index 12f2b9f..74e35df 100644
--- a/pkg/scrape/lib/src/histogram.dart
+++ b/pkg/scrape/lib/src/histogram.dart
@@ -27,7 +27,7 @@
int get totalCount => _counts.values.fold(0, (a, b) => a + b);
- Histogram({SortOrder order, bool showBar, bool showAll, int minCount})
+ Histogram({SortOrder? order, bool? showBar, bool? showAll, int? minCount})
: _order = order ?? SortOrder.descending,
_showBar = showBar ?? true,
_showAll = showAll ?? false,
@@ -35,7 +35,7 @@
void add(Object item) {
_counts.putIfAbsent(item, () => 0);
- _counts[item]++;
+ _counts[item] = _counts[item]! + 1;
}
void printCounts(String label) {
@@ -46,10 +46,10 @@
var keys = _counts.keys.toList();
switch (_order) {
case SortOrder.ascending:
- keys.sort((a, b) => _counts[a].compareTo(_counts[b]));
+ keys.sort((a, b) => _counts[a]!.compareTo(_counts[b]!));
break;
case SortOrder.descending:
- keys.sort((a, b) => _counts[b].compareTo(_counts[a]));
+ keys.sort((a, b) => _counts[b]!.compareTo(_counts[a]!));
break;
case SortOrder.alphabetical:
keys.sort();
@@ -68,7 +68,7 @@
var shown = 0;
var skipped = 0;
for (var object in keys) {
- var count = _counts[object];
+ var count = _counts[object]!;
var countString = count.toString().padLeft(7);
var percent = 100 * count / total;
var percentString = percent.toStringAsFixed(3).padLeft(7);
@@ -91,7 +91,7 @@
// If we're counting numeric keys, show other statistics too.
if (_order == SortOrder.numeric && keys.isNotEmpty) {
var sum = keys.fold<int>(
- 0, (result, key) => result + (key as int) * _counts[key]);
+ 0, (result, key) => result + (key as int) * _counts[key]!);
var average = sum / total;
var median = _counts[keys[keys.length ~/ 2]];
print('Sum $sum, average ${average.toStringAsFixed(3)}, median $median');
diff --git a/pkg/scrape/lib/src/scrape_visitor.dart b/pkg/scrape/lib/src/scrape_visitor.dart
index 0b8a405..38ca2c5 100644
--- a/pkg/scrape/lib/src/scrape_visitor.dart
+++ b/pkg/scrape/lib/src/scrape_visitor.dart
@@ -17,7 +17,6 @@
/// need to define a pass-through constructor.
void bindVisitor(ScrapeVisitor visitor, Scrape scrape, String path,
String source, LineInfo info) {
- assert(visitor._scrape == null, 'Should only bind once.');
visitor._scrape = scrape;
visitor._path = path;
visitor._source = source;
@@ -26,11 +25,11 @@
/// Base Visitor class with some utility functionality.
class ScrapeVisitor extends RecursiveAstVisitor<void> {
- // These final-ish fields are initialized by [bindVisitor()].
- Scrape _scrape;
- String _path;
- String _source;
- LineInfo lineInfo;
+ // These are initialized by [bindVisitor()].
+ late final Scrape _scrape;
+ late final String _path;
+ late final String _source;
+ late final LineInfo lineInfo;
/// How many levels deep the visitor is currently nested inside build methods.
int _inFlutterBuildMethods = 0;
@@ -47,8 +46,8 @@
/// "BuildContext context".
bool get isInFlutterBuildMethod => _inFlutterBuildMethods > 0;
- bool _isBuildMethod(TypeAnnotation returnType, SimpleIdentifier name,
- FormalParameterList parameters) {
+ bool _isBuildMethod(TypeAnnotation? returnType, SimpleIdentifier name,
+ FormalParameterList? parameters) {
var parameterString = parameters.toString();
if (returnType.toString() == 'void') return false;
@@ -79,8 +78,8 @@
var startLine = lineInfo.getLocation(node.offset).lineNumber;
var endLine = lineInfo.getLocation(node.end).lineNumber;
- startLine = startLine.clamp(0, lineInfo.lineCount - 1) as int;
- endLine = endLine.clamp(0, lineInfo.lineCount - 1) as int;
+ startLine = startLine.clamp(0, lineInfo.lineCount - 1);
+ endLine = endLine.clamp(0, lineInfo.lineCount - 1);
var buffer = StringBuffer();
buffer.writeln('// $path:$startLine');
diff --git a/pkg/scrape/pubspec.yaml b/pkg/scrape/pubspec.yaml
index ffdaff1..c250123 100644
--- a/pkg/scrape/pubspec.yaml
+++ b/pkg/scrape/pubspec.yaml
@@ -4,10 +4,10 @@
publish_to: none
environment:
- sdk: ^2.10.0
+ sdk: ^2.13.0
dependencies:
- args: ^1.6.0
+ args: ^2.1.1
analyzer:
path: ../analyzer
path: ^1.7.0
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index ed7fb28..1bd42fa 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -168,7 +168,7 @@
}
}
-intptr_t ObjectGraph::StackIterator::OffsetFromParentInWords() const {
+intptr_t ObjectGraph::StackIterator::OffsetFromParent() const {
intptr_t parent_index = stack_->Parent(index_);
if (parent_index == Stack::kNoParent) {
return -1;
@@ -179,8 +179,7 @@
uword child_ptr_addr = reinterpret_cast<uword>(child.ptr);
intptr_t offset = child_ptr_addr - parent_start;
if (offset > 0 && offset < parent.obj->untag()->HeapSize()) {
- ASSERT(Utils::IsAligned(offset, kWordSize));
- return offset >> kWordSizeLog2;
+ return offset;
} else {
// Some internal VM objects visit pointers not contained within the parent.
// For instance, UntaggedCode::VisitCodePointers visits pointers in
@@ -435,7 +434,7 @@
if (!path_.IsNull() && offset_index < path_.Length()) {
current = it->Get();
path_.SetAt(obj_index, current);
- offset_from_parent = Smi::New(it->OffsetFromParentInWords());
+ offset_from_parent = Smi::New(it->OffsetFromParent());
path_.SetAt(offset_index, offset_from_parent);
}
++length_;
@@ -509,8 +508,7 @@
uword current_ptr_addr = reinterpret_cast<uword>(current_ptr);
intptr_t offset = current_ptr_addr - source_start;
if (offset > 0 && offset < source_->untag()->HeapSize()) {
- ASSERT(Utils::IsAligned(offset, kWordSize));
- *scratch_ = Smi::New(offset >> kWordSizeLog2);
+ *scratch_ = Smi::New(offset);
} else {
// Some internal VM objects visit pointers not contained within the
// parent. For instance, UntaggedCode::VisitCodePointers visits
@@ -543,8 +541,7 @@
uword current_ptr_addr = reinterpret_cast<uword>(current_ptr);
intptr_t offset = current_ptr_addr - source_start;
if (offset > 0 && offset < source_->untag()->HeapSize()) {
- ASSERT(Utils::IsAligned(offset, kWordSize));
- *scratch_ = Smi::New(offset >> kWordSizeLog2);
+ *scratch_ = Smi::New(offset);
} else {
// Some internal VM objects visit pointers not contained within the
// parent. For instance, UntaggedCode::VisitCodePointers visits
@@ -1192,7 +1189,7 @@
intptr_t flags = 1; // Strong.
WriteUnsigned(flags);
intptr_t offset = OffsetsTable::offsets_table[j].offset;
- intptr_t index = (offset - min_offset) / kWordSize;
+ intptr_t index = (offset - min_offset) / kCompressedWordSize;
ASSERT(index >= 0);
WriteUnsigned(index);
WriteUtf8(OffsetsTable::offsets_table[j].field_name);
@@ -1208,7 +1205,8 @@
if (field.is_instance()) {
intptr_t flags = 1; // Strong.
WriteUnsigned(flags);
- intptr_t index = field.HostOffset() / kWordSize - 1;
+ intptr_t index = (field.HostOffset() / kCompressedWordSize) -
+ (kWordSize / kCompressedWordSize);
ASSERT(index >= 0);
WriteUnsigned(index);
str = field.name();
diff --git a/runtime/vm/object_graph.h b/runtime/vm/object_graph.h
index d034705..55dc815 100644
--- a/runtime/vm/object_graph.h
+++ b/runtime/vm/object_graph.h
@@ -35,7 +35,7 @@
// Returns false if there is no parent.
bool MoveToParent();
// Offset into parent for the pointer to current object. -1 if no parent.
- intptr_t OffsetFromParentInWords() const;
+ intptr_t OffsetFromParent() const;
private:
StackIterator(const Stack* stack, intptr_t index)
diff --git a/runtime/vm/object_graph_test.cc b/runtime/vm/object_graph_test.cc
index cfb022e..8294897 100644
--- a/runtime/vm/object_graph_test.cc
+++ b/runtime/vm/object_graph_test.cc
@@ -126,14 +126,12 @@
// c is the first element in b.
Smi& offset_from_parent = Smi::Handle();
offset_from_parent ^= path.At(1);
- EXPECT_EQ(Array::element_offset(0),
- offset_from_parent.Value() * kWordSize);
+ EXPECT_EQ(Array::element_offset(0), offset_from_parent.Value());
Array& expected_b = Array::Handle();
expected_b ^= path.At(2);
// b is the element with index 10 in a.
offset_from_parent ^= path.At(3);
- EXPECT_EQ(Array::element_offset(10),
- offset_from_parent.Value() * kWordSize);
+ EXPECT_EQ(Array::element_offset(10), offset_from_parent.Value());
Array& expected_a = Array::Handle();
expected_a ^= path.At(4);
EXPECT(expected_c.ptr() == c.ptr());
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index a370775..d7a1beb 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -396,30 +396,30 @@
uword next_field_offset = isolate_group->GetClassForHeapWalkAt(class_id)
->untag()
->host_next_field_offset_in_words_
- << kWordSizeLog2;
+ << kCompressedWordSizeLog2;
ASSERT(next_field_offset > 0);
uword obj_addr = UntaggedObject::ToAddr(this);
uword from = obj_addr + sizeof(UntaggedObject);
- uword to = obj_addr + next_field_offset - kWordSize;
- const auto first = reinterpret_cast<ObjectPtr*>(from);
- const auto last = reinterpret_cast<ObjectPtr*>(to);
+ uword to = obj_addr + next_field_offset - kCompressedWordSize;
+ const auto first = reinterpret_cast<CompressedObjectPtr*>(from);
+ const auto last = reinterpret_cast<CompressedObjectPtr*>(to);
#if defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
const auto unboxed_fields_bitmap =
visitor->shared_class_table()->GetUnboxedFieldsMapAt(class_id);
if (!unboxed_fields_bitmap.IsEmpty()) {
- intptr_t bit = sizeof(UntaggedObject) / kWordSize;
- for (ObjectPtr* current = first; current <= last; current++) {
+ intptr_t bit = sizeof(UntaggedObject) / kCompressedWordSize;
+ for (CompressedObjectPtr* current = first; current <= last; current++) {
if (!unboxed_fields_bitmap.Get(bit++)) {
- visitor->VisitPointer(current);
+ visitor->VisitCompressedPointers(heap_base(), current, current);
}
}
} else {
- visitor->VisitPointers(first, last);
+ visitor->VisitCompressedPointers(heap_base(), first, last);
}
#else
- visitor->VisitPointers(first, last);
+ visitor->VisitCompressedPointers(heap_base(), first, last);
#endif // defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
}
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 51d5a00..238bc27 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -2136,15 +2136,16 @@
jselement.AddProperty("source", source);
if (source.IsArray()) {
intptr_t element_index =
- slot_offset.Value() - (Array::element_offset(0) >> kWordSizeLog2);
+ (slot_offset.Value() - Array::element_offset(0)) /
+ Array::kBytesPerElement;
jselement.AddProperty("parentListIndex", element_index);
} else {
if (source.IsInstance()) {
source_class = source.clazz();
parent_field_map = source_class.OffsetToFieldMap();
- intptr_t offset = slot_offset.Value();
- if (offset > 0 && offset < parent_field_map.Length()) {
- field ^= parent_field_map.At(offset);
+ intptr_t index = slot_offset.Value() >> kCompressedWordSizeLog2;
+ if (index > 0 && index < parent_field_map.Length()) {
+ field ^= parent_field_map.At(index);
if (!field.IsNull()) {
jselement.AddProperty("parentField", field);
continue;
@@ -2152,7 +2153,7 @@
}
}
const char* field_name = offsets_table.FieldNameForOffset(
- source.GetClassId(), slot_offset.Value() * kWordSize);
+ source.GetClassId(), slot_offset.Value());
if (field_name != nullptr) {
jselement.AddProperty("_parentWordOffset", slot_offset.Value());
// TODO(vm-service): Adjust RPC type to allow returning a field name
@@ -2161,8 +2162,8 @@
// jselement.AddProperty("_parentFieldName", field_name);
} else if (source.IsContext()) {
intptr_t element_index =
- slot_offset.Value() -
- (Context::variable_offset(0) >> kWordSizeLog2);
+ (slot_offset.Value() - Context::variable_offset(0)) /
+ Context::kBytesPerElement;
jselement.AddProperty("parentListIndex", element_index);
} else {
jselement.AddProperty("_parentWordOffset", slot_offset.Value());
@@ -2254,13 +2255,15 @@
slot_offset ^= path.At((i * 2) - 1);
if (element.IsArray() || element.IsGrowableObjectArray()) {
intptr_t element_index =
- slot_offset.Value() - (Array::element_offset(0) >> kWordSizeLog2);
+ (slot_offset.Value() - Array::element_offset(0)) /
+ Array::kBytesPerElement;
jselement.AddProperty("parentListIndex", element_index);
} else if (element.IsLinkedHashMap()) {
map = static_cast<LinkedHashMapPtr>(path.At(i * 2));
map_data = map.data();
intptr_t element_index =
- slot_offset.Value() - (Array::element_offset(0) >> kWordSizeLog2);
+ (slot_offset.Value() - Array::element_offset(0)) /
+ Array::kBytesPerElement;
LinkedHashMap::Iterator iterator(map);
while (iterator.MoveNext()) {
if (iterator.CurrentKey() == map_data.At(element_index) ||
@@ -2278,9 +2281,9 @@
if (element.IsInstance()) {
element_class = element.clazz();
element_field_map = element_class.OffsetToFieldMap();
- intptr_t offset = slot_offset.Value();
- if ((offset > 0) && (offset < element_field_map.Length())) {
- field ^= element_field_map.At(offset);
+ intptr_t index = slot_offset.Value() >> kCompressedWordSizeLog2;
+ if ((index > 0) && (index < element_field_map.Length())) {
+ field ^= element_field_map.At(index);
if (!field.IsNull()) {
name ^= field.name();
jselement.AddProperty("parentField", name.ToCString());
@@ -2289,13 +2292,13 @@
}
}
const char* field_name = offsets_table.FieldNameForOffset(
- element.GetClassId(), slot_offset.Value() * kWordSize);
+ element.GetClassId(), slot_offset.Value());
if (field_name != nullptr) {
jselement.AddProperty("parentField", field_name);
} else if (element.IsContext()) {
intptr_t element_index =
- slot_offset.Value() -
- (Context::variable_offset(0) >> kWordSizeLog2);
+ (slot_offset.Value() - Context::variable_offset(0)) /
+ Context::kBytesPerElement;
jselement.AddProperty("parentListIndex", element_index);
} else {
jselement.AddProperty("_parentWordOffset", slot_offset.Value());
diff --git a/tools/VERSION b/tools/VERSION
index f206cb0..e08126e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 288
+PRERELEASE 289
PRERELEASE_PATCH 0
\ No newline at end of file