From 29f0f00c4dedb608091b995fedf7019f80e971ea Mon Sep 17 00:00:00 2001 From: Sydney Jodon Date: Thu, 24 Oct 2024 11:56:21 -0700 Subject: [PATCH] Update ClassComponentRequiredInitialStateMigrator suggestor --- ...lass_component_required_initial_state.dart | 5 + ...component_required_initial_state_test.dart | 123 ++++++++++++++++++ test/util/component_usage_migrator_test.dart | 4 +- 3 files changed, 130 insertions(+), 2 deletions(-) diff --git a/lib/src/dart3_suggestors/null_safety_prep/class_component_required_initial_state.dart b/lib/src/dart3_suggestors/null_safety_prep/class_component_required_initial_state.dart index c2085070..3488f42a 100644 --- a/lib/src/dart3_suggestors/null_safety_prep/class_component_required_initial_state.dart +++ b/lib/src/dart3_suggestors/null_safety_prep/class_component_required_initial_state.dart @@ -80,6 +80,11 @@ class ClassComponentRequiredInitialStateMigrator @override Future visitCascadeExpression(CascadeExpression node) async { + // Don't make any updates if the file is already null safe. + if (result.libraryElement.isNonNullableByDefault) { + return; + } + super.visitCascadeExpression(node); final isInitialState = [relevantGetterName, relevantMethodName].contains( diff --git a/test/dart3_suggestors/null_safety_prep/class_component_required_initial_state_test.dart b/test/dart3_suggestors/null_safety_prep/class_component_required_initial_state_test.dart index 1137b152..17d9810a 100644 --- a/test/dart3_suggestors/null_safety_prep/class_component_required_initial_state_test.dart +++ b/test/dart3_suggestors/null_safety_prep/class_component_required_initial_state_test.dart @@ -265,5 +265,128 @@ void main() { ); }); }); + + group('makes no update if file is already on a null safe Dart version', () { + final resolvedContext = SharedAnalysisContext.overReactNullSafe; + + // Warm up analysis in a setUpAll so that if getting the resolved AST times out + // (which is more common for the WSD context), it fails here instead of failing the first test. + setUpAll(resolvedContext.warmUpAnalysis); + + late SuggestorTester nullSafeTestSuggestor; + + setUp(() { + nullSafeTestSuggestor = getSuggestorTester( + ClassComponentRequiredInitialStateMigrator(), + resolvedContext: resolvedContext, + ); + }); + + test('', () async { + await nullSafeTestSuggestor( + expectedPatchCount: 0, + input: withOverReactImport(/*language=dart*/ r''' + // ignore: undefined_identifier + UiFactory Foo = castUiFactory(_$Foo); + mixin FooProps on UiProps {} + mixin FooStateMixin on UiState { + String? state1; + /// This is a doc comment + String? state2; + } + mixin SomeOtherStateMixin on UiState { + late num? state3; + } + class FooState = UiState with FooStateMixin, SomeOtherStateMixin; + class FooComponent extends UiStatefulComponent2 { + @override + get initialState => (newState() + ..state1 = 'foo' + ..state3 = null + ); + + @override + render() => null; + } + '''), + ); + }); + + test('unless there is a lang version comment', () async { + await nullSafeTestSuggestor( + expectedPatchCount: 5, + input: withOverReactImport(/*language=dart*/ r''' + // ignore: undefined_identifier + UiFactory Foo = castUiFactory(_$Foo); + mixin FooProps on UiProps {} + mixin FooStateMixin on UiState { + String notInitialized; + /// This is a doc comment + /*late*/ String/*!*/ alreadyPatched; + /*late*/ String/*!*/ alreadyPatchedButNoDocComment; + String initializedNullable; + num initializedNonNullable; + } + mixin SomeOtherStateMixin on UiState { + num anotherInitializedNonNullable; + Function initializedNonNullableFn; + List initializedNonNullableList; + } + class FooState = UiState with FooStateMixin, SomeOtherStateMixin; + class FooComponent extends UiStatefulComponent2 { + @override + get initialState => (newState() + ..alreadyPatched = 'foo' + ..initializedNullable = null + ..initializedNonNullable = 2.1 + ..anotherInitializedNonNullable = 1.1 + ..initializedNonNullableFn = () {} + ..initializedNonNullableList = [] + ); + + @override + render() => null; + } + ''', filePrefix: '// @dart=2.11\n'), + expectedOutput: withOverReactImport(/*language=dart*/ r''' + // ignore: undefined_identifier + UiFactory Foo = castUiFactory(_$Foo); + mixin FooProps on UiProps {} + mixin FooStateMixin on UiState { + String notInitialized; + /// This is a doc comment + /*late*/ String/*!*/ alreadyPatched; + /*late*/ String/*!*/ alreadyPatchedButNoDocComment; + /*late*/ String/*?*/ initializedNullable; + /*late*/ num/*!*/ initializedNonNullable; + } + mixin SomeOtherStateMixin on UiState { + /*late*/ num/*!*/ anotherInitializedNonNullable; + /*late*/ Function/*!*/ initializedNonNullableFn; + /*late*/ List/*!*/ initializedNonNullableList; + } + class FooState = UiState with FooStateMixin, SomeOtherStateMixin; + class FooComponent extends UiStatefulComponent2 { + @override + get initialState => (newState() + ..alreadyPatched = 'foo' + ..initializedNullable = null + ..initializedNonNullable = 2.1 + ..anotherInitializedNonNullable = 1.1 + ..initializedNonNullableFn = () {} + ..initializedNonNullableList = [] + ); + + @override + render() => null; + } + ''', filePrefix: '// @dart=2.11\n'), + // Ignore error on language version comment. + isExpectedError: (error) => + error.errorCode.name.toLowerCase() == + 'illegal_language_version_override', + ); + }); + }); }); } diff --git a/test/util/component_usage_migrator_test.dart b/test/util/component_usage_migrator_test.dart index c5913978..729bf5a4 100644 --- a/test/util/component_usage_migrator_test.dart +++ b/test/util/component_usage_migrator_test.dart @@ -1690,8 +1690,8 @@ class GenericMigrator extends ComponentUsageMigrator { const overReactImport = "import 'package:over_react/over_react.dart';"; -String withOverReactImport(String source) { - return '$overReactImport\n$source'; +String withOverReactImport(String source, {String filePrefix = ''}) { + return '$filePrefix$overReactImport\n$source'; } String fileWithCascadeOnUsage(String cascade) {