Version 2.12.0-1.0.dev
Merge commit '9ca05a40927142d3512b72055b72fccd7a1cc592' into 'dev'
diff --git a/pkg/analysis_server/lib/src/computer/import_elements_computer.dart b/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
index 8dc38a7..7f5a9a4 100644
--- a/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
+++ b/pkg/analysis_server/lib/src/computer/import_elements_computer.dart
@@ -325,7 +325,7 @@
var scope = libraryResult.libraryElement.scope;
if (prefix.isNotEmpty) {
- var prefixElement = scope.lookup2(prefix).getter;
+ var prefixElement = scope.lookup(prefix).getter;
if (prefixElement is PrefixElement) {
scope = prefixElement.scope;
} else {
@@ -333,7 +333,7 @@
}
}
- var lookupResult = scope.lookup2(name);
+ var lookupResult = scope.lookup(name);
return lookupResult.getter != null || lookupResult.setter != null;
}
diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
index 74b77aa..c31877f 100644
--- a/pkg/dartdev/lib/dartdev.dart
+++ b/pkg/dartdev/lib/dartdev.dart
@@ -2,7 +2,8 @@
// 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' as io;
+// Do not call exit() directly. Use VmInteropHandler.exit() instead.
+import 'dart:io' as io hide exit;
import 'dart:isolate';
import 'package:analyzer/src/dart/analysis/experiments.dart';
@@ -29,8 +30,7 @@
import 'src/vm_interop_handler.dart';
/// This is typically called from bin/, but given the length of the method and
-/// analytics logic, it has been moved here. Also note that this method calls
-/// [io.exit(code)] directly.
+/// analytics logic, it has been moved here.
Future<void> runDartdev(List<String> args, SendPort port) async {
VmInteropHandler.initialize(port);
@@ -69,13 +69,15 @@
// Alert the user that analytics has been disabled.
print(analyticsDisabledNoticeMessage);
- io.exit(0);
+ VmInteropHandler.exit(0);
+ return;
} else if (args.contains('--enable-analytics')) {
analytics.enabled = true;
// Alert the user again that anonymous data will be collected.
print(analyticsNoticeOnFirstRunMessage);
- io.exit(0);
+ VmInteropHandler.exit(0);
+ return;
}
try {
diff --git a/pkg/nnbd_migration/lib/migration_cli.dart b/pkg/nnbd_migration/lib/migration_cli.dart
index 34e70b7..d712d7b 100644
--- a/pkg/nnbd_migration/lib/migration_cli.dart
+++ b/pkg/nnbd_migration/lib/migration_cli.dart
@@ -314,11 +314,8 @@
CommandLineOptions.skipPubOutdatedFlag,
(parser, hide) => parser.addFlag(
CommandLineOptions.skipPubOutdatedFlag,
- // TODO(srawlins): Before "beta," change the default to "false," and
- // negatable to "false." See
- // https://github.com/dart-lang/sdk/issues/43774.
- defaultsTo: true,
- negatable: true,
+ defaultsTo: false,
+ negatable: false,
help:
'Skip the `pub outdated --mode=null-safety` check. This allows a '
'migration to proceed even if some package dependencies have not yet '
diff --git a/pkg/nnbd_migration/lib/nnbd_migration.dart b/pkg/nnbd_migration/lib/nnbd_migration.dart
index 7e9d2f8..087685d 100644
--- a/pkg/nnbd_migration/lib/nnbd_migration.dart
+++ b/pkg/nnbd_migration/lib/nnbd_migration.dart
@@ -117,6 +117,12 @@
kind: NullabilityFixKind.downcastExpression,
);
+ /// Informative message: there is no valid migration for `null` in a
+ /// non-nullable context.
+ static const noValidMigrationForNull = NullabilityFixDescription._(
+ appliedMessage: 'No valid migration for `null` in a non-nullable context',
+ kind: NullabilityFixKind.noValidMigrationForNull);
+
/// Informative message: a null-aware access won't be necessary in strong
/// checking mode.
static const nullAwarenessUnnecessaryInStrongMode =
@@ -276,6 +282,7 @@
downcastExpression,
makeTypeNullable,
makeTypeNullableDueToHint,
+ noValidMigrationForNull,
nullAwarenessUnnecessaryInStrongMode,
nullAwareAssignmentUnnecessaryInStrongMode,
otherCastExpression,
diff --git a/pkg/nnbd_migration/lib/src/fix_aggregator.dart b/pkg/nnbd_migration/lib/src/fix_aggregator.dart
index f6a9372..b006ba4 100644
--- a/pkg/nnbd_migration/lib/src/fix_aggregator.dart
+++ b/pkg/nnbd_migration/lib/src/fix_aggregator.dart
@@ -684,6 +684,10 @@
/// Implementation of [NodeChange] specialized for operating on [Expression]
/// nodes.
class NodeChangeForExpression<N extends Expression> extends NodeChange<N> {
+ bool _addsNoValidMigration = false;
+
+ AtomicEditInfo _addNoValidMigrationInfo;
+
bool _addsNullCheck = false;
AtomicEditInfo _addNullCheckInfo;
@@ -696,9 +700,15 @@
NodeChangeForExpression() : super._();
+ /// Gets the info for any added "no valid migration" comment.
+ AtomicEditInfo get addNoValidMigrationInfo => _addNoValidMigrationInfo;
+
/// Gets the info for any added null check.
AtomicEditInfo get addNullCheckInfo => _addNullCheckInfo;
+ /// Indicates whether [addNoValidMigration] has been called.
+ bool get addsNoValidMigration => _addsNoValidMigration;
+
/// Indicates whether [addNullCheck] has been called.
bool get addsNullCheck => _addsNullCheck;
@@ -711,10 +721,17 @@
@override
Iterable<String> get _toStringParts => [
+ if (_addsNoValidMigration) 'addsNoValidMigration',
if (_addsNullCheck) 'addsNullCheck',
if (_introducesAsType != null) 'introducesAsType'
];
+ void addNoValidMigration(AtomicEditInfo info) {
+ assert(!_addsNoValidMigration);
+ _addsNoValidMigration = true;
+ _addNoValidMigrationInfo = info;
+ }
+
/// Causes a null check to be added to this expression, with the given [info].
void addNullCheck(AtomicEditInfo info, {HintComment hint}) {
assert(!_addsNullCheck);
@@ -754,6 +771,11 @@
.addUnaryPostfix(plan, TokenType.BANG, info: _addNullCheckInfo);
}
}
+ if (_addsNoValidMigration) {
+ plan = aggregator.planner.addCommentPostfix(
+ plan, '/* no valid migration */',
+ info: _addNoValidMigrationInfo, isInformative: true);
+ }
if (_introducesAsType != null) {
plan = aggregator.planner.addBinaryPostfix(
plan, TokenType.AS, aggregator.typeToCode(_introducesAsType),
diff --git a/pkg/nnbd_migration/lib/src/fix_builder.dart b/pkg/nnbd_migration/lib/src/fix_builder.dart
index b3e2698..3699d66 100644
--- a/pkg/nnbd_migration/lib/src/fix_builder.dart
+++ b/pkg/nnbd_migration/lib/src/fix_builder.dart
@@ -573,12 +573,21 @@
{AtomicEditInfo info, HintComment hint}) {
var checks =
_fixBuilder._variables.expressionChecks(_fixBuilder.source, node);
+ bool noValidMigration = node is NullLiteral && hint == null;
info ??= checks != null
? AtomicEditInfo(
- NullabilityFixDescription.checkExpression, checks.edges)
+ noValidMigration
+ ? NullabilityFixDescription.noValidMigrationForNull
+ : NullabilityFixDescription.checkExpression,
+ checks.edges)
: null;
- (_fixBuilder._getChange(node) as NodeChangeForExpression)
- .addNullCheck(info, hint: hint);
+ var nodeChangeForExpression =
+ _fixBuilder._getChange(node) as NodeChangeForExpression;
+ if (noValidMigration) {
+ nodeChangeForExpression.addNoValidMigration(info);
+ } else {
+ nodeChangeForExpression.addNullCheck(info, hint: hint);
+ }
_flowAnalysis.nonNullAssert_end(node);
return _fixBuilder._typeSystem.promoteToNonNull(type as TypeImpl);
}
diff --git a/pkg/nnbd_migration/lib/src/front_end/info_builder.dart b/pkg/nnbd_migration/lib/src/front_end/info_builder.dart
index 01a0d05..2f9f0fb 100644
--- a/pkg/nnbd_migration/lib/src/front_end/info_builder.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/info_builder.dart
@@ -211,6 +211,10 @@
// their "OrNull" equivalents. We don't offer any hints around
// this transformation.
break;
+ case NullabilityFixKind.noValidMigrationForNull:
+ // We don't offer any edits around unmigratable `null`s. The user has
+ // to fix manually.
+ break;
}
return edits;
}
diff --git a/pkg/nnbd_migration/lib/src/front_end/migration_summary.dart b/pkg/nnbd_migration/lib/src/front_end/migration_summary.dart
index 3d74d30..a551df2 100644
--- a/pkg/nnbd_migration/lib/src/front_end/migration_summary.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/migration_summary.dart
@@ -94,6 +94,8 @@
return 'makeTypeNullable';
case NullabilityFixKind.makeTypeNullableDueToHint:
return 'makeTypeNullableDueToHint';
+ case NullabilityFixKind.noValidMigrationForNull:
+ return 'noValidMigrationForNull';
case NullabilityFixKind.nullAwarenessUnnecessaryInStrongMode:
return 'nullAwarenessUnnecessaryInStrongMode';
case NullabilityFixKind.nullAwareAssignmentUnnecessaryInStrongMode:
diff --git a/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart b/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart
index 7a2ae53..3c09f9b 100644
--- a/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart
@@ -4,7 +4,6 @@
import 'dart:convert' show jsonDecode, JsonEncoder;
-import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/file_system/file_system.dart';
@@ -30,11 +29,11 @@
// TODO(srawlins): Refactor to use
// `Feature.non_nullable.releaseVersion` when this becomes non-null (perhaps
// after "Beta").
- static final Version _intendedMinimumSdkVersion =
- Feature.non_nullable.experimentalReleaseVersion;
+ static final Version _intendedMinimumSdkVersion = Version.parse('2.12.0-0');
// In the package_config.json file, the patch number is omitted.
- static const String _intendedLanguageVersion = '2.10';
+ static final String _intendedLanguageVersion =
+ '${_intendedMinimumSdkVersion.major}.${_intendedMinimumSdkVersion.minor}';
static final String _intendedSdkVersionConstraint =
'>=$_intendedMinimumSdkVersion <2.12.0';
@@ -153,9 +152,6 @@
if (updated) {
_processConfigFile(pkgFolder, pubspec);
}
- // TODO(https://github.com/dart-lang/sdk/issues/43806): stop processing
- // analysis options file when the experiment is no longer needed.
- _processAnalysisOptionsFile(pkgFolder);
}
Future<void> processUnit(ResolvedUnitResult result) async {
@@ -212,91 +208,6 @@
}
}
- void _processAnalysisOptionsException(
- String action, String analysisOptionsPath, error) {
- listener.addRecommendation('''Failed to $action analysis options file
- $analysisOptionsPath
- $error
-
- Manually update this file to enable the Null Safety language feature in static
- analysis by adding:
-
- analyzer:
- enable-experiment:
- - non-nullable
-''');
- }
-
- void _processAnalysisOptionsFile(Folder pkgFolder) {
- var analysisOptionsFile =
- pkgFolder.getChildAssumingFile('analysis_options.yaml');
- if (!analysisOptionsFile.exists) {
- // A source file edit cannot be made for a file which doesn't exist.
- // Instead of using the fix listener, just write the file directly.
- analysisOptionsFile.writeAsStringSync('''
-analyzer:
- enable-experiment:
- - non-nullable
-
-''');
- return;
- }
-
- _YamlFile analysisOptions;
- try {
- analysisOptions = _YamlFile._parseFrom(analysisOptionsFile);
- } on FileSystemException catch (e) {
- _processAnalysisOptionsException('read', analysisOptionsFile.path, e);
- return;
- } on FormatException catch (e) {
- _processAnalysisOptionsException('parse', analysisOptionsFile.path, e);
- return;
- }
-
- var analysisOptionsMap = analysisOptions.content;
- YamlNode analyzerOptions;
- if (analysisOptionsMap is YamlMap) {
- analyzerOptions = analysisOptionsMap.nodes['analyzer'];
- }
- if (analyzerOptions == null) {
- // There is no top-level "analyzer" section. We can write one in its
- // entirety, and use a 2-space indentation. This is a valid indentation,
- // even if the file contains another top-level section (perhaps "linter")
- // which uses a different indentation.
- var start = SourceLocation(0, line: 0, column: 0);
- var content = '''
-analyzer:
- enable-experiment:
- - non-nullable
-
-''';
- analysisOptions._insertAfterParent(
- SourceSpan(start, start, ''), content, listener);
- } else if (analyzerOptions is YamlMap) {
- var enableExperiment = analyzerOptions.nodes['enable-experiment'];
- if (enableExperiment == null) {
- var analyzerIndentation =
- analysisOptions._getMapEntryIndentation(analyzerOptions);
- var indent = ' ' * analyzerIndentation;
- var content = '\n'
- '${indent}enable-experiment:\n'
- '$indent - non-nullable';
- analysisOptions._insertAfterParent(
- analyzerOptions.span, content, listener);
- } else if (enableExperiment is YamlList) {
- var enableExperimentIndentation =
- analysisOptions._getListIndentation(enableExperiment);
- var indent = ' ' * enableExperimentIndentation;
- var nonNullableIsEnabled = enableExperiment.value
- .any((experiment) => experiment == 'non-nullable');
- if (nonNullableIsEnabled) return;
- var content = '\n' '$indent- non-nullable';
- analysisOptions._insertAfterParent(
- enableExperiment.span, content, listener);
- }
- }
- }
-
/// Updates the Package Config file to specify a minimum Dart SDK version
/// which supports null safety.
void _processConfigFile(Folder pkgFolder, _YamlFile pubspec) {
@@ -516,7 +427,6 @@
}
class _YamlFile {
- static final _newlineCharacter = RegExp('[\r\n]');
final String path;
final String textContent;
@@ -524,40 +434,6 @@
_YamlFile._(this.path, this.textContent, this.content);
- /// Returns the indentation of the entries in [node].
- int _getListIndentation(YamlList node) {
- return node.span.start.column;
- }
-
- /// Returns the indentation of the first (and presumably all) entry of [node].
- int _getMapEntryIndentation(YamlMap node) {
- if (node.isEmpty) return 2;
-
- var value = node.nodes.values.first;
- if (value is YamlScalar) {
- // A YamlScalar value indicates that a "key: value" pair is on a single
- // line. The span's start column is the start column of the value, not the
- // key.
- var offset = value.span.start.offset;
- var firstSpaceIndex =
- textContent.lastIndexOf(_newlineCharacter, offset) + 1;
- var index = firstSpaceIndex;
- while (textContent.codeUnitAt(index) == $space) {
- index++;
- }
- return index - firstSpaceIndex;
- } else if (value is YamlMap) {
- // If the first entry of [node] is a YamlMap, then the span for [node]
- // indicates the start of the first entry.
- return node.span.start.column;
- } else {
- assert(value is YamlList);
- // If the first entry of [node] is a YamlList, then the span for [value]
- // indicates the start of the first list entry.
- return value.span.start.column;
- }
- }
-
String _getName() {
YamlNode packageNameNode;
diff --git a/pkg/nnbd_migration/lib/src/front_end/unit_renderer.dart b/pkg/nnbd_migration/lib/src/front_end/unit_renderer.dart
index b76c5ff..cddd307 100644
--- a/pkg/nnbd_migration/lib/src/front_end/unit_renderer.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/unit_renderer.dart
@@ -23,6 +23,7 @@
/// "proposed edits" area, in the order in which they should be displayed.
@visibleForTesting
static const List<NullabilityFixKind> kindPriorityOrder = [
+ NullabilityFixKind.noValidMigrationForNull,
NullabilityFixKind.compoundAssignmentHasBadCombinedType,
NullabilityFixKind.compoundAssignmentHasNullableSource,
NullabilityFixKind.removeDeadCode,
@@ -316,6 +317,8 @@
return '$count type$s made nullable';
case NullabilityFixKind.makeTypeNullableDueToHint:
return '$count nullability hint$s converted to ?$s';
+ case NullabilityFixKind.noValidMigrationForNull:
+ return '$count literal `null`$s could not be migrated';
case NullabilityFixKind.nullAwarenessUnnecessaryInStrongMode:
return '$count null-aware access$es will be unnecessary in strong '
'checking mode';
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 2100509..81066cf 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -785,27 +785,27 @@
Future<void> test_conditional_expression_guard_subexpression() async {
var content = '''
-void f(String s, int x) {
- s == null ? (x = null) : (x = s.length);
+void f(String s, int x, int/*?*/ n) {
+ s == null ? (x = n) : (x = s.length);
}
''';
var expected = '''
-void f(String s, int x) {
- s == null ? (x = null!) : (x = s.length);
+void f(String s, int x, int? n) {
+ s == null ? (x = n!) : (x = s.length);
}
''';
await _checkSingleFileChanges(content, expected, warnOnWeakCode: true);
}
Future<void> test_conditional_expression_guard_value_ifFalse() async {
- var content = 'int f(String s) => s != null ? s.length : null;';
- var expected = 'int f(String s) => s != null ? s.length : null!;';
+ var content = 'int f(String s, int/*?*/ n) => s != null ? s.length : n;';
+ var expected = 'int f(String s, int? n) => s != null ? s.length : n!;';
await _checkSingleFileChanges(content, expected, warnOnWeakCode: true);
}
Future<void> test_conditional_expression_guard_value_ifTrue() async {
- var content = 'int f(String s) => s == null ? null : s.length;';
- var expected = 'int f(String s) => s == null ? null! : s.length;';
+ var content = 'int f(String s, int/*?*/ n) => s == null ? n : s.length;';
+ var expected = 'int f(String s, int? n) => s == null ? n! : s.length;';
await _checkSingleFileChanges(content, expected, warnOnWeakCode: true);
}
@@ -3879,16 +3879,16 @@
class C<T extends Object/*!*/> {
C(T/*!*/ t);
}
-main() {
- C<int> c = C<int>(null);
+test(int/*?*/ n) {
+ C<int> c = C<int>(n);
}
''';
var expected = '''
class C<T extends Object> {
C(T t);
}
-main() {
- C<int> c = C<int>(null!);
+test(int? n) {
+ C<int> c = C<int>(n!);
}
''';
await _checkSingleFileChanges(content, expected);
@@ -3920,16 +3920,16 @@
class C<T extends Object/*!*/> {
C(T/*!*/ t);
}
-main() {
- C<int> c = C(null);
+test(int/*?*/ n) {
+ C<int> c = C(n);
}
''';
var expected = '''
class C<T extends Object> {
C(T t);
}
-main() {
- C<int> c = C(null!);
+test(int? n) {
+ C<int> c = C(n!);
}
''';
await _checkSingleFileChanges(content, expected);
@@ -4372,6 +4372,22 @@
{path2: file2, path1: file1}, {path1: expected1, path2: expected2});
}
+ Future<void> test_literal_null_without_valid_migration() async {
+ var content = '''
+void f(int/*!*/ x) {}
+void g() {
+ f(null);
+}
+''';
+ var expected = '''
+void f(int x) {}
+void g() {
+ f(null);
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
Future<void> test_literals_maintain_nullability() async {
// See #40590. Without exact nullability, this would migrate to
// `List<int?> list = <int>[1, 2]`. While the function of exact nullability
@@ -4705,14 +4721,14 @@
test_methodInvocation_typeArguments_explicit_nonNullable() async {
var content = '''
T f<T extends Object/*!*/>(T/*!*/ t) => t;
-void g() {
- int x = f<int>(null);
+void g(int/*?*/ n) {
+ int x = f<int>(n);
}
''';
var expected = '''
T f<T extends Object>(T t) => t;
-void g() {
- int x = f<int>(null!);
+void g(int? n) {
+ int x = f<int>(n!);
}
''';
await _checkSingleFileChanges(content, expected);
@@ -4755,14 +4771,14 @@
test_methodInvocation_typeArguments_inferred_nonNullable() async {
var content = '''
T f<T extends Object/*!*/>(T/*!*/ t) => t;
-void g() {
- int x = f(null);
+void g(int/*?*/ n) {
+ int x = f(n);
}
''';
var expected = '''
T f<T extends Object>(T t) => t;
-void g() {
- int x = f(null!);
+void g(int? n) {
+ int x = f(n!);
}
''';
await _checkSingleFileChanges(content, expected);
@@ -7079,8 +7095,8 @@
}
i4.toDouble();
}
-main() {
- g(false, null, null);
+test(int/*?*/ n) {
+ g(false, n, null);
}
''';
var expected = '''
@@ -7097,8 +7113,8 @@
}
i4!.toDouble();
}
-main() {
- g(false, null!, null);
+test(int? n) {
+ g(false, n!, null);
}
''';
await _checkSingleFileChanges(content, expected);
diff --git a/pkg/nnbd_migration/test/fix_aggregator_test.dart b/pkg/nnbd_migration/test/fix_aggregator_test.dart
index e0839dc..123de0a 100644
--- a/pkg/nnbd_migration/test/fix_aggregator_test.dart
+++ b/pkg/nnbd_migration/test/fix_aggregator_test.dart
@@ -1134,6 +1134,16 @@
expect(previewInfo, null);
}
+ Future<void> test_noValidMigration() async {
+ await analyze('f(a) => null;');
+ var literal = findNode.nullLiteral('null');
+ var previewInfo = run(
+ {literal: NodeChangeForExpression()..addNoValidMigration(_MockInfo())});
+ expect(previewInfo.applyTo(code), code);
+ expect(previewInfo.applyTo(code, includeInformative: true),
+ 'f(a) => null /* no valid migration */;');
+ }
+
Future<void> test_nullCheck_index_cascadeResult() async {
await analyze('f(a) => a..[0].c;');
var index = findNode.index('[0]');
diff --git a/pkg/nnbd_migration/test/fix_builder_test.dart b/pkg/nnbd_migration/test/fix_builder_test.dart
index 1795fb0..29e39622 100644
--- a/pkg/nnbd_migration/test/fix_builder_test.dart
+++ b/pkg/nnbd_migration/test/fix_builder_test.dart
@@ -68,6 +68,9 @@
static final isNodeChangeForExpression =
TypeMatcher<NodeChangeForExpression>();
+ static final isNoValidMigration =
+ isNodeChangeForExpression.havingNoValidMigrationWithInfo(anything);
+
static final isNullCheck =
isNodeChangeForExpression.havingNullCheckWithInfo(anything);
@@ -2060,6 +2063,16 @@
visitSubexpression(assignment, 'int?');
}
+ Future<void> test_nullable_value_in_null_context() async {
+ await analyze('int/*!*/ f(int/*?*/ i) => i;');
+ var iRef = findNode.simple('i;');
+ visitSubexpression(iRef, 'int', changes: {
+ iRef: isNodeChangeForExpression.havingNullCheckWithInfo(isInfo(
+ NullabilityFixDescription.checkExpression,
+ {FixReasonTarget.root: TypeMatcher<NullabilityEdge>()}))
+ });
+ }
+
Future<void> test_nullAssertion_promotes() async {
await analyze('''
_f(bool/*?*/ x) => x && x;
@@ -2077,6 +2090,36 @@
visitSubexpression(findNode.nullLiteral('null'), 'Null');
}
+ Future<void> test_nullLiteral_hinted() async {
+ await analyze('''
+int/*!*/ f() => null/*!*/;
+''');
+ var literal = findNode.nullLiteral('null');
+ // Normally we would leave the null literal alone and add an informative
+ // comment saying there's no valid migration for it. But since the user
+ // specifically hinted that `!` should be added, we respect that.
+ visitSubexpression(literal, 'Never', changes: {
+ literal: isNodeChangeForExpression.havingNullCheckWithInfo(isInfo(
+ NullabilityFixDescription.checkExpressionDueToHint,
+ {FixReasonTarget.root: TypeMatcher<FixReason_NullCheckHint>()}))
+ });
+ }
+
+ Future<void> test_nullLiteral_noValidMigration() async {
+ await analyze('''
+int/*!*/ f() => null;
+''');
+ var literal = findNode.nullLiteral('null');
+ // Note: in spite of the fact that we leave the literal as `null`, we
+ // analyze it as though it has type `Never`, because it's in a context where
+ // `null` doesn't work.
+ visitSubexpression(literal, 'Never', changes: {
+ literal: isNodeChangeForExpression.havingNoValidMigrationWithInfo(isInfo(
+ NullabilityFixDescription.noValidMigrationForNull,
+ {FixReasonTarget.root: TypeMatcher<NullabilityEdge>()}))
+ });
+ }
+
Future<void> test_parenthesizedExpression() async {
await analyze('''
f() => (1);
@@ -3516,6 +3559,12 @@
having((c) => c.addsNullCheck, 'addsNullCheck', true)
.having((c) => c.addNullCheckInfo, 'addNullCheckInfo', matcher);
+ TypeMatcher<NodeChangeForExpression> havingNoValidMigrationWithInfo(
+ dynamic matcher) =>
+ having((c) => c.addsNoValidMigration, 'addsNoValidMigration', true)
+ .having((c) => c.addNoValidMigrationInfo, 'addNoValidMigrationInfo',
+ matcher);
+
TypeMatcher<NodeChangeForExpression> havingIndroduceAsWithInfo(
dynamic typeStringMatcher, dynamic infoMatcher) =>
having((c) => c.introducesAsType.toString(), 'introducesAsType (string)',
diff --git a/pkg/nnbd_migration/test/migration_cli_test.dart b/pkg/nnbd_migration/test/migration_cli_test.dart
index e27e23b..c62fc75 100644
--- a/pkg/nnbd_migration/test/migration_cli_test.dart
+++ b/pkg/nnbd_migration/test/migration_cli_test.dart
@@ -432,7 +432,7 @@
'''
name: test
environment:
- sdk: '${migrated ? '>=2.10.0 <2.12.0' : '>=2.6.0 <3.0.0'}'
+ sdk: '${migrated ? '>=2.12.0-0 <2.12.0' : '>=2.6.0 <3.0.0'}'
''',
'.dart_tool/package_config.json':
packageConfigText ?? _getPackageConfigText(migrated: migrated),
@@ -449,210 +449,6 @@
NonNullableFix.shutdownAllServers();
}
- test_analysis_options_analyzer_is_missing_enable_experiment() async {
- var projectContents = simpleProject(analysisOptionsText: '''
-analyzer:
- foo: 1
-''');
- var projectDir = createProjectDir(projectContents);
- var cliRunner = _createCli()
- .decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- await cliRunner.run();
- // The Dart source code should still be migrated.
- assertProjectContents(
- projectDir, simpleProject(migrated: true, analysisOptionsText: '''
-analyzer:
- foo: 1
- enable-experiment:
- - non-nullable
-'''));
- }
-
- test_analysis_options_analyzer_is_missing_enable_experiment_big_indent() async {
- var projectContents = simpleProject(analysisOptionsText: '''
-analyzer:
- foo: 1
-''');
- var projectDir = createProjectDir(projectContents);
- var cliRunner = _createCli()
- .decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- await cliRunner.run();
- // The Dart source code should still be migrated.
- assertProjectContents(
- projectDir, simpleProject(migrated: true, analysisOptionsText: '''
-analyzer:
- foo: 1
- enable-experiment:
- - non-nullable
-'''));
- }
-
- test_analysis_options_analyzer_is_missing_enable_experiment_nested_map() async {
- var projectContents = simpleProject(analysisOptionsText: '''
-analyzer:
- exclude:
- foo:
- bar: 1
-''');
- var projectDir = createProjectDir(projectContents);
- var cliRunner = _createCli()
- .decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- await cliRunner.run();
- // The Dart source code should still be migrated.
- assertProjectContents(
- projectDir, simpleProject(migrated: true, analysisOptionsText: '''
-analyzer:
- exclude:
- foo:
- bar: 1
- enable-experiment:
- - non-nullable
-'''));
- }
-
- test_analysis_options_analyzer_is_not_a_map() async {
- var analysisOptionsText = '''
-analyzer: 1
-''';
- var projectContents =
- simpleProject(analysisOptionsText: analysisOptionsText);
- var projectDir = createProjectDir(projectContents);
- var cliRunner = _createCli()
- .decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- await cliRunner.run();
- // The Dart source code should still be migrated.
- assertProjectContents(
- projectDir,
- simpleProject(
- migrated: true, analysisOptionsText: analysisOptionsText));
- }
-
- test_analysis_options_does_not_exist() async {
- var projectContents = simpleProject();
- var projectDir = createProjectDir(projectContents);
- var cliRunner = _createCli()
- .decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- await cliRunner.run();
- // The Dart source code should still be migrated.
- assertProjectContents(
- projectDir, simpleProject(migrated: true, analysisOptionsText: '''
-analyzer:
- enable-experiment:
- - non-nullable
-
-'''));
- }
-
- test_analysis_options_enable_experiment_contains_non_nullable() async {
- var analysisOptionsText = '''
-analyzer:
- enable-experiment:
- - non-nullable
-''';
- var projectContents =
- simpleProject(analysisOptionsText: analysisOptionsText);
- var projectDir = createProjectDir(projectContents);
- var cliRunner = _createCli()
- .decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- await cliRunner.run();
- // The Dart source code should still be migrated.
- assertProjectContents(
- projectDir,
- simpleProject(
- migrated: true, analysisOptionsText: analysisOptionsText));
- }
-
- test_analysis_options_enable_experiment_is_not_list() async {
- var analysisOptionsText = '''
-analyzer:
- enable-experiment: 1
-''';
- var projectContents =
- simpleProject(analysisOptionsText: analysisOptionsText);
- var projectDir = createProjectDir(projectContents);
- var cliRunner = _createCli()
- .decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- await cliRunner.run();
- // The Dart source code should still be migrated.
- assertProjectContents(
- projectDir,
- simpleProject(
- migrated: true, analysisOptionsText: analysisOptionsText));
- }
-
- test_analysis_options_enable_experiment_missing_non_nullable() async {
- var analysisOptionsText = '''
-analyzer:
- enable-experiment:
- - foo
-''';
- var projectContents =
- simpleProject(analysisOptionsText: analysisOptionsText);
- var projectDir = createProjectDir(projectContents);
- var cliRunner = _createCli()
- .decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- await cliRunner.run();
- // The Dart source code should still be migrated.
- assertProjectContents(
- projectDir, simpleProject(migrated: true, analysisOptionsText: '''
-analyzer:
- enable-experiment:
- - foo
- - non-nullable
-'''));
- }
-
- test_analysis_options_enable_experiment_missing_non_nullable_big_indent() async {
- var analysisOptionsText = '''
-analyzer:
- enable-experiment:
- - foo
-''';
- var projectContents =
- simpleProject(analysisOptionsText: analysisOptionsText);
- var projectDir = createProjectDir(projectContents);
- var cliRunner = _createCli()
- .decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- await cliRunner.run();
- // The Dart source code should still be migrated.
- assertProjectContents(
- projectDir, simpleProject(migrated: true, analysisOptionsText: '''
-analyzer:
- enable-experiment:
- - foo
- - non-nullable
-'''));
- }
-
- test_analysis_options_is_missing_analyzer() async {
- var projectContents = simpleProject(analysisOptionsText: '''
-name: test
-''');
- var projectDir = createProjectDir(projectContents);
- var cliRunner = _createCli()
- .decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- await cliRunner.run();
- // The Dart source code should still be migrated.
- assertProjectContents(
- projectDir, simpleProject(migrated: true, analysisOptionsText:
- // This is strange-looking, but valid.
- '''
-analyzer:
- enable-experiment:
- - non-nullable
-
-name: test
-'''));
- }
-
- test_analysis_options_is_not_a_map() async {
- var projectContents = simpleProject(analysisOptionsText: 'not-a-map');
- var projectDir = createProjectDir(projectContents);
- var cliRunner = _createCli()
- .decodeCommandLineArgs(_parseArgs(['--apply-changes', projectDir]));
- expect(() async => await cliRunner.run(), throwsUnsupportedError);
- }
-
test_default_logger() {
// When running normally, we don't override the logger; make sure it has a
// non-null default so that there won't be a crash.
@@ -772,7 +568,12 @@
}
test_flag_skip_pub_outdated_default() {
- expect(assertParseArgsSuccess([]).skipPubOutdated, isTrue);
+ expect(assertParseArgsSuccess([]).skipPubOutdated, isFalse);
+ }
+
+ test_flag_skip_pub_outdated_disable() async {
+ // "--no-skip-pub-outdated" is not an option.
+ await assertParseArgsFailure(['--no-skip-pub-outdated']);
}
test_flag_skip_pub_outdated_enable() {
@@ -780,11 +581,6 @@
isTrue);
}
- test_flag_skip_pub_outdated_negated() async {
- expect(assertParseArgsSuccess(['--no-skip-pub-outdated']).skipPubOutdated,
- isFalse);
- }
-
test_flag_web_preview_default() {
expect(assertParseArgsSuccess([]).webPreview, isTrue);
}
@@ -1524,8 +1320,7 @@
}
''' /* stdout */,
'' /* stderr */);
- var output = await assertRunFailure([projectDir, '--no-skip-pub-outdated'],
- expectedExitCode: 1);
+ var output = await assertRunFailure([projectDir], expectedExitCode: 1);
expect(output,
contains('Warning: not all current dependencies have migrated'));
}
@@ -1999,7 +1794,7 @@
name: test
environment:
foo: 1
- sdk: '>=2.10.0 <2.12.0'
+ sdk: '>=2.12.0-0 <2.12.0'
'''));
}
@@ -2052,7 +1847,7 @@
// This is strange-looking, but valid.
'''
environment:
- sdk: '>=2.10.0 <2.12.0'
+ sdk: '>=2.12.0-0 <2.12.0'
name: test
'''));
@@ -2115,7 +1910,7 @@
"name": "test",
"rootUri": "../",
"packageUri": "lib/",
- "languageVersion": "${migrated ? '2.10' : '2.6'}"
+ "languageVersion": "${migrated ? '2.12' : '2.6'}"
}
]
}
diff --git a/runtime/bin/dartdev_isolate.cc b/runtime/bin/dartdev_isolate.cc
index c5a8908..0153f2f 100644
--- a/runtime/bin/dartdev_isolate.cc
+++ b/runtime/bin/dartdev_isolate.cc
@@ -145,9 +145,7 @@
// If we're given a non-zero exit code, DartDev is signaling for us to
// shutdown.
- if (dartdev_exit_code != 0) {
- Process::SetGlobalExitCode(dartdev_exit_code);
- }
+ Process::SetGlobalExitCode(dartdev_exit_code);
// If DartDev hasn't signaled for us to do anything else, we can assume
// there's nothing else for the VM to run and that we can exit.
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 8ab0091..16fca32 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -4841,6 +4841,10 @@
"<extractor parameter names>");
s->AddBaseObject(Object::empty_context_scope().raw(), "ContextScope",
"<empty>");
+ s->AddBaseObject(Object::empty_object_pool().raw(), "ObjectPool",
+ "<empty>");
+ s->AddBaseObject(Object::empty_compressed_stackmaps().raw(),
+ "CompressedStackMaps", "<empty>");
s->AddBaseObject(Object::empty_descriptors().raw(), "PcDescriptors",
"<empty>");
s->AddBaseObject(Object::empty_var_descriptors().raw(),
@@ -4925,6 +4929,8 @@
ASSERT(Object::extractor_parameter_names().raw() != Object::null());
d->AddBaseObject(Object::extractor_parameter_names().raw());
d->AddBaseObject(Object::empty_context_scope().raw());
+ d->AddBaseObject(Object::empty_object_pool().raw());
+ d->AddBaseObject(Object::empty_compressed_stackmaps().raw());
d->AddBaseObject(Object::empty_descriptors().raw());
d->AddBaseObject(Object::empty_var_descriptors().raw());
d->AddBaseObject(Object::empty_exception_handlers().raw());
diff --git a/tools/FAKE_COMMITS b/tools/FAKE_COMMITS
index 2a622d1..471f72f 100644
--- a/tools/FAKE_COMMITS
+++ b/tools/FAKE_COMMITS
@@ -26,6 +26,8 @@
Force build while trybots are broken, to check builders for brokenness.
Force build to test recipe changes
Force build to test recipe changes
+Trigger bots
+Trigger bots
Analyzer branch commits:
Force build on new analyzer-branch linux build with new workflow
diff --git a/tools/VERSION b/tools/VERSION
index 966c0c1..ca382e0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 0
+PRERELEASE 1
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/flutter/analyze_flutter_engine.sh b/tools/bots/flutter/analyze_flutter_engine.sh
index bdf8244..eac0e39 100755
--- a/tools/bots/flutter/analyze_flutter_engine.sh
+++ b/tools/bots/flutter/analyze_flutter_engine.sh
@@ -25,6 +25,8 @@
# analyze lib/web_ui
echo Analyzing lib/web_ui...
pushd lib/web_ui
+
$dart pub get
-$dart analyze
+$dart analyze --fatal-infos
+
popd