Version 2.15.0-169.0.dev
Merge commit '765a6cf282e6b26d842a736127fdac59a1c18bc0' into 'dev'
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 48a5828..fc93703 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -127,8 +127,8 @@
def HasFormatErrors(filename: str = None, contents: str = None):
# Don't look for formatting errors in multitests. Since those are very
- # sensitive to whitespace, many cannot be formatted with dartfmt without
- # breaking them.
+ # sensitive to whitespace, many cannot be reformatted without breaking
+ # them.
if filename and filename.endswith('_test.dart'):
with open(filename) as f:
contents = f.read()
@@ -179,7 +179,7 @@
lineSep = " ^\n"
return [
output_api.PresubmitError(
- 'File output does not match dartfmt.\n'
+ 'File output does not match dart format.\n'
'Fix these issues with:\n'
'%s format %s%s' %
(dart, lineSep, lineSep.join(unformatted_files)))
diff --git a/benchmarks/IsolateJson/dart/IsolateJson.dart b/benchmarks/IsolateJson/dart/IsolateJson.dart
index 5b5a9ee..9717f34 100644
--- a/benchmarks/IsolateJson/dart/IsolateJson.dart
+++ b/benchmarks/IsolateJson/dart/IsolateJson.dart
@@ -10,8 +10,6 @@
import 'package:benchmark_harness/benchmark_harness.dart' show BenchmarkBase;
-import 'runtime/tests/vm/dart/export_sendAndExit_helper.dart' show sendAndExit;
-
class JsonDecodingBenchmark {
JsonDecodingBenchmark(this.name,
{required this.sample,
@@ -80,7 +78,7 @@
Future<void> jsonDecodingIsolate(JsonDecodeRequest request) async {
final result = json.decode(utf8.decode(request.encodedJson));
if (request.useSendAndExit) {
- sendAndExit(request.sendPort, result);
+ Isolate.exit(request.sendPort, result);
} else {
request.sendPort.send(result);
}
diff --git a/benchmarks/IsolateJson/dart/runtime/tests/vm/dart/export_sendAndExit_helper.dart b/benchmarks/IsolateJson/dart/runtime/tests/vm/dart/export_sendAndExit_helper.dart
deleted file mode 100644
index 75628d6..0000000
--- a/benchmarks/IsolateJson/dart/runtime/tests/vm/dart/export_sendAndExit_helper.dart
+++ /dev/null
@@ -1 +0,0 @@
-export 'dart:_internal' show sendAndExit;
diff --git a/benchmarks/IsolateJson/dart2/IsolateJson.dart b/benchmarks/IsolateJson/dart2/IsolateJson.dart
index 46ac6ca..a78b95d 100644
--- a/benchmarks/IsolateJson/dart2/IsolateJson.dart
+++ b/benchmarks/IsolateJson/dart2/IsolateJson.dart
@@ -13,8 +13,6 @@
import 'package:benchmark_harness/benchmark_harness.dart' show BenchmarkBase;
import 'package:meta/meta.dart';
-import 'runtime/tests/vm/dart/export_sendAndExit_helper.dart' show sendAndExit;
-
class JsonDecodingBenchmark {
JsonDecodingBenchmark(this.name,
{@required this.sample,
@@ -83,7 +81,7 @@
Future<void> jsonDecodingIsolate(JsonDecodeRequest request) async {
final result = json.decode(utf8.decode(request.encodedJson));
if (request.useSendAndExit) {
- sendAndExit(request.sendPort, result);
+ Isolate.exit(request.sendPort, result);
} else {
request.sendPort.send(result);
}
diff --git a/benchmarks/IsolateJson/dart2/runtime/tests/vm/dart/export_sendAndExit_helper.dart b/benchmarks/IsolateJson/dart2/runtime/tests/vm/dart/export_sendAndExit_helper.dart
deleted file mode 100644
index 75628d6..0000000
--- a/benchmarks/IsolateJson/dart2/runtime/tests/vm/dart/export_sendAndExit_helper.dart
+++ /dev/null
@@ -1 +0,0 @@
-export 'dart:_internal' show sendAndExit;
diff --git a/pkg/analysis_server/lib/src/g3/fixes.dart b/pkg/analysis_server/lib/src/g3/fixes.dart
new file mode 100644
index 0000000..51c05f4
--- /dev/null
+++ b/pkg/analysis_server/lib/src/g3/fixes.dart
@@ -0,0 +1,207 @@
+// 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:analysis_server/plugin/edit/fix/fix_core.dart';
+import 'package:analysis_server/src/protocol_server.dart' show SourceEdit;
+import 'package:analysis_server/src/services/correction/change_workspace.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/correction/fix_internal.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/overlay_file_system.dart';
+import 'package:analyzer/instrumentation/service.dart';
+import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
+import 'package:analyzer/src/dart/error/lint_codes.dart';
+import 'package:collection/collection.dart';
+
+/// The root of a set of classes that support testing for lint fixes.
+///
+/// These classes work as a sequence:
+/// 1. Create this tested with necessary SDK and package config.
+/// 2. Configure any overlays on top of the file system with [updateFile].
+/// 3. Request fixes for a file using [fixesForSingleLint].
+/// 4. Use the [LintFixTesterWithFixes] to check how many fixes there are.
+/// 5. If there is a single fix, use [LintFixTesterWithSingleFix] to verify
+/// the fixed content for specific files.
+class LintFixTester {
+ final OverlayResourceProvider _resourceProvider;
+ final String sdkPath;
+ final String? packageConfigPath;
+
+ /// If `false`, then we have already computed lints for this tester,
+ /// and updating the file system (as much as we can observe it) should
+ /// not be allowed.
+ bool _canUpdateResourceProvider = true;
+
+ LintFixTester({
+ required ResourceProvider resourceProvider,
+ required this.sdkPath,
+ required this.packageConfigPath,
+ }) : _resourceProvider = OverlayResourceProvider(resourceProvider);
+
+ /// Prepare fixes for a single lint in the file with the [path]
+ ///
+ /// If [inFile] is `false`, there must be exactly one diagnostic in the file,
+ /// and it is a lint.
+ ///
+ /// If [inFile] is `true`, there must be one or more diagnostics, but all
+ /// of them must have the same error code, and it must be a lint.
+ ///
+ /// Throws [StateError] if an expectation is not satisfied.
+ Future<LintFixTesterWithFixes> fixesForSingleLint({
+ required String path,
+ required bool inFile,
+ }) async {
+ _canUpdateResourceProvider = true;
+
+ var collection = AnalysisContextCollectionImpl(
+ includedPaths: [path],
+ resourceProvider: _resourceProvider,
+ sdkPath: sdkPath,
+ packagesFile: packageConfigPath,
+ );
+ var analysisContext = collection.contextFor(path);
+ var analysisSession = analysisContext.currentSession;
+
+ var unitResult = await analysisSession.getResolvedUnit(path);
+ unitResult as ResolvedUnitResult;
+
+ AnalysisError error;
+ var errors = unitResult.errors;
+ if (inFile) {
+ var groups = errors.groupListsBy((error) => error.errorCode);
+ if (groups.length != 1) {
+ throw StateError(
+ 'Exactly one error code expected:'
+ '\n$errors\n${groups.keys.toList()}',
+ );
+ }
+ error = errors.first;
+ } else {
+ if (errors.length != 1) {
+ throw StateError('Exactly one lint expected: $errors');
+ }
+ error = errors.single;
+ }
+
+ if (error.errorCode is! LintCode) {
+ throw StateError('A lint expected: $errors');
+ }
+
+ var workspace = DartChangeWorkspace([analysisSession]);
+ var context = DartFixContextImpl(
+ InstrumentationService.NULL_SERVICE,
+ workspace,
+ unitResult,
+ error,
+ (name) => const [],
+ );
+
+ List<Fix> fixes;
+ if (inFile) {
+ var fixInFileProcessor = FixInFileProcessor(context);
+ fixes = await fixInFileProcessor.compute();
+ } else {
+ fixes = await FixProcessor(context).compute();
+ fixes.removeWhere(
+ (fix) =>
+ fix.kind == DartFixKind.IGNORE_ERROR_LINE ||
+ fix.kind == DartFixKind.IGNORE_ERROR_FILE,
+ );
+ }
+
+ return LintFixTesterWithFixes(parent: this, fixes: fixes);
+ }
+
+ /// Update the view on the file system so that the final with the [path]
+ /// is considered to have the given [content]. The actual file system is
+ /// not changed.
+ ///
+ /// This method should not be used after any analysis is performed, such
+ /// as invocation of [fixesForSingleLint], will throw [StateError].
+ void updateFile({
+ required String path,
+ required String content,
+ }) {
+ if (!_canUpdateResourceProvider) {
+ throw StateError('Diagnostics were already computed.');
+ }
+
+ _resourceProvider.setOverlay(
+ path,
+ content: content,
+ modificationStamp: 0,
+ );
+ }
+}
+
+class LintFixTesterWithFixes {
+ final LintFixTester _parent;
+ final List<Fix> fixes;
+
+ LintFixTesterWithFixes({
+ required LintFixTester parent,
+ required this.fixes,
+ }) : _parent = parent;
+
+ void assertNoFixes() {
+ if (fixes.isNotEmpty) {
+ throw StateError('Must have exactly zero fixes: $fixes');
+ }
+ }
+
+ LintFixTesterWithSingleFix assertSingleFix() {
+ if (fixes.length != 1) {
+ throw StateError('Must have exactly one fix: $fixes');
+ }
+
+ return LintFixTesterWithSingleFix(
+ parent: this,
+ fix: fixes.single,
+ );
+ }
+}
+
+class LintFixTesterWithSingleFix {
+ final LintFixTesterWithFixes _parent;
+ final Fix fix;
+
+ LintFixTesterWithSingleFix({
+ required LintFixTesterWithFixes parent,
+ required this.fix,
+ }) : _parent = parent;
+
+ void assertFixedContentOfFile({
+ required String path,
+ required String fixedContent,
+ }) {
+ var fileEdits = fix.change.edits;
+ var fileEdit = fileEdits.singleWhere(
+ (fileEdit) => fileEdit.file == path,
+ );
+
+ var resourceProvider = _parent._parent._resourceProvider;
+ var file = resourceProvider.getFile(path);
+ var fileContent = file.readAsStringSync();
+
+ var actualFixedContent = SourceEdit.applySequence(
+ fileContent,
+ fileEdit.edits,
+ );
+ if (actualFixedContent != fixedContent) {
+ throw StateError('Not expected content:\n$actualFixedContent');
+ }
+ }
+
+ void assertNoFileEdit({required String path}) {
+ var fileEdits = fix.change.edits;
+ var filtered = fileEdits.where(
+ (fileEdit) => fileEdit.file == path,
+ );
+ if (filtered.isNotEmpty) {
+ throw StateError('Expected no edit for $path: $fix');
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/make_field_public.dart b/pkg/analysis_server/lib/src/services/correction/dart/make_field_public.dart
new file mode 100644
index 0000000..16025e4
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/dart/make_field_public.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:analysis_server/src/services/correction/dart/abstract_producer.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:analyzer_plugin/utilities/range_factory.dart';
+
+class MakeFieldPublic extends CorrectionProducer {
+ late String _fieldName;
+
+ @override
+ List<Object>? get fixArguments => [_fieldName];
+
+ @override
+ FixKind get fixKind => DartFixKind.MAKE_FIELD_PUBLIC;
+
+ @override
+ Future<void> compute(ChangeBuilder builder) async {
+ var node = this.node;
+ if (node is! SimpleIdentifier) {
+ return;
+ }
+ var getterName = node.name;
+ _fieldName = '_$getterName';
+ var parent = node.parent;
+ if (parent is MethodDeclaration && parent.name == node && parent.isGetter) {
+ var container = parent.parent;
+ if (container is ClassOrMixinDeclaration) {
+ var members = container.members;
+ MethodDeclaration? setter;
+ VariableDeclaration? field;
+ for (var member in members) {
+ if (member is MethodDeclaration &&
+ member.name.name == getterName &&
+ member.isSetter) {
+ setter = member;
+ } else if (member is FieldDeclaration) {
+ for (var variable in member.fields.variables) {
+ if (variable.name.name == _fieldName) {
+ field = variable;
+ }
+ }
+ }
+ }
+ if (setter == null || field == null) {
+ return;
+ }
+ await builder.addDartFileEdit(file, (builder) {
+ builder.addSimpleReplacement(range.node(field!.name), getterName);
+ builder.removeMember(members, parent);
+ builder.removeMember(members, setter!);
+ });
+ }
+ }
+ }
+
+ /// Return an instance of this class. Used as a tear-off in `FixProcessor`.
+ static MakeFieldPublic newInstance() => MakeFieldPublic();
+}
+
+extension on DartFileEditBuilder {
+ void removeMember(NodeList<ClassMember> members, ClassMember member) {
+ // TODO(brianwilkerson) Consider moving this to DartFileEditBuilder.
+ var index = members.indexOf(member);
+ if (index == 0) {
+ if (members.length == 1) {
+ // TODO(brianwilkerson) Remove the whitespace before and after the
+ // member.
+ addDeletion(range.node(member));
+ } else {
+ addDeletion(range.startStart(member, members[index + 1]));
+ }
+ } else {
+ addDeletion(range.endEnd(members[index - 1], member));
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index c9a98b8..8bdf4f5 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -671,6 +671,11 @@
DartFixKindPriority.DEFAULT,
"Make field '{0}' not final",
);
+ static const MAKE_FIELD_PUBLIC = FixKind(
+ 'dart.fix.makeFieldPublic',
+ DartFixKindPriority.DEFAULT,
+ "Make field '{0}' public",
+ );
static const MAKE_FINAL = FixKind(
'dart.fix.makeFinal',
DartFixKindPriority.DEFAULT,
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index ab54076..e1a0b22 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -86,6 +86,7 @@
import 'package:analysis_server/src/services/correction/dart/make_class_abstract.dart';
import 'package:analysis_server/src/services/correction/dart/make_conditional_on_debug_mode.dart';
import 'package:analysis_server/src/services/correction/dart/make_field_not_final.dart';
+import 'package:analysis_server/src/services/correction/dart/make_field_public.dart';
import 'package:analysis_server/src/services/correction/dart/make_final.dart';
import 'package:analysis_server/src/services/correction/dart/make_return_type_nullable.dart';
import 'package:analysis_server/src/services/correction/dart/make_variable_not_final.dart';
@@ -571,6 +572,9 @@
LintNames.unnecessary_final: [
ReplaceFinalWithVar.newInstance,
],
+ LintNames.unnecessary_getters_setters: [
+ MakeFieldPublic.newInstance,
+ ],
LintNames.unnecessary_lambdas: [
ReplaceWithTearOff.newInstance,
],
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index cfdea77..c614c89 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -115,6 +115,8 @@
static const String unnecessary_constructor_name =
'unnecessary_constructor_name';
static const String unnecessary_final = 'unnecessary_final';
+ static const String unnecessary_getters_setters =
+ 'unnecessary_getters_setters';
static const String unnecessary_lambdas = 'unnecessary_lambdas';
static const String unnecessary_new = 'unnecessary_new';
static const String unnecessary_null_in_if_null_operators =
diff --git a/pkg/analysis_server/test/src/g3/fixes_test.dart b/pkg/analysis_server/test/src/g3/fixes_test.dart
new file mode 100644
index 0000000..430ac37b
--- /dev/null
+++ b/pkg/analysis_server/test/src/g3/fixes_test.dart
@@ -0,0 +1,201 @@
+// 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:analysis_server/src/g3/fixes.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer/src/test_utilities/mock_sdk.dart';
+import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
+import 'package:linter/src/rules.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(G3FixesTest);
+ });
+}
+
+@reflectiveTest
+class G3FixesTest with ResourceProviderMixin {
+ void setUp() {
+ registerLintRules();
+ MockSdk(resourceProvider: resourceProvider);
+ }
+
+ Future<void> test_awaitOnlyFutures() async {
+ await _assertHasLintFix(
+ codeWithLint: r'''
+void f() async {
+ await 0;
+}
+''',
+ lintName: LintNames.await_only_futures,
+ fixedCode: r'''
+void f() async {
+ 0;
+}
+''',
+ );
+ }
+
+ Future<void> test_awaitOnlyFutures_inFile() async {
+ await _assertHasLintFix(
+ inFile: true,
+ codeWithLint: r'''
+void f() async {
+ await 0;
+ await 1;
+}
+''',
+ lintName: LintNames.await_only_futures,
+ fixedCode: r'''
+void f() async {
+ 0;
+ 1;
+}
+''',
+ );
+ }
+
+ Future<void> test_emptyCatches_noFinally() async {
+ await _assertNoLintFix(
+ codeWithLint: r'''
+void f() {
+ try {
+ } catch (e) {}
+}
+''',
+ lintName: LintNames.empty_catches,
+ );
+ }
+
+ Future<void> test_emptyConstructorBodies() async {
+ await _assertHasLintFix(
+ codeWithLint: r'''
+class C {
+ C() {}
+}
+''',
+ lintName: LintNames.empty_constructor_bodies,
+ fixedCode: r'''
+class C {
+ C();
+}
+''',
+ );
+ }
+
+ Future<void> test_invalid_moreThanOneDiagnostic() async {
+ expect(() async {
+ await _assertHasLintFix(
+ codeWithLint: '0 1',
+ lintName: LintNames.avoid_empty_else,
+ fixedCode: '',
+ );
+ }, throwsStateError);
+ }
+
+ Future<void> test_invalid_noDiagnostics() async {
+ expect(() async {
+ await _assertHasLintFix(
+ codeWithLint: '',
+ lintName: LintNames.avoid_empty_else,
+ fixedCode: '',
+ );
+ }, throwsStateError);
+ }
+
+ Future<void> test_invalid_notLint() async {
+ expect(() async {
+ await _assertHasLintFix(
+ codeWithLint: '42',
+ lintName: LintNames.avoid_empty_else,
+ fixedCode: '',
+ );
+ }, throwsStateError);
+ }
+
+ Future<void> _assertHasLintFix({
+ required String codeWithLint,
+ required String lintName,
+ required String fixedCode,
+ bool inFile = false,
+ }) async {
+ _enableLint(lintName);
+
+ var tester = LintFixTester(
+ resourceProvider: resourceProvider,
+ sdkPath: sdkRoot,
+ packageConfigPath: null,
+ );
+
+ var path = convertPath('/home/test/lib/test.dart');
+ tester.updateFile(
+ path: path,
+ content: codeWithLint,
+ );
+
+ var testerWithFixes = await tester.fixesForSingleLint(
+ path: path,
+ inFile: inFile,
+ );
+
+ var singleFix = testerWithFixes.assertSingleFix();
+ singleFix.assertFixedContentOfFile(
+ path: path,
+ fixedContent: fixedCode,
+ );
+ }
+
+ Future<void> _assertNoLintFix({
+ required String codeWithLint,
+ required String lintName,
+ bool inFile = false,
+ }) async {
+ _enableLint(lintName);
+
+ var tester = LintFixTester(
+ resourceProvider: resourceProvider,
+ sdkPath: sdkRoot,
+ packageConfigPath: null,
+ );
+
+ var path = convertPath('/home/test/lib/test.dart');
+ tester.updateFile(
+ path: path,
+ content: codeWithLint,
+ );
+
+ var testerWithFixes = await tester.fixesForSingleLint(
+ path: path,
+ inFile: inFile,
+ );
+
+ testerWithFixes.assertNoFixes();
+ }
+
+ void _enableLint(String lintName) {
+ _writeAnalysisOptionsFile(
+ lints: [lintName],
+ );
+ }
+
+ /// Write an analysis options file based on the given arguments.
+ /// TODO(scheglov) Use AnalysisOptionsFileConfig
+ void _writeAnalysisOptionsFile({
+ List<String>? lints,
+ }) {
+ var buffer = StringBuffer();
+
+ if (lints != null) {
+ buffer.writeln('linter:');
+ buffer.writeln(' rules:');
+ for (var lint in lints) {
+ buffer.writeln(' - $lint');
+ }
+ }
+
+ newFile('/home/test/analysis_options.yaml', content: buffer.toString());
+ }
+}
diff --git a/pkg/analysis_server/test/src/g3/test_all.dart b/pkg/analysis_server/test/src/g3/test_all.dart
new file mode 100644
index 0000000..2050c81
--- /dev/null
+++ b/pkg/analysis_server/test/src/g3/test_all.dart
@@ -0,0 +1,13 @@
+// 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:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fixes_test.dart' as fixes;
+
+void main() {
+ defineReflectiveSuite(() {
+ fixes.main();
+ });
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/make_field_public_test.dart b/pkg/analysis_server/test/src/services/correction/fix/make_field_public_test.dart
new file mode 100644
index 0000000..3b95f2c
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/make_field_public_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 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(MakeFieldPublicTest);
+ });
+}
+
+@reflectiveTest
+class MakeFieldPublicTest extends FixProcessorLintTest {
+ @override
+ FixKind get kind => DartFixKind.MAKE_FIELD_PUBLIC;
+
+ @override
+ String get lintCode => LintNames.unnecessary_getters_setters;
+
+ Future<void> test_class() async {
+ await resolveTestCode('''
+class C {
+ int _f = 0;
+
+ int get f => _f;
+
+ void set f(int p) => _f = p;
+}
+''');
+ await assertHasFix('''
+class C {
+ int f = 0;
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index 0fbbd97..0fea0a6 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -106,6 +106,7 @@
import 'make_conditional_on_debug_mode_test.dart'
as make_conditional_on_debug_mode;
import 'make_field_not_final_test.dart' as make_field_not_final;
+import 'make_field_public_test.dart' as make_field_public;
import 'make_final_test.dart' as make_final;
import 'make_return_type_nullable_test.dart' as make_return_type_nullable;
import 'make_variable_not_final_test.dart' as make_variable_not_final;
@@ -294,6 +295,7 @@
make_class_abstract.main();
make_conditional_on_debug_mode.main();
make_field_not_final.main();
+ make_field_public.main();
make_final.main();
make_return_type_nullable.main();
make_variable_not_final.main();
diff --git a/pkg/analysis_server/test/src/test_all.dart b/pkg/analysis_server/test/src/test_all.dart
index 0cb76aa..85dd930 100644
--- a/pkg/analysis_server/test/src/test_all.dart
+++ b/pkg/analysis_server/test/src/test_all.dart
@@ -9,6 +9,7 @@
import 'domain_abstract_test.dart' as domain_abstract;
import 'domains/test_all.dart' as domains;
import 'flutter/test_all.dart' as flutter;
+import 'g3/test_all.dart' as g3;
import 'lsp/test_all.dart' as lsp;
import 'plugin/test_all.dart' as plugin;
import 'server/test_all.dart' as server;
@@ -22,6 +23,7 @@
domain_abstract.main();
domains.main();
flutter.main();
+ g3.main();
lsp.main();
plugin.main();
server.main();
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 4978d9e..919a698 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1523,11 +1523,13 @@
CollectionElement thenElement = node.thenElement;
flowAnalysis.flow?.ifStatement_thenBegin(condition, node);
thenElement.accept(this);
+ nullSafetyDeadCodeVerifier.flowEnd(thenElement);
var elseElement = node.elseElement;
if (elseElement != null) {
flowAnalysis.flow?.ifStatement_elseBegin();
elseElement.accept(this);
+ nullSafetyDeadCodeVerifier.flowEnd(elseElement);
}
flowAnalysis.flow?.ifStatement_end(elseElement != null);
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
index 894f8a9..2d38f07 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/map_literal_test.dart
@@ -82,7 +82,7 @@
var v = {...?a, if (b) throw 0: throw 0};
}
''', [
- error(HintCode.DEAD_CODE, 99, 9),
+ error(HintCode.DEAD_CODE, 99, 7),
]);
assertType(setOrMapLiteral('{...'), 'Map<Never, Never>');
}
@@ -107,7 +107,7 @@
var v = {...?a, if (b) throw 0: throw 0};
}
''', [
- error(HintCode.DEAD_CODE, 112, 9),
+ error(HintCode.DEAD_CODE, 112, 7),
]);
assertType(setOrMapLiteral('{...'), 'Map<Never, Never>');
}
diff --git a/pkg/analyzer/test/src/diagnostics/dead_code_test.dart b/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
index 92f1995..e2ba5bb 100644
--- a/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
@@ -338,6 +338,29 @@
]);
}
+ test_deadBlock_ifElement() async {
+ await assertErrorsInCode(r'''
+f() {
+ [
+ if (false) 2,
+ ];
+}''', [
+ error(HintCode.DEAD_CODE, 25, 1),
+ ]);
+ }
+
+ test_deadBlock_ifElement_else() async {
+ await assertErrorsInCode(r'''
+f() {
+ [
+ if (true) 2
+ else 3,
+ ];
+}''', [
+ error(HintCode.DEAD_CODE, 35, 1),
+ ]);
+ }
+
test_deadBlock_while() async {
await assertErrorsInCode(r'''
f() {
diff --git a/pkg/analyzer/test/src/diagnostics/non_constant_map_element_test.dart b/pkg/analyzer/test/src/diagnostics/non_constant_map_element_test.dart
index 35beee6..88f45a7 100644
--- a/pkg/analyzer/test/src/diagnostics/non_constant_map_element_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/non_constant_map_element_test.dart
@@ -85,7 +85,7 @@
const {1: null, if (isTrue) null: null else null: null};
}
''', [
- error(HintCode.DEAD_CODE, 83, 12),
+ error(HintCode.DEAD_CODE, 83, 10),
]);
}
diff --git a/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart b/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
index c88b7b7..18b56dc 100644
--- a/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/late_lowering.dart
@@ -42,10 +42,6 @@
// pair).
final Map<Field, Field> _backingInstanceFields = {};
- // TODO(fishythefish): Remove this when [FieldInitializer] maintains a correct
- // [Reference] to its [Field].
- final Map<Procedure, Field> _getterToField = {};
-
Member? _contextMember;
LateLowering(this._coreTypes, CompilerOptions? _options)
@@ -151,7 +147,6 @@
assert(_variableCells.isEmpty);
_fieldCells.clear();
_backingInstanceFields.clear();
- _getterToField.clear();
}
void enterFunction() {
@@ -364,17 +359,19 @@
Uri fileUri = field.fileUri;
Name name = field.name;
String nameText = name.text;
+ Name mangledName = _mangleFieldName(field);
DartType type = field.type;
Expression? initializer = field.initializer;
Class enclosingClass = field.enclosingClass!;
- Name mangledName = _mangleFieldName(field);
+ field.fieldReference.canonicalName?.unbind();
Field backingField = Field.mutable(mangledName,
type: type,
initializer: StaticInvocation(_coreTypes.createSentinelMethod,
Arguments(const [], types: [type])..fileOffset = fileOffset)
..fileOffset = fileOffset,
- fileUri: fileUri)
+ fileUri: fileUri,
+ fieldReference: field.fieldReference)
..fileOffset = fileOffset
..isNonNullableByDefault = true
..isInternalImplementation = true;
@@ -485,7 +482,6 @@
..fileOffset = fileOffset
..isNonNullableByDefault = true;
enclosingClass.addProcedure(getter);
- _getterToField[getter] = backingField;
VariableDeclaration setterValue = VariableDeclaration('value', type: type)
..fileOffset = fileOffset;
@@ -552,25 +548,4 @@
return field;
}
-
- TreeNode transformFieldInitializer(
- FieldInitializer initializer, Member contextMember) {
- _contextMember = contextMember;
-
- // If the [Field] has been lowered, we can't use `node.field` to retrieve it
- // because the `getterReference` of the original field now points to the new
- // getter for the backing field.
- // TODO(fishythefish): Clean this up when [FieldInitializer] maintains a
- // correct [Reference] to its [Field].
- NamedNode node = initializer.fieldReference.node!;
- Field backingField;
- if (node is Field) {
- if (!_shouldLowerInstanceField(node)) return initializer;
- backingField = _backingInstanceField(node);
- } else {
- backingField = _getterToField[node]!;
- }
- return FieldInitializer(backingField, initializer.value)
- ..fileOffset = initializer.fileOffset;
- }
}
diff --git a/pkg/compiler/lib/src/kernel/transformations/lowering.dart b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
index 2d3b374..234eac1 100644
--- a/pkg/compiler/lib/src/kernel/transformations/lowering.dart
+++ b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
@@ -85,10 +85,4 @@
node.transformChildren(this);
return _lateLowering.transformField(node, _currentMember!);
}
-
- @override
- TreeNode visitFieldInitializer(FieldInitializer node) {
- node.transformChildren(this);
- return _lateLowering.transformFieldInitializer(node, _currentMember!);
- }
}
diff --git a/pkg/dart2js_info/tool/update_proto.sh b/pkg/dart2js_info/tool/update_proto.sh
index c784edd..559f87d 100755
--- a/pkg/dart2js_info/tool/update_proto.sh
+++ b/pkg/dart2js_info/tool/update_proto.sh
@@ -10,4 +10,4 @@
fi
protoc --proto_path="." --dart_out=lib/src/proto info.proto
-dartfmt -w lib/src/proto
+dart format lib/src/proto
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index f8c0bb5..0515336 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -272,36 +272,37 @@
return obj.ptr();
}
-DEFINE_NATIVE_ENTRY(SendPortImpl_sendAndExitInternal_, 0, 2) {
- GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
- if (!PortMap::IsReceiverInThisIsolateGroup(port.Id(), isolate->group())) {
- const auto& error =
- String::Handle(String::New("sendAndExit is only supported across "
- "isolates spawned via spawnFunction."));
- Exceptions::ThrowArgumentError(error);
- UNREACHABLE();
- }
+DEFINE_NATIVE_ENTRY(Isolate_exit_, 0, 2) {
+ GET_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
+ if (!port.IsNull()) {
+ GET_NATIVE_ARGUMENT(Instance, obj, arguments->NativeArgAt(1));
+ if (!PortMap::IsReceiverInThisIsolateGroup(port.Id(), isolate->group())) {
+ const auto& error =
+ String::Handle(String::New("exit with final message is only allowed "
+ "for isolates in one isolate group."));
+ Exceptions::ThrowArgumentError(error);
+ UNREACHABLE();
+ }
- GET_NON_NULL_NATIVE_ARGUMENT(Instance, obj, arguments->NativeArgAt(1));
-
- Object& validated_result = Object::Handle(zone);
- const Object& msg_obj = Object::Handle(zone, obj.ptr());
- validated_result = ValidateMessageObject(zone, isolate, msg_obj);
- // msg_array = [
- // <message>,
- // <collection-lib-objects-to-rehash>,
- // <core-lib-objects-to-rehash>,
- // ]
- const Array& msg_array = Array::Handle(zone, Array::New(3));
- msg_array.SetAt(0, msg_obj);
- if (validated_result.IsUnhandledException()) {
- Exceptions::PropagateError(Error::Cast(validated_result));
- UNREACHABLE();
+ Object& validated_result = Object::Handle(zone);
+ const Object& msg_obj = Object::Handle(zone, obj.ptr());
+ validated_result = ValidateMessageObject(zone, isolate, msg_obj);
+ // msg_array = [
+ // <message>,
+ // <collection-lib-objects-to-rehash>,
+ // <core-lib-objects-to-rehash>,
+ // ]
+ const Array& msg_array = Array::Handle(zone, Array::New(3));
+ msg_array.SetAt(0, msg_obj);
+ if (validated_result.IsUnhandledException()) {
+ Exceptions::PropagateError(Error::Cast(validated_result));
+ UNREACHABLE();
+ }
+ PersistentHandle* handle =
+ isolate->group()->api_state()->AllocatePersistentHandle();
+ handle->set_ptr(msg_array);
+ isolate->bequeath(std::unique_ptr<Bequest>(new Bequest(handle, port.Id())));
}
- PersistentHandle* handle =
- isolate->group()->api_state()->AllocatePersistentHandle();
- handle->set_ptr(msg_array);
- isolate->bequeath(std::unique_ptr<Bequest>(new Bequest(handle, port.Id())));
Isolate::KillIfExists(isolate, Isolate::LibMsgId::kKillMsg);
// Drain interrupts before running so any IMMEDIATE operations on the current
// isolate happen synchronously.
diff --git a/runtime/observatory/tests/service/object_graph_vm_test.dart b/runtime/observatory/tests/service/object_graph_vm_test.dart
index 8a8e7ec..5ab5fe9 100644
--- a/runtime/observatory/tests/service/object_graph_vm_test.dart
+++ b/runtime/observatory/tests/service/object_graph_vm_test.dart
@@ -90,7 +90,9 @@
int internalSum = 0;
int externalSum = 0;
for (SnapshotObject instance in klass.instances) {
- if (instance == graph.root || instance.klass.name.contains("Isolate")) {
+ if (instance == graph.root ||
+ instance.klass.name.contains("Isolate") ||
+ instance.klass.name.contains("Read-Only Pages")) {
// The root and fake root subdivisions have 0 self size.
expect(instance.internalSize, greaterThanOrEqualTo(0));
expect(instance.externalSize, greaterThanOrEqualTo(0));
@@ -122,7 +124,9 @@
int internalSum = 0;
int externalSum = 0;
for (SnapshotObject instance in graph.objects) {
- if (instance == graph.root || instance.klass.name.contains("Isolate")) {
+ if (instance == graph.root ||
+ instance.klass.name.contains("Isolate") ||
+ instance.klass.name.contains("Read-Only Pages")) {
// The root and fake root subdivisions have 0 self size.
expect(instance.internalSize, greaterThanOrEqualTo(0));
expect(instance.externalSize, greaterThanOrEqualTo(0));
diff --git a/runtime/observatory_2/tests/service_2/object_graph_vm_test.dart b/runtime/observatory_2/tests/service_2/object_graph_vm_test.dart
index 81be62e..6e35ba2 100644
--- a/runtime/observatory_2/tests/service_2/object_graph_vm_test.dart
+++ b/runtime/observatory_2/tests/service_2/object_graph_vm_test.dart
@@ -90,7 +90,9 @@
int internalSum = 0;
int externalSum = 0;
for (SnapshotObject instance in klass.instances) {
- if (instance == graph.root || instance.klass.name.contains("Isolate")) {
+ if (instance == graph.root ||
+ instance.klass.name.contains("Isolate") ||
+ instance.klass.name.contains("Read-Only Pages")) {
// The root and fake root subdivisions have 0 self size.
expect(instance.internalSize, greaterThanOrEqualTo(0));
expect(instance.externalSize, greaterThanOrEqualTo(0));
@@ -122,7 +124,9 @@
int internalSum = 0;
int externalSum = 0;
for (SnapshotObject instance in graph.objects) {
- if (instance == graph.root || instance.klass.name.contains("Isolate")) {
+ if (instance == graph.root ||
+ instance.klass.name.contains("Isolate") ||
+ instance.klass.name.contains("Read-Only Pages")) {
// The root and fake root subdivisions have 0 self size.
expect(instance.internalSize, greaterThanOrEqualTo(0));
expect(instance.externalSize, greaterThanOrEqualTo(0));
diff --git a/runtime/tests/vm/dart/isolates/internal.dart b/runtime/tests/vm/dart/isolates/internal.dart
deleted file mode 100644
index ec854b0..0000000
--- a/runtime/tests/vm/dart/isolates/internal.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2020, 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 'dart:isolate';
-import 'dart:async';
-import 'dart:_internal' as dart_internal;
-
-extension SendPortSendAndExit on SendPort {
- void sendAndExit(var message) {
- dart_internal.sendAndExit(this, message);
- }
-}
diff --git a/runtime/tests/vm/dart/isolates/ring_gc_sendAndExit_test.dart b/runtime/tests/vm/dart/isolates/ring_gc_sendAndExit_test.dart
index 74b6820..a50d9e8 100644
--- a/runtime/tests/vm/dart/isolates/ring_gc_sendAndExit_test.dart
+++ b/runtime/tests/vm/dart/isolates/ring_gc_sendAndExit_test.dart
@@ -24,7 +24,7 @@
final ring = await Ring.create(numIsolates);
// Let each node produce a tree, send it to it's neighbour and let it return
- // the one it received (via sendAndExit).
+ // the one it received (via Isolate.exit).
final results = await ring.runAndClose((int id) => Worker(id));
Expect.equals(numIsolates, results.length);
diff --git a/runtime/tests/vm/dart/isolates/test_utils.dart b/runtime/tests/vm/dart/isolates/test_utils.dart
index 7c5da81..3268cc1 100644
--- a/runtime/tests/vm/dart/isolates/test_utils.dart
+++ b/runtime/tests/vm/dart/isolates/test_utils.dart
@@ -6,8 +6,6 @@
import 'dart:io';
import 'dart:isolate';
-import 'internal.dart';
-
export '../../../../../benchmarks/IsolateFibonacci/dart/IsolateFibonacci.dart'
show fibonacciRecursive;
@@ -102,7 +100,7 @@
case Command.kRunAndClose:
final RingElement re = args[1];
final SendPort nextNeighbor = args[2];
- port.sendAndExit(await re.run(nextNeighbor, siData));
+ Isolate.exit(port, await re.run(nextNeighbor, siData));
break;
case Command.kClose:
port.send('done');
diff --git a/runtime/tests/vm/dart/sendandexit_test.dart b/runtime/tests/vm/dart/sendandexit_test.dart
index 58e02c6..235a3c2 100644
--- a/runtime/tests/vm/dart/sendandexit_test.dart
+++ b/runtime/tests/vm/dart/sendandexit_test.dart
@@ -4,9 +4,8 @@
//
// VMOptions=--enable-isolate-groups
//
-// Validates functionality of sendAndExit.
+// Validates functionality of Isolate.exit().
-import 'dart:_internal' show sendAndExit;
import 'dart:async';
import 'dart:isolate';
import 'dart:nativewrappers';
@@ -27,7 +26,7 @@
verifyCantSendAnonymousClosure() async {
final receivePort = ReceivePort();
Expect.throws(
- () => sendAndExit(receivePort.sendPort, () {}),
+ () => Isolate.exit(receivePort.sendPort, () {}),
(e) =>
e.toString() ==
'Invalid argument: "Illegal argument in isolate message : '
@@ -40,7 +39,7 @@
verifyCantSendNative() async {
final receivePort = ReceivePort();
Expect.throws(
- () => sendAndExit(receivePort.sendPort, NativeWrapperClass()),
+ () => Isolate.exit(receivePort.sendPort, NativeWrapperClass()),
(e) => e.toString().startsWith('Invalid argument: '
'"Illegal argument in isolate message : '
'(object extends NativeWrapper'));
@@ -50,7 +49,7 @@
verifyCantSendReceivePort() async {
final receivePort = ReceivePort();
Expect.throws(
- () => sendAndExit(receivePort.sendPort, receivePort),
+ () => Isolate.exit(receivePort.sendPort, receivePort),
// closure is encountered first before we reach ReceivePort instance
(e) => e.toString().startsWith(
'Invalid argument: "Illegal argument in isolate message : '
@@ -62,7 +61,7 @@
final receivePort = ReceivePort();
final regexp = RegExp("");
Expect.throws(
- () => sendAndExit(receivePort.sendPort, regexp),
+ () => Isolate.exit(receivePort.sendPort, regexp),
(e) =>
e.toString() ==
'Invalid argument: '
@@ -73,7 +72,7 @@
add(a, b) => a + b;
worker(SendPort sendPort) async {
- sendAndExit(sendPort, add);
+ Isolate.exit(sendPort, add);
}
verifyCanSendStaticMethod() async {
diff --git a/runtime/tests/vm/dart_2/isolates/internal.dart b/runtime/tests/vm/dart_2/isolates/internal.dart
deleted file mode 100644
index 1742a43..0000000
--- a/runtime/tests/vm/dart_2/isolates/internal.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2020, 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:io';
-import 'dart:isolate';
-import 'dart:async';
-import 'dart:_internal' as dart_internal;
-
-extension SendPortSendAndExit on SendPort {
- void sendAndExit(var message) {
- dart_internal.sendAndExit(this, message);
- }
-}
diff --git a/runtime/tests/vm/dart_2/isolates/ring_gc_sendAndExit_test.dart b/runtime/tests/vm/dart_2/isolates/ring_gc_sendAndExit_test.dart
index 56b636c..2c7011c 100644
--- a/runtime/tests/vm/dart_2/isolates/ring_gc_sendAndExit_test.dart
+++ b/runtime/tests/vm/dart_2/isolates/ring_gc_sendAndExit_test.dart
@@ -26,7 +26,7 @@
final ring = await Ring.create(numIsolates);
// Let each node produce a tree, send it to it's neighbour and let it return
- // the one it received (via sendAndExit).
+ // the one it received (via Isolate.exit()).
final results = await ring.runAndClose((int id) => Worker(id));
Expect.equals(numIsolates, results.length);
diff --git a/runtime/tests/vm/dart_2/isolates/test_utils.dart b/runtime/tests/vm/dart_2/isolates/test_utils.dart
index 0c93f3d..a57bb41 100644
--- a/runtime/tests/vm/dart_2/isolates/test_utils.dart
+++ b/runtime/tests/vm/dart_2/isolates/test_utils.dart
@@ -8,8 +8,6 @@
import 'dart:io';
import 'dart:isolate';
-import 'internal.dart';
-
export '../../../../../benchmarks/IsolateFibonacci/dart2/IsolateFibonacci.dart'
show fibonacciRecursive;
@@ -104,7 +102,7 @@
case Command.kRunAndClose:
final RingElement re = args[1];
final SendPort nextNeighbor = args[2];
- port.sendAndExit(await re.run(nextNeighbor, siData));
+ Isolate.exit(port, await re.run(nextNeighbor, siData));
break;
case Command.kClose:
port.send('done');
diff --git a/runtime/tests/vm/dart_2/sendandexit_test.dart b/runtime/tests/vm/dart_2/sendandexit_test.dart
index f64b1ee..3ee64fe 100644
--- a/runtime/tests/vm/dart_2/sendandexit_test.dart
+++ b/runtime/tests/vm/dart_2/sendandexit_test.dart
@@ -4,11 +4,10 @@
//
// VMOptions=--enable-isolate-groups
//
-// Validates functionality of sendAndExit.
+// Validates functionality of Isolate.exit().
// @dart = 2.9
-import 'dart:_internal' show sendAndExit;
import 'dart:async';
import 'dart:isolate';
import 'dart:nativewrappers';
@@ -29,7 +28,7 @@
verifyCantSendAnonymousClosure() async {
final receivePort = ReceivePort();
Expect.throws(
- () => sendAndExit(receivePort.sendPort, () {}),
+ () => Isolate.exit(receivePort.sendPort, () {}),
(e) =>
e.toString() ==
'Invalid argument: "Illegal argument in isolate message : '
@@ -42,7 +41,7 @@
verifyCantSendNative() async {
final receivePort = ReceivePort();
Expect.throws(
- () => sendAndExit(receivePort.sendPort, NativeWrapperClass()),
+ () => Isolate.exit(receivePort.sendPort, NativeWrapperClass()),
(e) => e.toString().startsWith('Invalid argument: '
'"Illegal argument in isolate message : '
'(object extends NativeWrapper'));
@@ -52,7 +51,7 @@
verifyCantSendReceivePort() async {
final receivePort = ReceivePort();
Expect.throws(
- () => sendAndExit(receivePort.sendPort, receivePort),
+ () => Isolate.exit(receivePort.sendPort, receivePort),
// closure is encountered first before we reach ReceivePort instance
(e) => e.toString().startsWith(
'Invalid argument: "Illegal argument in isolate message : '
@@ -64,7 +63,7 @@
final receivePort = ReceivePort();
final regexp = RegExp("");
Expect.throws(
- () => sendAndExit(receivePort.sendPort, regexp),
+ () => Isolate.exit(receivePort.sendPort, regexp),
(e) =>
e.toString() ==
'Invalid argument: '
@@ -75,7 +74,7 @@
add(a, b) => a + b;
worker(SendPort sendPort) async {
- sendAndExit(sendPort, add);
+ Isolate.exit(sendPort, add);
}
verifyCanSendStaticMethod() async {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 4911d25..6f6d67d 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -65,7 +65,6 @@
V(SendPortImpl_get_id, 1) \
V(SendPortImpl_get_hashcode, 1) \
V(SendPortImpl_sendInternal_, 2) \
- V(SendPortImpl_sendAndExitInternal_, 2) \
V(Smi_bitNegate, 1) \
V(Smi_bitLength, 1) \
V(Mint_bitNegate, 1) \
@@ -316,12 +315,13 @@
V(Int32x4_setFlagZ, 2) \
V(Int32x4_setFlagW, 2) \
V(Int32x4_select, 3) \
+ V(Isolate_exit_, 2) \
+ V(Isolate_getCurrentRootUriStr, 0) \
+ V(Isolate_getDebugName, 1) \
+ V(Isolate_getPortAndCapabilitiesOfCurrentIsolate, 0) \
+ V(Isolate_sendOOB, 2) \
V(Isolate_spawnFunction, 10) \
V(Isolate_spawnUri, 12) \
- V(Isolate_getPortAndCapabilitiesOfCurrentIsolate, 0) \
- V(Isolate_getCurrentRootUriStr, 0) \
- V(Isolate_sendOOB, 2) \
- V(Isolate_getDebugName, 1) \
V(GrowableList_allocate, 2) \
V(GrowableList_getIndexed, 2) \
V(GrowableList_setIndexed, 3) \
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 863880e..bed2681 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -756,11 +756,10 @@
TEST_CASE(DartAPI_EnsureUnwindErrorHandled_WhenSendAndExit) {
const char* kScriptChars = R"(
import 'dart:isolate';
-import 'dart:_internal' show sendAndExit;
sendAndExitNow() {
final receivePort = ReceivePort();
- sendAndExit(receivePort.sendPort, true);
+ Isolate.exit(receivePort.sendPort, true);
}
@pragma("vm:external-name", "Test_nativeFunc")
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index dfa116b..8a1cd87 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -849,6 +849,47 @@
DISALLOW_COPY_AND_ASSIGN(Pass1Visitor);
};
+class CountImagePageRefs : public ObjectVisitor {
+ public:
+ CountImagePageRefs() : ObjectVisitor() {}
+
+ void VisitObject(ObjectPtr obj) {
+ if (obj->IsPseudoObject()) return;
+ count_++;
+ }
+ intptr_t count() const { return count_; }
+
+ private:
+ intptr_t count_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(CountImagePageRefs);
+};
+
+class WriteImagePageRefs : public ObjectVisitor {
+ public:
+ explicit WriteImagePageRefs(HeapSnapshotWriter* writer)
+ : ObjectVisitor(), writer_(writer) {}
+
+ void VisitObject(ObjectPtr obj) {
+ if (obj->IsPseudoObject()) return;
+#if defined(DEBUG)
+ count_++;
+#endif
+ writer_->WriteUnsigned(writer_->GetObjectId(obj));
+ }
+#if defined(DEBUG)
+ intptr_t count() const { return count_; }
+#endif
+
+ private:
+ HeapSnapshotWriter* const writer_;
+#if defined(DEBUG)
+ intptr_t count_ = 0;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(WriteImagePageRefs);
+};
+
enum NonReferenceDataTags {
kNoData = 0,
kNullData,
@@ -865,9 +906,10 @@
enum ExtraCids {
kRootExtraCid = 1, // 1-origin
- kIsolateExtraCid = 2,
+ kImagePageExtraCid = 2,
+ kIsolateExtraCid = 3,
- kNumExtraCids = 2,
+ kNumExtraCids = 3,
};
class Pass2Visitor : public ObjectVisitor,
@@ -1209,7 +1251,16 @@
WriteUnsigned(0); // Field count
}
{
- ASSERT(kIsolateExtraCid == 2);
+ ASSERT(kImagePageExtraCid == 2);
+ WriteUnsigned(0); // Flags
+ WriteUtf8("Read-Only Pages"); // Name
+ WriteUtf8(""); // Library name
+ WriteUtf8(""); // Library uri
+ WriteUtf8(""); // Reserved
+ WriteUnsigned(0); // Field count
+ }
+ {
+ ASSERT(kIsolateExtraCid == 3);
WriteUnsigned(0); // Flags
WriteUtf8("Isolate"); // Name
WriteUtf8(""); // Library name
@@ -1226,7 +1277,7 @@
WriteUtf8(""); // Reserved
}
}
- ASSERT(kNumExtraCids == 2);
+ ASSERT(kNumExtraCids == 3);
for (intptr_t cid = 1; cid <= class_count_; cid++) {
if (!class_table->HasValidClassAt(cid)) {
WriteUnsigned(0); // Flags
@@ -1320,21 +1371,34 @@
SetupCountingPages();
intptr_t num_isolates = 0;
+ intptr_t num_image_objects = 0;
{
Pass1Visitor visitor(this);
// Root "objects".
- ++object_count_;
- isolate_group()->VisitSharedPointers(&visitor);
- isolate_group()->ForEachIsolate(
- [&](Isolate* isolate) {
- ++object_count_;
- isolate->VisitObjectPointers(&visitor,
- ValidationPolicy::kDontValidateFrames);
- ++num_isolates;
- },
- /*at_safepoint=*/true);
- CountReferences(num_isolates);
+ {
+ ++object_count_;
+ isolate_group()->VisitSharedPointers(&visitor);
+ }
+ {
+ ++object_count_;
+ CountImagePageRefs visitor;
+ H->old_space()->VisitObjectsImagePages(&visitor);
+ num_image_objects = visitor.count();
+ CountReferences(num_image_objects);
+ }
+ {
+ isolate_group()->ForEachIsolate(
+ [&](Isolate* isolate) {
+ ++object_count_;
+ isolate->VisitObjectPointers(&visitor,
+ ValidationPolicy::kDontValidateFrames);
+ ++num_isolates;
+ },
+ /*at_safepoint=*/true);
+ }
+ CountReferences(1); // Root -> Image Pages
+ CountReferences(num_isolates); // Root -> Isolate
// Heap objects.
iteration.IterateVMIsolateObjects(&visitor);
@@ -1357,13 +1421,24 @@
WriteUnsigned(kNoData);
visitor.DoCount();
isolate_group()->VisitSharedPointers(&visitor);
- visitor.CountExtraRefs(num_isolates);
+ visitor.CountExtraRefs(num_isolates + 1);
visitor.DoWrite();
isolate_group()->VisitSharedPointers(&visitor);
+ visitor.WriteExtraRef(2); // Root -> Image Pages
for (intptr_t i = 0; i < num_isolates; i++) {
- visitor.WriteExtraRef(i + 2); // 0 = sentinel, 1 = root, 2+ = isolates
+ // 0 = sentinel, 1 = root, 2 = image pages, 2+ = isolates
+ visitor.WriteExtraRef(i + 3);
}
}
+ {
+ WriteUnsigned(kImagePageExtraCid);
+ WriteUnsigned(0); // shallowSize
+ WriteUnsigned(kNoData);
+ WriteUnsigned(num_image_objects);
+ WriteImagePageRefs visitor(this);
+ H->old_space()->VisitObjectsImagePages(&visitor);
+ DEBUG_ASSERT(visitor.count() == num_image_objects);
+ }
isolate_group()->ForEachIsolate(
[&](Isolate* isolate) {
WriteUnsigned(kIsolateExtraCid);
@@ -1395,10 +1470,13 @@
// Identity hash codes
Pass3Visitor visitor(this);
- // Handle root object.
- WriteUnsigned(0);
- isolate_group()->ForEachIsolate([&](Isolate* isolate) { WriteUnsigned(0); },
- /*at_safepoint=*/true);
+ WriteUnsigned(0); // Root fake object.
+ WriteUnsigned(0); // Image pages fake object.
+ isolate_group()->ForEachIsolate(
+ [&](Isolate* isolate) {
+ WriteUnsigned(0); // Isolate fake object.
+ },
+ /*at_safepoint=*/true);
// Handle visit rest of the objects.
iteration.IterateVMIsolateObjects(&visitor);
diff --git a/sdk/lib/_http/http.dart b/sdk/lib/_http/http.dart
index d303412..b7b1f50 100644
--- a/sdk/lib/_http/http.dart
+++ b/sdk/lib/_http/http.dart
@@ -2063,7 +2063,7 @@
/// Using the [IOSink] methods (e.g., [write] and [add]) has no effect after
/// the request has been aborted
///
- /// ```dart
+ /// ```dart import:async
/// HttpClientRequst request = ...
/// request.write();
/// Timer(Duration(seconds: 1), () {
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
index 6799347..0d12311 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
@@ -77,6 +77,10 @@
@patch
void removeErrorListener(SendPort port) => _unsupported();
+
+ @patch
+ static Never exit([SendPort? finalMessagePort, Object? message]) =>
+ _unsupported();
}
/** Default factory for receive ports. */
diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
index 1c0b053..2bb2fa1 100644
--- a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
@@ -106,6 +106,11 @@
void removeErrorListener(SendPort port) {
throw new UnsupportedError("Isolate.removeErrorListener");
}
+
+ @patch
+ static Never exit([SendPort? finalMessagePort, Object? message]) {
+ throw new UnsupportedError("Isolate.exit");
+ }
}
@patch
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index 421fb4d..569b91c 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.dart
@@ -178,9 +178,6 @@
@pragma("vm:external-name", "Internal_nativeEffect")
external void _nativeEffect(Object object);
-@pragma("vm:external-name", "SendPortImpl_sendAndExitInternal_")
-external void sendAndExit(SendPort sendPort, var message);
-
// Collection of functions which should only be used for testing purposes.
abstract class VMInternalsForTesting {
// This function can be used by tests to enforce garbage collection.
diff --git a/sdk/lib/_internal/vm/lib/isolate_patch.dart b/sdk/lib/_internal/vm/lib/isolate_patch.dart
index b7bf498..37fb390 100644
--- a/sdk/lib/_internal/vm/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/vm/lib/isolate_patch.dart
@@ -645,6 +645,13 @@
@pragma("vm:external-name", "Isolate_getCurrentRootUriStr")
external static String _getCurrentRootUriStr();
+
+ @pragma("vm:external-name", "Isolate_exit_")
+ external static Never _exit(SendPort? finalMessagePort, Object? message);
+
+ static Never exit([SendPort? finalMessagePort, Object? message]) {
+ _exit(finalMessagePort, message);
+ }
}
@patch
diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart
index 33df08e..00b7fc6 100644
--- a/sdk/lib/async/async.dart
+++ b/sdk/lib/async/async.dart
@@ -32,7 +32,7 @@
/// Many methods in the Dart libraries return `Future`s when
/// performing tasks. For example, when binding an `HttpServer`
/// to a host and port, the `bind()` method returns a Future.
-/// ```dart
+/// ```dart import:io
/// HttpServer.bind('127.0.0.1', 4444)
/// .then((server) => print('${server.isBroadcast}'))
/// .catchError(print);
@@ -60,7 +60,7 @@
/// the stream has finished.
/// Further functionality is provided on [Stream], implemented by calling
/// [Stream.listen] to get the actual data.
-/// ```dart
+/// ```dart import:io import:convert
/// Stream<List<int>> stream = File('quotes.txt').openRead();
/// stream.transform(utf8.decoder).forEach(print);
/// ```
@@ -72,7 +72,7 @@
///
/// Another common use of streams is for user-generated events
/// in a web app: The following code listens for mouse clicks on a button.
-/// ```dart
+/// ```dart import:html
/// querySelector('#myButton').onClick.forEach((_) => print('Click.'));
/// ```
/// ## Other resources
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index f663b08..c587536 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -738,7 +738,7 @@
///
/// This method is equivalent to:
/// ```dart
- /// Future<T> whenComplete(action()) {
+ /// Future<T> whenComplete(action() {
/// return this.then((v) {
/// var f2 = action();
/// if (f2 is Future) return f2.then((_) => v);
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 2083510..3f12cb3 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -2059,7 +2059,7 @@
/// [StreamTransformer.bind] API and can be used when the transformation is
/// available as a stream-to-stream function.
///
- /// ```dart
+ /// ```dart import:convert
/// final splitDecoded = StreamTransformer<List<int>, String>.fromBind(
/// (stream) => stream.transform(utf8.decoder).transform(LineSplitter()));
/// ```
diff --git a/sdk/lib/convert/convert.dart b/sdk/lib/convert/convert.dart
index 081f006..b1a1cea 100644
--- a/sdk/lib/convert/convert.dart
+++ b/sdk/lib/convert/convert.dart
@@ -34,7 +34,7 @@
/// as it's read from a file,
/// The second is an instance of [LineSplitter],
/// which splits the data on newline boundaries.
-/// ```dart
+/// ```dart import:io
/// var lineNumber = 1;
/// var stream = File('quotes.txt').openRead();
///
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index 84ad5f9..4cad26d 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.dart
@@ -111,7 +111,7 @@
/// and listens for the data on the returned web socket.
/// For example, here's a mini server that listens for 'ws' data
/// on a WebSocket:
-/// ```dart
+/// ```dart import:async
/// runZoned(() async {
/// var server = await HttpServer.bind('127.0.0.1', 4040);
/// server.listen((HttpRequest req) async {
@@ -140,7 +140,7 @@
/// Use [ServerSocket] on the server side and [Socket] on the client.
/// The server creates a listening socket using the `bind()` method and
/// then listens for incoming connections on the socket. For example:
-/// ```dart
+/// ```dart import:convert
/// ServerSocket.bind('127.0.0.1', 4041)
/// .then((serverSocket) {
/// serverSocket.listen((socket) {
diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart
index 2d0ca6e..39d5a11 100644
--- a/sdk/lib/io/platform.dart
+++ b/sdk/lib/io/platform.dart
@@ -43,7 +43,7 @@
///
/// You can get the name of the operating system as a string with the
/// [operatingSystem] getter. You can also use one of the static boolean
-/// getters: [isMacOS], [isLinux], and [isWindows].
+/// getters: [isMacOS], [isLinux], [isWindows], etc.
/// ```dart
/// import 'dart:io' show Platform;
///
@@ -77,6 +77,17 @@
static String get localeName => _Platform.localeName();
/// A string representing the operating system or platform.
+ ///
+ /// Possible values include:
+ /// "android"
+ /// "fuchsia"
+ /// "ios"
+ /// "linux"
+ /// "macos"
+ /// "windows"
+ ///
+ /// Note that this list may change over time so platform-specific logic
+ /// should be guarded by the appropriate boolean getter e.g. [isMacOS].
static String get operatingSystem => _operatingSystem;
/// A string representing the version of the operating system or platform.
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index 8a68d10..fc47a29 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -553,6 +553,32 @@
};
return controller.stream;
}
+
+ /// Terminates the current isolate synchronously.
+ ///
+ /// This operations is potentially dangerous and should be used judiciously.
+ /// The isolate stops operating *immediately*. It throws if optional [message]
+ /// does not adhere to the limitation on what can be send from one isolate to
+ /// another. It also throws if a [finalMessagePort] is associated with an
+ /// isolate spawned outside of current isolate group, spawned via [spawnUri].
+ ///
+ /// If successful, a call to this method does not return. Pending `finally`
+ /// blocks are not executed, control flow will not go back to the event loop,
+ /// scheduled asynchronous asks will never run, and even pending isolate
+ /// control commands may be ignored. (The isolate will send messages to ports
+ /// already registered using [Isolate.addOnExitListener], but no further Dart
+ /// code will run in the isolate.)
+ ///
+ /// If [finalMessagePort] is provided, and the [message] can be sent through
+ /// it, then the message is sent through that port as the final operation of
+ /// the current isolate. The isolate terminates immediately after
+ /// that [SendPort.send] call returns.
+ ///
+ /// (If the port is a native port, one provided by [ReceivePort.sendPort]
+ /// or [RawReceivePort.sendPort], the system may be able to send this final
+ /// message more efficiently than normal port communication between live
+ /// isolates.)
+ external static Never exit([SendPort? finalMessagePort, Object? message]);
}
/// Sends messages to its [ReceivePort]s.
diff --git a/tests/corelib/symbol_arbitrary_string_test.dart b/tests/corelib/symbol_arbitrary_string_test.dart
index c4c4d25..ff6cf56 100644
--- a/tests/corelib/symbol_arbitrary_string_test.dart
+++ b/tests/corelib/symbol_arbitrary_string_test.dart
@@ -2,9 +2,9 @@
// 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.
-// Note that this library violates the formatting provided by `dartfmt` in
+// Note that this library violates the formatting provided by `dart format` in
// a few locations, to verify that `"""...""""z"` can be parsed as two
-// consecutive strings, `dartfmt` will insert whitespace before `"z"`.
+// consecutive strings, `dart format` will insert whitespace before `"z"`.
import 'package:expect/expect.dart';
diff --git a/tests/language/async_star/yield_statement_context_test.dart b/tests/language/async_star/yield_statement_context_test.dart
index 7320f02..2b3faa9 100644
--- a/tests/language/async_star/yield_statement_context_test.dart
+++ b/tests/language/async_star/yield_statement_context_test.dart
@@ -51,7 +51,7 @@
test('two labels on same line', () {
f() async* {
- // DO NOT RUN dartfmt on this file. The labels should be on the same.
+ // DO NOT RUN dart format on this file. The labels should be on the same.
// line. Originally VM issue #2238.
label1: label2: yield 0;
}
diff --git a/tests/language/null_aware/access_test.dart b/tests/language/null_aware/access_test.dart
index 3307440..6fc1daa 100644
--- a/tests/language/null_aware/access_test.dart
+++ b/tests/language/null_aware/access_test.dart
@@ -132,4 +132,7 @@
// ^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
// [cfe] Member not found: 'hashCode'.
+
+ // (C.staticInt?.floor())! can be assigned to int.
+ int y = (C.staticInt?.floor())!;
}
diff --git a/tests/language/redirecting/factory_bounds_test.dart b/tests/language/redirecting/factory_bounds_test.dart
index 694062e..fcc2f54 100644
--- a/tests/language/redirecting/factory_bounds_test.dart
+++ b/tests/language/redirecting/factory_bounds_test.dart
@@ -11,7 +11,7 @@
class Foobar<T> implements Foo<T> {}
class Bar<
- T // A comment to prevent dartfmt from joining the lines.
+ T // A comment to prevent dart format from joining the lines.
extends Foo<T> //# 00: ok
extends Baz<Foo<T>> //# 01: compile-time error
extends Foobar<T> //# 02: compile-time error
@@ -21,7 +21,7 @@
}
class Qux<
- T // A comment to prevent dartfmt from joining the lines.
+ T // A comment to prevent dart format from joining the lines.
extends Foo<T> //# 00: continued
extends Foo<T> //# 01: continued
extends Foo<T> //# 02: continued
@@ -33,7 +33,7 @@
class A<T extends int> {
factory A() = B<
- T // A comment to prevent dartfmt from joining the lines.
+ T // A comment to prevent dart format from joining the lines.
, int //# 03: compile-time error
, String //# 04: ok
>;
diff --git a/tests/language_2/async_star/yield_statement_context_test.dart b/tests/language_2/async_star/yield_statement_context_test.dart
index e512b3f..7e64c9b 100644
--- a/tests/language_2/async_star/yield_statement_context_test.dart
+++ b/tests/language_2/async_star/yield_statement_context_test.dart
@@ -53,7 +53,7 @@
test('two labels on same line', () {
f() async* {
- // DO NOT RUN dartfmt on this file. The labels should be on the same.
+ // DO NOT RUN dart format on this file. The labels should be on the same.
// line. Originally VM issue #2238.
label1: label2: yield 0;
}
diff --git a/tests/language_2/redirecting/factory_bounds_test.dart b/tests/language_2/redirecting/factory_bounds_test.dart
index 9fec8bd..f8fcca9 100644
--- a/tests/language_2/redirecting/factory_bounds_test.dart
+++ b/tests/language_2/redirecting/factory_bounds_test.dart
@@ -13,7 +13,7 @@
class Foobar<T> implements Foo<T> {}
class Bar<
- T // A comment to prevent dartfmt from joining the lines.
+ T // A comment to prevent dart format from joining the lines.
extends Foo<T> //# 00: ok
extends Baz<Foo<T>> //# 01: compile-time error
extends Foobar<T> //# 02: compile-time error
@@ -23,7 +23,7 @@
}
class Qux<
- T // A comment to prevent dartfmt from joining the lines.
+ T // A comment to prevent dart format from joining the lines.
extends Foo<T> //# 00: continued
extends Foo<T> //# 01: continued
extends Foo<T> //# 02: continued
@@ -35,7 +35,7 @@
class A<T extends int> {
factory A() = B<
- T // A comment to prevent dartfmt from joining the lines.
+ T // A comment to prevent dart format from joining the lines.
, int //# 03: compile-time error
, String //# 04: ok
>;
diff --git a/tests/lib/mirrors/invocation_fuzz_test.dart b/tests/lib/mirrors/invocation_fuzz_test.dart
index ea8f546..ed8ba09 100644
--- a/tests/lib/mirrors/invocation_fuzz_test.dart
+++ b/tests/lib/mirrors/invocation_fuzz_test.dart
@@ -20,6 +20,7 @@
// Don't exit the test pre-maturely.
'dart.io.exit',
+ 'dart.isolate.Isolate.exit',
// Don't change the exit code, which may fool the test harness.
'dart.io.exitCode',
diff --git a/tests/lib_2/mirrors/invocation_fuzz_test.dart b/tests/lib_2/mirrors/invocation_fuzz_test.dart
index 6323806..68360d1 100644
--- a/tests/lib_2/mirrors/invocation_fuzz_test.dart
+++ b/tests/lib_2/mirrors/invocation_fuzz_test.dart
@@ -22,6 +22,7 @@
// Don't exit the test pre-maturely.
'dart.io.exit',
+ 'dart.isolate.Isolate.exit',
// Don't change the exit code, which may fool the test harness.
'dart.io.exitCode',
diff --git a/tests/standalone/dwarf_stack_trace_invisible_functions_test.dart b/tests/standalone/dwarf_stack_trace_invisible_functions_test.dart
index b7247454..a9fe0f3 100644
--- a/tests/standalone/dwarf_stack_trace_invisible_functions_test.dart
+++ b/tests/standalone/dwarf_stack_trace_invisible_functions_test.dart
@@ -20,7 +20,7 @@
@pragma("vm:prefer-inline")
bar() {
// Keep the 'throw' and its argument on separate lines.
- throw // force linebreak with dartfmt // LINE_A
+ throw // force linebreak with dart format // LINE_A
"Hello, Dwarf!";
}
diff --git a/tests/standalone/dwarf_stack_trace_obfuscate_test.dart b/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
index f6b3360..23eb3f9 100644
--- a/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
+++ b/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
@@ -14,7 +14,7 @@
@pragma("vm:prefer-inline")
bar() {
// Keep the 'throw' and its argument on separate lines.
- throw // force linebreak with dartfmt
+ throw // force linebreak with dart format
"Hello, Dwarf!";
}
diff --git a/tests/standalone/dwarf_stack_trace_test.dart b/tests/standalone/dwarf_stack_trace_test.dart
index a583d34..970be0e 100644
--- a/tests/standalone/dwarf_stack_trace_test.dart
+++ b/tests/standalone/dwarf_stack_trace_test.dart
@@ -14,7 +14,7 @@
@pragma("vm:prefer-inline")
bar() {
// Keep the 'throw' and its argument on separate lines.
- throw // force linebreak with dartfmt
+ throw // force linebreak with dart format
"Hello, Dwarf!";
}
diff --git a/tests/standalone_2/dwarf_stack_trace_invisible_functions_test.dart b/tests/standalone_2/dwarf_stack_trace_invisible_functions_test.dart
index cd912fc..411ebd9 100644
--- a/tests/standalone_2/dwarf_stack_trace_invisible_functions_test.dart
+++ b/tests/standalone_2/dwarf_stack_trace_invisible_functions_test.dart
@@ -22,7 +22,7 @@
@pragma("vm:prefer-inline")
bar() {
// Keep the 'throw' and its argument on separate lines.
- throw // force linebreak with dartfmt // LINE_A
+ throw // force linebreak with dart format // LINE_A
"Hello, Dwarf!";
}
diff --git a/tests/standalone_2/dwarf_stack_trace_obfuscate_test.dart b/tests/standalone_2/dwarf_stack_trace_obfuscate_test.dart
index 8614b88..f21fff1 100644
--- a/tests/standalone_2/dwarf_stack_trace_obfuscate_test.dart
+++ b/tests/standalone_2/dwarf_stack_trace_obfuscate_test.dart
@@ -16,7 +16,7 @@
@pragma("vm:prefer-inline")
bar() {
// Keep the 'throw' and its argument on separate lines.
- throw // force linebreak with dartfmt
+ throw // force linebreak with dart format
"Hello, Dwarf!";
}
diff --git a/tests/standalone_2/dwarf_stack_trace_test.dart b/tests/standalone_2/dwarf_stack_trace_test.dart
index 75353ee..acc066b 100644
--- a/tests/standalone_2/dwarf_stack_trace_test.dart
+++ b/tests/standalone_2/dwarf_stack_trace_test.dart
@@ -16,7 +16,7 @@
@pragma("vm:prefer-inline")
bar() {
// Keep the 'throw' and its argument on separate lines.
- throw // force linebreak with dartfmt
+ throw // force linebreak with dart format
"Hello, Dwarf!";
}
diff --git a/tools/VERSION b/tools/VERSION
index 0fdd90e..4eb2c84 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 168
+PRERELEASE 169
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/sdks/README b/tools/sdks/README
index b7d766a5..0ef9f68 100644
--- a/tools/sdks/README
+++ b/tools/sdks/README
@@ -7,6 +7,6 @@
on ARM and ARM64 are also provided.
To upload new versions of these CIPD packages, run "./update.sh" in this
-directory. Because these SDKs are used for the presubmit dartfmt check on
-changed files, they may need to be updated often when dartfmt is changing
+directory. Because these SDKs are used for the presubmit dart format check on
+changed files, they may need to be updated often when dart format is changing
rapidly. Access to the project-dart-admins Luci auth group is required to do so.
diff --git a/tools/verify_docs/README.md b/tools/verify_docs/README.md
index 13f72bd..cc64017 100644
--- a/tools/verify_docs/README.md
+++ b/tools/verify_docs/README.md
@@ -20,5 +20,36 @@
## Authoring code samples
-TODO(devoncarew): Document the conventions for code samples in the dart: libraries
-and the tools available to configure them.
+### What gets analyzed
+
+This tool will walk all dartdoc api docs looking for code samples in doc comments.
+It will analyze any code sample in a `dart` code fence. For example:
+
+> ```dart
+> print('hello world!');
+> ```
+
+By default, an import for that library is added to the sample being analyzed (i.e.,
+`import 'dart:async";`). Additionally, the code sample is automatically embedded in
+the body of a simple main() method.
+
+### Excluding code samples from analysis
+
+In order to exclude a code sample from analysis, change it to a plain code fence style:
+
+> ```
+> print("I'm not analyzed :(");
+> ```
+
+### Specifying additional imports
+
+In order to reference code from other Dart core libraries, you can either explicitly add
+the import to the code sample - in-line in the sample - or use a directive on the same
+line as the code fence. The directive style looks like:
+
+> ```dart import:async
+> print('hello world ${Timer()}');
+> ```
+
+Multiple imports can be specified like this if desired (i.e., "```dart import:async import:convert").
+
diff --git a/tools/verify_docs/bin/verify_docs.dart b/tools/verify_docs/bin/verify_docs.dart
index ebd4822..8c4fc67 100644
--- a/tools/verify_docs/bin/verify_docs.dart
+++ b/tools/verify_docs/bin/verify_docs.dart
@@ -28,8 +28,10 @@
print('Validating the dartdoc code samples from the dart: libraries.');
print('');
print('To run this tool, run `dart tools/verify_docs/bin/verify_docs.dart`.');
+ print('');
print('For documentation about how to author dart: code samples,'
' see tools/verify_docs/README.md');
+ print('');
final coreLibraries = args.isEmpty
? libDir.listSync().whereType<Directory>().toList()
@@ -90,7 +92,6 @@
return error.errorCode.type == ErrorType.SYNTACTIC_ERROR;
}).toList();
if (syntacticErrors.isNotEmpty) {
- // todo: have a better failure mode
throw Exception(syntacticErrors);
}
@@ -108,21 +109,22 @@
return visitor.errors.isEmpty;
}
-/// todo: doc
+/// Visit a compilation unit and collect the list of code samples found in
+/// dartdoc comments.
class ValidateCommentCodeSamplesVisitor extends GeneralizingAstVisitor {
final String coreLibName;
final String filePath;
final LineInfo lineInfo;
+ final List<CodeSample> samples = [];
+ final StringBuffer errors = StringBuffer();
+
ValidateCommentCodeSamplesVisitor(
this.coreLibName,
this.filePath,
this.lineInfo,
);
- final List<CodeSample> samples = [];
- final StringBuffer errors = StringBuffer();
-
Future process(ParseStringResult parseResult) async {
// collect code samples
visitCompilationUnit(parseResult.unit);
@@ -135,7 +137,6 @@
@override
void visitAnnotatedNode(AnnotatedNode node) {
- // todo: ignore (or fail?) doc comments on non-public symbols
_handleDocumentableNode(node);
super.visitAnnotatedNode(node);
}
@@ -158,6 +159,11 @@
var offset = text.indexOf(sampleStart);
while (offset != -1) {
+ // Collect template directives, like "```dart import:async".
+ final codeFenceSuffix = text.substring(
+ offset + sampleStart.length, text.indexOf('\n', offset));
+ final directives = Set.unmodifiable(codeFenceSuffix.trim().split(' '));
+
offset = text.indexOf('\n', offset) + 1;
final end = text.indexOf(sampleEnd, offset);
@@ -166,13 +172,12 @@
List<String> lines = snippet.split('\n');
- // TODO(devoncarew): Also look for template directives.
-
samples.add(
CodeSample(
- coreLibName,
lines.map((e) => ' ${cleanDocLine(e)}').join('\n'),
- commentLineStart +
+ coreLibName: coreLibName,
+ directives: directives,
+ lineStartOffset: commentLineStart +
text.substring(0, offset - 1).split('\n').length -
1,
),
@@ -183,9 +188,6 @@
}
Future validateCodeSample(CodeSample sample) async {
- // TODO(devoncarew): Support <!-- template: none --> ?
- // TODO(devoncarew): Support <!-- template: main --> ?
-
final resourceProvider =
OverlayResourceProvider(PhysicalResourceProvider.INSTANCE);
@@ -212,6 +214,12 @@
text = "main() async {\n${text.trimRight()}\n}\n";
}
+ for (final directive
+ in sample.directives.where((str) => str.startsWith('import:'))) {
+ final libName = directive.substring('import:'.length);
+ text = "import 'dart:$libName';\n$text";
+ }
+
if (sample.coreLibName != 'internal') {
text = "import 'dart:${sample.coreLibName}';\n$text";
}
@@ -227,7 +235,7 @@
modificationStamp: 0,
);
- // TODO(devoncarew): refactor to use AnalysisContextCollection to avoid
+ // TODO(devoncarew): Refactor to use AnalysisContextCollection to avoid
// re-creating analysis contexts.
final result = await resolveFile2(
path: sampleFilePath,
@@ -239,8 +247,9 @@
if (result is ResolvedUnitResult) {
// Filter out unused imports, since we speculatively add imports to some
// samples.
- var errors =
- result.errors.where((e) => e.errorCode != HintCode.UNUSED_IMPORT);
+ var errors = result.errors.where(
+ (e) => e.errorCode != HintCode.UNUSED_IMPORT,
+ );
// Also, don't worry about 'unused_local_variable' and related; this may
// be intentional in samples.
@@ -250,8 +259,16 @@
e.errorCode != HintCode.UNUSED_ELEMENT,
);
+ // Remove warnings about deprecated member use from the same library.
+ errors = errors.where(
+ (e) =>
+ e.errorCode != HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE &&
+ e.errorCode !=
+ HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE,
+ );
+
if (errors.isNotEmpty) {
- print('$filePath:${sample.lineStart}: ${errors.length} errors');
+ print('$filePath:${sample.lineStartOffset}: ${errors.length} errors');
for (final error in errors) {
final location = result.lineInfo.getLocation(error.offset);
@@ -290,10 +307,16 @@
class CodeSample {
final String coreLibName;
+ final Set<String> directives;
final String text;
- final int lineStart;
+ final int lineStartOffset;
- CodeSample(this.coreLibName, this.text, this.lineStart);
+ CodeSample(
+ this.text, {
+ required this.coreLibName,
+ this.directives = const {},
+ required this.lineStartOffset,
+ });
}
String _severity(Severity severity) {