Version 2.14.0-130.0.dev
Merge commit 'b9a0c0dfba993e726c36c255470af9868b65a6e5' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
index 1499ae6..6c90568 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/import_library.dart
@@ -8,6 +8,7 @@
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/fix/dart/top_level_declarations.dart';
import 'package:analysis_server/src/services/correction/namespace.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/source/source_range.dart';
@@ -110,26 +111,44 @@
return false;
}
- /// Return the relative uri from the passed [library] to the given [path].
- /// If the [path] is not in the LibraryElement, `null` is returned.
- String? _getRelativeURIFromLibrary(LibraryElement library, String path) {
+ /// Returns the relative URI from the passed [library] to the given [path].
+ ///
+ /// If the [path] is not in the [library]'s directory, `null` is returned.
+ String? _getRelativeUriFromLibrary(LibraryElement library, String path) {
var librarySource = library.librarySource;
- var pathCtx = resourceProvider.pathContext;
- var libraryDirectory = pathCtx.dirname(librarySource.fullName);
- var sourceDirectory = pathCtx.dirname(path);
- if (pathCtx.isWithin(libraryDirectory, path) ||
- pathCtx.isWithin(sourceDirectory, libraryDirectory)) {
- var relativeFile = pathCtx.relative(path, from: libraryDirectory);
- return pathCtx.split(relativeFile).join('/');
+ var pathContext = resourceProvider.pathContext;
+ var libraryDirectory = pathContext.dirname(librarySource.fullName);
+ var sourceDirectory = pathContext.dirname(path);
+ if (pathContext.isWithin(libraryDirectory, path) ||
+ pathContext.isWithin(sourceDirectory, libraryDirectory)) {
+ var relativeFile = pathContext.relative(path, from: libraryDirectory);
+ return pathContext.split(relativeFile).join('/');
}
return null;
}
+ /// Returns a list of one or two import corrections.
+ ///
+ /// If [relativeUri] is `null`, only one correction, with an absolute import
+ /// path, is returned. Otherwise, a correction with an absolute import path
+ /// and a correction with a relative path are returned. If the
+ /// `prefer_relative_imports` lint rule is enabled, the relative path is
+ /// returned first.
Iterable<CorrectionProducer> _importLibrary(FixKind fixKind, Uri library,
- [String? relativeURI]) sync* {
- yield _ImportAbsoluteLibrary(fixKind, library);
- if (relativeURI != null && relativeURI.isNotEmpty) {
- yield _ImportRelativeLibrary(fixKind, relativeURI);
+ [String? relativeUri]) {
+ if (relativeUri == null || relativeUri.isEmpty) {
+ return [_ImportAbsoluteLibrary(fixKind, library)];
+ }
+ if (isLintEnabled(LintNames.prefer_relative_imports)) {
+ return [
+ _ImportRelativeLibrary(fixKind, relativeUri),
+ _ImportAbsoluteLibrary(fixKind, library),
+ ];
+ } else {
+ return [
+ _ImportAbsoluteLibrary(fixKind, library),
+ _ImportRelativeLibrary(fixKind, relativeUri),
+ ];
}
}
@@ -215,9 +234,9 @@
fixKind = DartFixKind.IMPORT_LIBRARY_PROJECT1;
}
// Add the fix.
- var relativeURI =
- _getRelativeURIFromLibrary(libraryElement, declaration.path);
- yield* _importLibrary(fixKind, declaration.uri, relativeURI);
+ var relativeUri =
+ _getRelativeUriFromLibrary(libraryElement, declaration.path);
+ yield* _importLibrary(fixKind, declaration.uri, relativeUri);
}
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
index aab237e..7ac6c2b 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
@@ -232,6 +232,22 @@
expect(resultCode, expected);
}
+ /// Computes an error from [errorFilter], and verifies that
+ /// [expectedNumberOfFixesForKind] fixes of the appropriate kind are found,
+ /// and that they have messages equal to [matchFixMessages].
+ Future<void> assertHasFixesWithoutApplying({
+ bool Function(AnalysisError)? errorFilter,
+ required int expectedNumberOfFixesForKind,
+ required List<String> matchFixMessages,
+ }) async {
+ var error = await _findErrorToFix(errorFilter: errorFilter);
+ await _assertHasFixes(
+ error,
+ expectedNumberOfFixesForKind: expectedNumberOfFixesForKind,
+ matchFixMessages: matchFixMessages,
+ );
+ }
+
Future<void> assertHasFixWithoutApplying(
{bool Function(AnalysisError)? errorFilter}) async {
var error = await _findErrorToFix(errorFilter: errorFilter);
@@ -283,9 +299,14 @@
useLineEndingsForPlatform = true;
}
- /// Computes fixes and verifies that there is a fix for the given [error] of the appropriate kind.
- /// Optionally, if a [matchFixMessage] is passed, then the kind as well as the fix message must
- /// match to be returned.
+ /// Computes fixes, verifies that there is a fix for the given [error] of
+ /// the appropriate kind, and returns the fix.
+ ///
+ /// If a [matchFixMessage] is passed, then the kind as well as the fix message
+ /// must match to be returned.
+ ///
+ /// If [expectedNumberOfFixesForKind] is non-null, then the number of fixes
+ /// for [kind] is verified to be [expectedNumberOfFixesForKind].
Future<Fix> _assertHasFix(AnalysisError error,
{int? expectedNumberOfFixesForKind,
String? matchFixMessage,
@@ -294,16 +315,7 @@
var fixes = await _computeFixes(error);
if (expectedNumberOfFixesForKind != null) {
- var actualNumberOfFixesForKind = 0;
- for (var fix in fixes) {
- if (fix.kind == kind) {
- actualNumberOfFixesForKind++;
- }
- }
- if (actualNumberOfFixesForKind != expectedNumberOfFixesForKind) {
- fail('Expected $expectedNumberOfFixesForKind fixes of kind $kind,'
- ' but found $actualNumberOfFixesForKind:\n${fixes.join('\n')}');
- }
+ _assertNumberOfFixesForKind(fixes, expectedNumberOfFixesForKind);
}
// If a matchFixMessage was provided,
@@ -364,6 +376,21 @@
return foundFix;
}
+ /// Computes fixes and verifies that there are [expectedNumberOfFixesForKind]
+ /// fixes for the given [error] of the appropriate kind, and that the messages
+ /// of the fixes are equal to [matchFixMessages].
+ Future<void> _assertHasFixes(
+ AnalysisError error, {
+ required int expectedNumberOfFixesForKind,
+ required List<String> matchFixMessages,
+ }) async {
+ // Compute the fixes for this AnalysisError
+ var fixes = await _computeFixes(error);
+ _assertNumberOfFixesForKind(fixes, expectedNumberOfFixesForKind);
+ var actualFixMessages = [for (var fix in fixes) fix.change.message];
+ expect(actualFixMessages, containsAllInOrder(matchFixMessages));
+ }
+
Future<void> _assertNoFix(AnalysisError error) async {
var fixes = await _computeFixes(error);
for (var fix in fixes) {
@@ -386,6 +413,16 @@
}
}
+ void _assertNumberOfFixesForKind(
+ List<Fix> fixes, int expectedNumberOfFixesForKind) {
+ var actualNumberOfFixesForKind =
+ fixes.where((fix) => fix.kind == kind).length;
+ if (actualNumberOfFixesForKind != expectedNumberOfFixesForKind) {
+ fail('Expected $expectedNumberOfFixesForKind fixes of kind $kind,'
+ ' but found $actualNumberOfFixesForKind:\n${fixes.join('\n')}');
+ }
+ }
+
/// Computes fixes for the given [error] in [testUnit].
Future<List<Fix>> _computeFixes(AnalysisError error) async {
var analysisContext = contextFor(testFile);
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
index fcfed31..98c939b 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_project_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -172,6 +173,12 @@
''',
expectedNumberOfFixesForKind: 2,
matchFixMessage: "Import library 'a.dart'");
+ await assertHasFixesWithoutApplying(
+ expectedNumberOfFixesForKind: 2,
+ matchFixMessages: [
+ "Import library 'package:test/a.dart'",
+ "Import library 'a.dart'",
+ ]);
}
Future<void> test_relativeDirective_downOneDirectory() async {
@@ -190,6 +197,29 @@
matchFixMessage: "Import library 'dir/a.dart'");
}
+ Future<void> test_relativeDirective_preferRelativeImports() async {
+ createAnalysisOptionsFile(lints: [LintNames.prefer_relative_imports]);
+ addSource('/home/test/lib/a.dart', '''
+class Foo {}
+''');
+ await resolveTestCode('''
+main() { new Foo(); }
+''');
+ await assertHasFix('''
+import 'a.dart';
+
+main() { new Foo(); }
+''',
+ expectedNumberOfFixesForKind: 2,
+ matchFixMessage: "Import library 'a.dart'");
+ await assertHasFixesWithoutApplying(
+ expectedNumberOfFixesForKind: 2,
+ matchFixMessages: [
+ "Import library 'a.dart'",
+ "Import library 'package:test/a.dart'",
+ ]);
+ }
+
Future<void> test_relativeDirective_upOneDirectory() async {
addSource('/home/test/lib/a.dart', '''
class Foo {}
diff --git a/pkg/dev_compiler/lib/src/kernel/type_table.dart b/pkg/dev_compiler/lib/src/kernel/type_table.dart
index 15cbd31..b9833db 100644
--- a/pkg/dev_compiler/lib/src/kernel/type_table.dart
+++ b/pkg/dev_compiler/lib/src/kernel/type_table.dart
@@ -43,7 +43,7 @@
/// A name for a type made of JS identifier safe characters.
///
-/// 'L' and 'N' are prepended to a type name to represent a legacy or nullable
+/// 'L' and 'N' are appended to a type name to represent a legacy or nullable
/// flavor of a type.
String _typeString(DartType type, {bool flat = false}) {
var nullability = type.declaredNullability == Nullability.legacy
@@ -213,8 +213,10 @@
// resulting in some duplicated runtime code. We may get some performance
// wins if we just locally hoist everything.
if (freeVariables.isNotEmpty) {
+ // TODO(40273) Remove prepended text when we have a better way to hide
+ // these names from debug tools.
_unboundTypeIds[type] =
- js_ast.TemporaryId(escapeIdentifier(_typeString(type)));
+ js_ast.TemporaryId(escapeIdentifier('__t\$${_typeString(type)}'));
}
for (var free in freeVariables) {
diff --git a/pkg/frontend_server/lib/frontend_server.dart b/pkg/frontend_server/lib/frontend_server.dart
index 635cdd2..4b3a9b0 100644
--- a/pkg/frontend_server/lib/frontend_server.dart
+++ b/pkg/frontend_server/lib/frontend_server.dart
@@ -141,6 +141,13 @@
..addFlag('track-widget-creation',
help: 'Run a kernel transformer to track creation locations for widgets.',
defaultsTo: false)
+ ..addMultiOption(
+ 'delete-tostring-package-uri',
+ help: 'Replaces implementations of `toString` with `super.toString()` for '
+ 'specified package',
+ valueHelp: 'dart:ui',
+ defaultsTo: const <String>[],
+ )
..addFlag('enable-asserts',
help: 'Whether asserts will be enabled.', defaultsTo: false)
..addFlag('sound-null-safety',
@@ -531,6 +538,7 @@
results = await _runWithPrintRedirection(() => compileToKernel(
_mainSource, compilerOptions,
includePlatform: options['link-platform'],
+ deleteToStringPackageUris: options['delete-tostring-package-uri'],
aot: options['aot'],
useGlobalTypeFlowAnalysis: options['tfa'],
environmentDefines: environmentDefines,
diff --git a/pkg/vm/lib/kernel_front_end.dart b/pkg/vm/lib/kernel_front_end.dart
index e0368f7..0458451 100644
--- a/pkg/vm/lib/kernel_front_end.dart
+++ b/pkg/vm/lib/kernel_front_end.dart
@@ -65,6 +65,7 @@
import 'transformations/unreachable_code_elimination.dart'
as unreachable_code_elimination;
import 'transformations/deferred_loading.dart' as deferred_loading;
+import 'transformations/to_string_transformer.dart' as to_string_transformer;
/// Declare options consumed by [runCompiler].
void declareCompilerOptions(ArgParser args) {
@@ -129,6 +130,13 @@
args.addFlag('track-widget-creation',
help: 'Run a kernel transformer to track creation locations for widgets.',
defaultsTo: false);
+ args.addMultiOption(
+ 'delete-tostring-package-uri',
+ help: 'Replaces implementations of `toString` with `super.toString()` for '
+ 'specified package',
+ valueHelp: 'dart:ui',
+ defaultsTo: const <String>[],
+ );
args.addOption('invocation-modes',
help: 'Provides information to the front end about how it is invoked.',
defaultsTo: '');
@@ -258,6 +266,7 @@
final results = await compileToKernel(mainUri, compilerOptions,
includePlatform: additionalDills.isNotEmpty,
+ deleteToStringPackageUris: options['delete-tostring-package-uri'],
aot: aot,
useGlobalTypeFlowAnalysis: tfa,
environmentDefines: environmentDefines,
@@ -324,6 +333,7 @@
Future<KernelCompilationResults> compileToKernel(
Uri source, CompilerOptions options,
{bool includePlatform: false,
+ List<String> deleteToStringPackageUris: const <String>[],
bool aot: false,
bool useGlobalTypeFlowAnalysis: false,
Map<String, String> environmentDefines,
@@ -354,6 +364,11 @@
compilerResult?.loadedComponents, compilerResult?.sdkComponent,
includePlatform: includePlatform);
+ if (deleteToStringPackageUris.isNotEmpty && component != null) {
+ to_string_transformer.transformComponent(
+ component, deleteToStringPackageUris);
+ }
+
// Run global transformations only if component is correct.
if ((aot || minimalKernel) && component != null) {
await runGlobalTransformations(
diff --git a/pkg/vm/lib/transformations/to_string_transformer.dart b/pkg/vm/lib/transformations/to_string_transformer.dart
new file mode 100644
index 0000000..2931251
--- /dev/null
+++ b/pkg/vm/lib/transformations/to_string_transformer.dart
@@ -0,0 +1,82 @@
+// 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.
+
+import 'package:kernel/ast.dart';
+
+/// Transformer/visitor for toString
+transformComponent(Component component, List<String> packageUris) {
+ component.visitChildren(ToStringVisitor(packageUris.toSet()));
+}
+
+/// A [RecursiveVisitor] that replaces [Object.toString] overrides with
+/// `super.toString()`.
+class ToStringVisitor extends RecursiveVisitor {
+ /// The [packageUris] must not be null.
+ ToStringVisitor(this._packageUris) : assert(_packageUris != null);
+
+ /// A set of package URIs to apply this transformer to, e.g. 'dart:ui' and
+ /// 'package:flutter/foundation.dart'.
+ final Set<String> _packageUris;
+
+ /// Turn 'dart:ui' into 'dart:ui', or
+ /// 'package:flutter/src/semantics_event.dart' into 'package:flutter'.
+ String _importUriToPackage(Uri importUri) =>
+ '${importUri.scheme}:${importUri.pathSegments.first}';
+
+ bool _isInTargetPackage(Procedure node) {
+ return _packageUris
+ .contains(_importUriToPackage(node.enclosingLibrary.importUri));
+ }
+
+ bool _hasKeepAnnotation(Procedure node) {
+ for (ConstantExpression expression
+ in node.annotations.whereType<ConstantExpression>()) {
+ if (expression.constant is! InstanceConstant) {
+ continue;
+ }
+ final InstanceConstant constant = expression.constant as InstanceConstant;
+ final className = constant.classNode.name;
+ final libraryUri =
+ constant.classNode.enclosingLibrary.importUri.toString();
+ if (className == '_KeepToString' && libraryUri == 'dart:ui') {
+ return true;
+ }
+ if (className == 'pragma' && libraryUri == 'dart:core') {
+ for (var fieldRef in constant.fieldValues.keys) {
+ if (fieldRef.asField.name.text == 'name') {
+ Constant name = constant.fieldValues[fieldRef];
+ return name is StringConstant &&
+ name.value == 'flutter:keep-to-string';
+ }
+ }
+ return false;
+ }
+ }
+ return false;
+ }
+
+ @override
+ void visitProcedure(Procedure node) {
+ if (node.name.text == 'toString' &&
+ node.enclosingClass != null &&
+ node.enclosingLibrary != null &&
+ !node.isStatic &&
+ !node.isAbstract &&
+ !node.enclosingClass.isEnum &&
+ _isInTargetPackage(node) &&
+ !_hasKeepAnnotation(node)) {
+ node.function.body.replaceWith(
+ ReturnStatement(
+ SuperMethodInvocation(
+ node.name,
+ Arguments(<Expression>[]),
+ ),
+ ),
+ );
+ }
+ }
+
+ @override
+ void defaultMember(Member node) {}
+}
diff --git a/pkg/vm/test/common_test_utils.dart b/pkg/vm/test/common_test_utils.dart
index 1c97ba4..a45a95d 100644
--- a/pkg/vm/test/common_test_utils.dart
+++ b/pkg/vm/test/common_test_utils.dart
@@ -38,7 +38,8 @@
{Target target,
bool enableSuperMixins = false,
List<String> experimentalFlags,
- Map<String, String> environmentDefines}) async {
+ Map<String, String> environmentDefines,
+ Uri packagesFileUri}) async {
final platformKernel =
computePlatformBinariesLocation().resolve('vm_platform_strong.dill');
target ??= new TestingVmTarget(new TargetFlags())
@@ -48,6 +49,7 @@
..target = target
..additionalDills = <Uri>[platformKernel]
..environmentDefines = environmentDefines
+ ..packagesFileUri = packagesFileUri
..explicitExperimentalFlags =
parseExperimentalFlags(parseExperimentalArguments(experimentalFlags),
onError: (String message) {
diff --git a/pkg/vm/test/transformations/to_string_transformer_test.dart b/pkg/vm/test/transformations/to_string_transformer_test.dart
new file mode 100644
index 0000000..ef94ca8
--- /dev/null
+++ b/pkg/vm/test/transformations/to_string_transformer_test.dart
@@ -0,0 +1,42 @@
+// 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.
+
+import 'dart:io';
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/verifier.dart';
+import 'package:test/test.dart';
+import 'package:vm/transformations/to_string_transformer.dart'
+ show transformComponent;
+
+import '../common_test_utils.dart';
+
+final Uri pkgVmUri = Platform.script.resolve('../..');
+
+runTestCase(List<String> packageUris, String expectationName) async {
+ final testCasesUri =
+ pkgVmUri.resolve('testcases/transformations/to_string_transformer/');
+ final packagesFileUri =
+ testCasesUri.resolve('.dart_tool/package_config.json');
+ Component component = await compileTestCaseToKernelProgram(
+ Uri.parse('package:to_string_transformer_test/main.dart'),
+ packagesFileUri: packagesFileUri);
+
+ transformComponent(component, packageUris);
+ verifyComponent(component);
+
+ final actual = kernelLibraryToString(component.mainMethod.enclosingLibrary);
+
+ compareResultWithExpectationsFile(
+ testCasesUri.resolve(expectationName), actual);
+}
+
+main() {
+ group('to-string-transformer', () {
+ runTestCase(['package:foo'], 'not_transformed');
+ runTestCase(
+ ['package:foo', 'package:to_string_transformer_test'], 'transformed');
+ });
+}
diff --git a/pkg/vm/testcases/transformations/to_string_transformer/.dart_tool/package_config.json b/pkg/vm/testcases/transformations/to_string_transformer/.dart_tool/package_config.json
new file mode 100644
index 0000000..b8a9fce
--- /dev/null
+++ b/pkg/vm/testcases/transformations/to_string_transformer/.dart_tool/package_config.json
@@ -0,0 +1,11 @@
+{
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "to_string_transformer_test",
+ "rootUri": "../",
+ "packageUri": "lib",
+ "languageVersion": "2.12"
+ }
+ ]
+}
diff --git a/pkg/vm/testcases/transformations/to_string_transformer/.gitignore b/pkg/vm/testcases/transformations/to_string_transformer/.gitignore
new file mode 100644
index 0000000..0a29033
--- /dev/null
+++ b/pkg/vm/testcases/transformations/to_string_transformer/.gitignore
@@ -0,0 +1 @@
+!.dart_tool
diff --git a/pkg/vm/testcases/transformations/to_string_transformer/lib/main.dart b/pkg/vm/testcases/transformations/to_string_transformer/lib/main.dart
new file mode 100644
index 0000000..96544f2
--- /dev/null
+++ b/pkg/vm/testcases/transformations/to_string_transformer/lib/main.dart
@@ -0,0 +1,34 @@
+// 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.
+
+import 'dart:convert';
+
+const keepToString = pragma('flutter:keep-to-string');
+
+String toString() => 'I am static';
+
+abstract class IFoo {
+ @override
+ String toString();
+}
+
+class Foo implements IFoo {
+ @override
+ String toString() => 'I am a Foo';
+}
+
+enum FooEnum { A, B, C }
+
+class Keep {
+ @keepToString
+ @override
+ String toString() => 'I am a Keep';
+}
+
+void main() {
+ final IFoo foo = Foo();
+ print(foo.toString());
+ print(Keep().toString());
+ print(FooEnum.B.toString());
+}
diff --git a/pkg/vm/testcases/transformations/to_string_transformer/not_transformed.expect b/pkg/vm/testcases/transformations/to_string_transformer/not_transformed.expect
new file mode 100644
index 0000000..291ca37
--- /dev/null
+++ b/pkg/vm/testcases/transformations/to_string_transformer/not_transformed.expect
@@ -0,0 +1,68 @@
+library #lib /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "dart:convert";
+
+abstract class IFoo extends core::Object {
+ synthetic constructor •() → self::IFoo
+ : super core::Object::•()
+ ;
+ @#C1
+ abstract method toString() → core::String;
+}
+class Foo extends core::Object implements self::IFoo {
+ synthetic constructor •() → self::Foo
+ : super core::Object::•()
+ ;
+ @#C1
+ method toString() → core::String
+ return "I am a Foo";
+}
+class FooEnum extends core::Object /*isEnum*/ {
+ final field core::int index;
+ final field core::String _name;
+ static const field core::List<self::FooEnum> values = #C11;
+ static const field self::FooEnum A = #C4;
+ static const field self::FooEnum B = #C7;
+ static const field self::FooEnum C = #C10;
+ const constructor •(core::int index, core::String _name) → self::FooEnum
+ : self::FooEnum::index = index, self::FooEnum::_name = _name, super core::Object::•()
+ ;
+ method toString() → core::String
+ return this.{self::FooEnum::_name};
+}
+class Keep extends core::Object {
+ synthetic constructor •() → self::Keep
+ : super core::Object::•()
+ ;
+ @#C14
+ @#C1
+ method toString() → core::String
+ return "I am a Keep";
+}
+static const field core::pragma keepToString = #C14;
+static method toString() → core::String
+ return "I am static";
+static method main() → void {
+ final self::IFoo foo = new self::Foo::•();
+ core::print(foo.{self::IFoo::toString}());
+ core::print(new self::Keep::•().{self::Keep::toString}());
+ core::print((#C7).{self::FooEnum::toString}());
+}
+constants {
+ #C1 = core::_Override {}
+ #C2 = 0
+ #C3 = "FooEnum.A"
+ #C4 = self::FooEnum {index:#C2, _name:#C3}
+ #C5 = 1
+ #C6 = "FooEnum.B"
+ #C7 = self::FooEnum {index:#C5, _name:#C6}
+ #C8 = 2
+ #C9 = "FooEnum.C"
+ #C10 = self::FooEnum {index:#C8, _name:#C9}
+ #C11 = <self::FooEnum*>[#C4, #C7, #C10]
+ #C12 = "flutter:keep-to-string"
+ #C13 = null
+ #C14 = core::pragma {name:#C12, options:#C13}
+}
diff --git a/pkg/vm/testcases/transformations/to_string_transformer/transformed.expect b/pkg/vm/testcases/transformations/to_string_transformer/transformed.expect
new file mode 100644
index 0000000..7ae1922
--- /dev/null
+++ b/pkg/vm/testcases/transformations/to_string_transformer/transformed.expect
@@ -0,0 +1,68 @@
+library #lib /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "dart:convert";
+
+abstract class IFoo extends core::Object {
+ synthetic constructor •() → self::IFoo
+ : super core::Object::•()
+ ;
+ @#C1
+ abstract method toString() → core::String;
+}
+class Foo extends core::Object implements self::IFoo {
+ synthetic constructor •() → self::Foo
+ : super core::Object::•()
+ ;
+ @#C1
+ method toString() → core::String
+ return super.toString();
+}
+class FooEnum extends core::Object /*isEnum*/ {
+ final field core::int index;
+ final field core::String _name;
+ static const field core::List<self::FooEnum> values = #C11;
+ static const field self::FooEnum A = #C4;
+ static const field self::FooEnum B = #C7;
+ static const field self::FooEnum C = #C10;
+ const constructor •(core::int index, core::String _name) → self::FooEnum
+ : self::FooEnum::index = index, self::FooEnum::_name = _name, super core::Object::•()
+ ;
+ method toString() → core::String
+ return this.{self::FooEnum::_name};
+}
+class Keep extends core::Object {
+ synthetic constructor •() → self::Keep
+ : super core::Object::•()
+ ;
+ @#C14
+ @#C1
+ method toString() → core::String
+ return "I am a Keep";
+}
+static const field core::pragma keepToString = #C14;
+static method toString() → core::String
+ return "I am static";
+static method main() → void {
+ final self::IFoo foo = new self::Foo::•();
+ core::print(foo.{self::IFoo::toString}());
+ core::print(new self::Keep::•().{self::Keep::toString}());
+ core::print((#C7).{self::FooEnum::toString}());
+}
+constants {
+ #C1 = core::_Override {}
+ #C2 = 0
+ #C3 = "FooEnum.A"
+ #C4 = self::FooEnum {index:#C2, _name:#C3}
+ #C5 = 1
+ #C6 = "FooEnum.B"
+ #C7 = self::FooEnum {index:#C5, _name:#C6}
+ #C8 = 2
+ #C9 = "FooEnum.C"
+ #C10 = self::FooEnum {index:#C8, _name:#C9}
+ #C11 = <self::FooEnum*>[#C4, #C7, #C10]
+ #C12 = "flutter:keep-to-string"
+ #C13 = null
+ #C14 = core::pragma {name:#C12, options:#C13}
+}
diff --git a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
index 212571a..9b74eca 100644
--- a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
+++ b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
@@ -280,7 +280,7 @@
// Not every byte is accounted for by the snapshot profile, and data and
// instruction segments are padded to an alignment boundary.
- final tolerance = 0.03 * actualSize + 2 * segmentAlignment;
+ final tolerance = 0.04 * actualSize + 2 * segmentAlignment;
Expect.approxEquals(
expectedSize,
diff --git a/runtime/tests/vm/dart_2/v8_snapshot_profile_writer_test.dart b/runtime/tests/vm/dart_2/v8_snapshot_profile_writer_test.dart
index 9b7c95d..23be14f 100644
--- a/runtime/tests/vm/dart_2/v8_snapshot_profile_writer_test.dart
+++ b/runtime/tests/vm/dart_2/v8_snapshot_profile_writer_test.dart
@@ -285,7 +285,7 @@
// Not every byte is accounted for by the snapshot profile, and data and
// instruction segments are padded to an alignment boundary.
- final tolerance = 0.03 * actualSize + 2 * segmentAlignment;
+ final tolerance = 0.04 * actualSize + 2 * segmentAlignment;
Expect.approxEquals(
expectedSize,
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index 4ff4a9b..0a7e529 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -106,11 +106,6 @@
}
int64_t OS::GetCurrentThreadCPUMicros() {
-#if HOST_OS_IOS
- // Thread CPU time appears unreliable on iOS, sometimes incorrectly reporting
- // no time elapsed.
- return -1;
-#else
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
thread_basic_info_data_t info_data;
thread_basic_info_t info = &info_data;
@@ -124,7 +119,6 @@
thread_cpu_micros += info->user_time.microseconds;
thread_cpu_micros += info->system_time.microseconds;
return thread_cpu_micros;
-#endif
}
int64_t OS::GetCurrentThreadCPUMicrosForTimeline() {
diff --git a/tools/VERSION b/tools/VERSION
index b247895..220da86 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 129
+PRERELEASE 130
PRERELEASE_PATCH 0
\ No newline at end of file