From 94f20d77314a91489e2c32fd144b81f506822561 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Fri, 16 Dec 2022 00:47:49 +0000 Subject: [PATCH] Revert "Remove all support for all strong-mode analysis options" This reverts ea120b5d441edd0803e8313b2a1f706db793c855 Change-Id: I97a1bf6ced06bf8bcab50a2fdb41732f13182a84 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/276026 Reviewed-by: Siva Annamalai Commit-Queue: Samuel Rawlins Reviewed-by: Brian Wilkerson --- CHANGELOG.md | 7 - .../yaml/analysis_options_generator.dart | 5 + .../services/correction/error_fix_status.yaml | 57 +++++ .../fix/analysis_options/fix_generator.dart | 3 + .../lib/src/status/diagnostics.dart | 2 + .../test/abstract_context.dart | 8 +- .../notification_analysis_options_test.dart | 2 +- .../test/analysis_server_base.dart | 7 + .../src/analytics/analytics_manager_test.dart | 8 +- .../flutter_outline_notification_test.dart | 2 +- .../analysis_options/remove_setting_test.dart | 7 + .../fix/change_type_annotation_test.dart | 13 ++ .../error/option_codes.g.dart | 19 ++ pkg/analyzer/lib/src/context/context.dart | 4 + pkg/analyzer/lib/src/dart/constant/value.dart | 1 + .../lib/src/dart/element/type_system.dart | 15 +- .../lib/src/dart/micro/resolve_file.dart | 1 + pkg/analyzer/lib/src/error/codes.g.dart | 120 ++++++++++ .../lib/src/error/error_code_values.g.dart | 12 + .../src/error/type_arguments_verifier.dart | 60 +++++ pkg/analyzer/lib/src/generated/engine.dart | 20 ++ .../lib/src/generated/error_verifier.dart | 97 ++++++++ pkg/analyzer/lib/src/task/options.dart | 103 ++++++++ pkg/analyzer/messages.yaml | 65 ++++++ .../test/generated/test_analysis_context.dart | 2 + .../analysis_options_provider_test.dart | 4 +- .../test/source/error_processor_test.dart | 8 + .../dart/analysis/context_builder_test.dart | 2 + .../dart/micro/simple_file_resolver_test.dart | 32 +-- .../context_collection_resolution.dart | 36 +++ .../argument_type_not_assignable_test.dart | 27 +++ ...field_initializer_not_assignable_test.dart | 18 ++ .../implicit_dynamic_field_test.dart | 120 ++++++++++ .../implicit_dynamic_function_test.dart | 142 ++++++++++++ .../implicit_dynamic_list_literal_test.dart | 92 ++++++++ .../implicit_dynamic_map_literal_test.dart | 100 ++++++++ .../diagnostics/invalid_assignment_test.dart | 72 ++++++ ...list_element_type_not_assignable_test.dart | 57 +++++ .../map_key_type_not_assignable_test.dart | 57 +++++ .../map_value_type_not_assignable_test.dart | 57 +++++ .../diagnostics/non_bool_condition_test.dart | 47 ++++ .../return_of_invalid_type_test.dart | 24 ++ .../set_element_type_not_assignable_test.dart | 57 +++++ .../test/src/diagnostics/test_all.dart | 9 + pkg/analyzer/test/src/task/options_test.dart | 53 +++++ .../test/src/task/strong/checker_test.dart | 219 ++++++++++++++++++ .../tool/messages/error_code_info.dart | 4 + pkg/nnbd_migration/lib/src/fix_builder.dart | 1 + .../test/edge_builder_test.dart | 2 + .../test/migration_cli_test.dart | 3 + 50 files changed, 1851 insertions(+), 32 deletions(-) create mode 100644 pkg/analyzer/test/src/diagnostics/implicit_dynamic_field_test.dart create mode 100644 pkg/analyzer/test/src/diagnostics/implicit_dynamic_function_test.dart create mode 100644 pkg/analyzer/test/src/diagnostics/implicit_dynamic_list_literal_test.dart create mode 100644 pkg/analyzer/test/src/diagnostics/implicit_dynamic_map_literal_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index e47e812bbce4..8900449ec8d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,13 +71,6 @@ ### Tools -#### Analyzer - -- Remove deprecated 'strong-mode' analysis options from `analysis_options.yaml` - files. These options are replaced by the supported "strict" options - documented at - [dart.dev](https://dart.dev/guides/language/analysis-options#enabling-additional-type-checks). - #### Linter Updates the Linter to `1.32.0`, which includes changes that diff --git a/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart b/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart index 72ba073b12bf..fafccf50d97c 100644 --- a/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart +++ b/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart @@ -34,6 +34,11 @@ class AnalysisOptionsGenerator extends YamlCompletionGenerator { }), AnalyzerOptions.plugins: EmptyProducer(), AnalyzerOptions.propagateLinterExceptions: EmptyProducer(), + AnalyzerOptions.strongMode: MapProducer({ + AnalyzerOptions.declarationCasts: EmptyProducer(), + AnalyzerOptions.implicitCasts: EmptyProducer(), + AnalyzerOptions.implicitDynamic: EmptyProducer(), + }), }), AnalyzerOptions.codeStyle: MapProducer({ AnalyzerOptions.format: BooleanProducer(), diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml index b98d95279cc7..e4011b210de9 100644 --- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml +++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml @@ -43,6 +43,9 @@ AnalysisOptionsErrorCode.PARSE_ERROR: AnalysisOptionsHintCode.PREVIEW_DART_2_SETTING_DEPRECATED: status: needsFix notes: Fixed. +AnalysisOptionsHintCode.STRONG_MODE_SETTING_DEPRECATED: + status: needsFix + notes: Fixed. AnalysisOptionsWarningCode.INCLUDE_FILE_NOT_FOUND: status: noFix notes: |- @@ -63,6 +66,10 @@ AnalysisOptionsWarningCode.INVALID_OPTION: replace the invalid option with the selected replacement. AnalysisOptionsWarningCode.INVALID_SECTION_FORMAT: status: needsEvaluation +AnalysisOptionsWarningCode.SPEC_MODE_REMOVED: + status: needsFix + notes: |- + Provide a fix to remove the deprecated setting. AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE: status: needsEvaluation AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE: @@ -1680,6 +1687,56 @@ HintCode.UNUSED_RESULT_WITH_MESSAGE: There is no predictable common way in which a result _should_ be used. HintCode.UNUSED_SHOWN_NAME: status: hasFix +LanguageCode.IMPLICIT_DYNAMIC_FIELD: + status: needsFix + notes: |- + The correction says to add an explicit type or remove implicit-dynamic from + analysis options. We can add a fix to add an explicit `dynamic`. +LanguageCode.IMPLICIT_DYNAMIC_FUNCTION: + status: needsFix + notes: |- + The correction says to add an explicit type or remove implicit-dynamic from + analysis options. We can add a fix to add an explicit `dynamic`. +LanguageCode.IMPLICIT_DYNAMIC_INVOKE: + status: needsFix + notes: |- + The correction says to add an explicit type or remove implicit-dynamic from + analysis options. We can add a fix to add an explicit `dynamic`. +LanguageCode.IMPLICIT_DYNAMIC_LIST_LITERAL: + status: needsFix + notes: |- + The correction says to add an explicit type or remove implicit-dynamic from + analysis options. We can add a fix to add an explicit `dynamic`. +LanguageCode.IMPLICIT_DYNAMIC_MAP_LITERAL: + status: needsFix + notes: |- + The correction says to add an explicit type or remove implicit-dynamic from + analysis options. We can add a fix to add an explicit `dynamic`. +LanguageCode.IMPLICIT_DYNAMIC_METHOD: + status: needsFix + notes: |- + The correction says to add an explicit type or remove implicit-dynamic from + analysis options. We can add a fix to add an explicit `dynamic`. +LanguageCode.IMPLICIT_DYNAMIC_PARAMETER: + status: needsFix + notes: |- + The correction says to add an explicit type or remove implicit-dynamic from + analysis options. We can add a fix to add an explicit `dynamic`. +LanguageCode.IMPLICIT_DYNAMIC_RETURN: + status: needsFix + notes: |- + The correction says to add an explicit type or remove implicit-dynamic from + analysis options. We can add a fix to add an explicit `dynamic`. +LanguageCode.IMPLICIT_DYNAMIC_TYPE: + status: needsFix + notes: |- + The correction says to add an explicit type or remove implicit-dynamic from + analysis options. We can add a fix to add an explicit `dynamic`. +LanguageCode.IMPLICIT_DYNAMIC_VARIABLE: + status: needsFix + notes: |- + The correction says to add an explicit type or remove implicit-dynamic from + analysis options. We can add a fix to add an explicit `dynamic`. LintCode.always_declare_return_types: status: hasFix LintCode.always_put_control_body_on_new_line: diff --git a/pkg/analysis_server/lib/src/services/correction/fix/analysis_options/fix_generator.dart b/pkg/analysis_server/lib/src/services/correction/fix/analysis_options/fix_generator.dart index 3620fe8c7065..4067043a41a3 100644 --- a/pkg/analysis_server/lib/src/services/correction/fix/analysis_options/fix_generator.dart +++ b/pkg/analysis_server/lib/src/services/correction/fix/analysis_options/fix_generator.dart @@ -65,6 +65,9 @@ class AnalysisOptionsFixGenerator { if (errorCode == AnalysisOptionsHintCode.PREVIEW_DART_2_SETTING_DEPRECATED) { await _addFix_removeSetting(coveringNodePath); + } else if (errorCode == + AnalysisOptionsHintCode.STRONG_MODE_SETTING_DEPRECATED) { + await _addFix_removeSetting(coveringNodePath); } else if (errorCode == DEPRECATED_LINT_HINT) { await _addFix_removeLint(coveringNodePath); // } else if (errorCode == AnalysisOptionsWarningCode.INCLUDED_FILE_WARNING) { diff --git a/pkg/analysis_server/lib/src/status/diagnostics.dart b/pkg/analysis_server/lib/src/status/diagnostics.dart index a7778c29e52d..1700dbca2445 100644 --- a/pkg/analysis_server/lib/src/status/diagnostics.dart +++ b/pkg/analysis_server/lib/src/status/diagnostics.dart @@ -452,6 +452,8 @@ class ContextsPage extends DiagnosticPageWithNav { String describe(AnalysisOptionsImpl options) { var b = StringBuffer(); + b.write(writeOption('Implicit dynamic', options.implicitDynamic)); + b.write(writeOption('Implicit casts', options.implicitCasts)); b.write(writeOption('Feature set', options.contextFeatures.toString())); b.write('
'); diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart index dfc8d537b8ef..eca97b17956e 100644 --- a/pkg/analysis_server/test/abstract_context.dart +++ b/pkg/analysis_server/test/abstract_context.dart @@ -105,11 +105,12 @@ class AbstractContextTest with ResourceProviderMixin { void createAnalysisOptionsFile({ List? experiments, List? cannotIgnore, + bool? implicitCasts, List? lints, }) { var buffer = StringBuffer(); - if (experiments != null || cannotIgnore != null) { + if (experiments != null || implicitCasts != null || cannotIgnore != null) { buffer.writeln('analyzer:'); } @@ -120,6 +121,11 @@ class AbstractContextTest with ResourceProviderMixin { } } + if (implicitCasts != null) { + buffer.writeln(' strong-mode:'); + buffer.writeln(' implicit-casts: $implicitCasts'); + } + if (cannotIgnore != null) { buffer.writeln(' cannot-ignore:'); for (var unignorable in cannotIgnore) { diff --git a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart index d118d27c01b4..43b7cb66851b 100644 --- a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart +++ b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart @@ -28,7 +28,7 @@ class AnalysisOptionsFileNotificationTest extends PubPackageAnalysisServerTest { final testSource = ''' void f() { var x = ''; - int y = x; // Not assignable. + int y = x; // Not assignable in strong-mode print(y); }'''; diff --git a/pkg/analysis_server/test/analysis_server_base.dart b/pkg/analysis_server/test/analysis_server_base.dart index 0468c2dd77c6..14a8e0a2140d 100644 --- a/pkg/analysis_server/test/analysis_server_base.dart +++ b/pkg/analysis_server/test/analysis_server_base.dart @@ -27,6 +27,8 @@ import 'src/utilities/mock_packages.dart'; /// TODO(scheglov) this is duplicate class AnalysisOptionsFileConfig { final List experiments; + final bool implicitCasts; + final bool implicitDynamic; final List lints; final bool strictCasts; final bool strictInference; @@ -34,6 +36,8 @@ class AnalysisOptionsFileConfig { AnalysisOptionsFileConfig({ this.experiments = const [], + this.implicitCasts = true, + this.implicitDynamic = true, this.lints = const [], this.strictCasts = false, this.strictInference = false, @@ -54,6 +58,9 @@ class AnalysisOptionsFileConfig { buffer.writeln(' strict-casts: $strictCasts'); buffer.writeln(' strict-inference: $strictInference'); buffer.writeln(' strict-raw-types: $strictRawTypes'); + buffer.writeln(' strong-mode:'); + buffer.writeln(' implicit-casts: $implicitCasts'); + buffer.writeln(' implicit-dynamic: $implicitDynamic'); buffer.writeln('linter:'); buffer.writeln(' rules:'); diff --git a/pkg/analysis_server/test/src/analytics/analytics_manager_test.dart b/pkg/analysis_server/test/src/analytics/analytics_manager_test.dart index 328dd81160ab..aae4d81a874e 100644 --- a/pkg/analysis_server/test/src/analytics/analytics_manager_test.dart +++ b/pkg/analysis_server/test/src/analytics/analytics_manager_test.dart @@ -359,12 +359,13 @@ class AnalyticsManagerTest with ResourceProviderMixin { String? path, Map? errors, List? experiments, + bool? implicitCasts, List? lints, }) { path ??= '$testPackageRootPath/analysis_options.yaml'; var buffer = StringBuffer(); - if (errors != null || experiments != null) { + if (errors != null || experiments != null || implicitCasts != null) { buffer.writeln('analyzer:'); } @@ -382,6 +383,11 @@ class AnalyticsManagerTest with ResourceProviderMixin { } } + if (implicitCasts != null) { + buffer.writeln(' strong-mode:'); + buffer.writeln(' implicit-casts: $implicitCasts'); + } + if (lints != null) { buffer.writeln('linter:'); buffer.writeln(' rules:'); diff --git a/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart b/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart index d50f80a3742b..c9375cbb0b5d 100644 --- a/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart +++ b/pkg/analysis_server/test/src/flutter/flutter_outline_notification_test.dart @@ -69,7 +69,7 @@ class FlutterNotificationOutlineTest extends PubPackageAnalysisServerTest { ); newAnalysisOptionsYamlFile(testPackageRootPath, ''' analyzer: - language: true + strong-mode: true '''); await pumpEventQueue(); await server.onAnalysisComplete; diff --git a/pkg/analysis_server/test/src/services/correction/fix/analysis_options/remove_setting_test.dart b/pkg/analysis_server/test/src/services/correction/fix/analysis_options/remove_setting_test.dart index 13450a2059fc..e31e439d30ea 100644 --- a/pkg/analysis_server/test/src/services/correction/fix/analysis_options/remove_setting_test.dart +++ b/pkg/analysis_server/test/src/services/correction/fix/analysis_options/remove_setting_test.dart @@ -62,4 +62,11 @@ analyzer: ''', ''' '''); } + + Future test_strong_mode_settings_deprecated() async { + await assertHasFix(''' +analyzer: + strong-mode: true +''', ''); + } } diff --git a/pkg/analysis_server/test/src/services/correction/fix/change_type_annotation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/change_type_annotation_test.dart index bc5fcdde5e8d..429deba6ae83 100644 --- a/pkg/analysis_server/test/src/services/correction/fix/change_type_annotation_test.dart +++ b/pkg/analysis_server/test/src/services/correction/fix/change_type_annotation_test.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:analysis_server/src/services/correction/fix.dart'; +import 'package:analyzer/src/error/codes.dart'; import 'package:analyzer_plugin/utilities/fixes/fixes.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; @@ -118,4 +119,16 @@ f() { } '''); } + + Future test_synthetic_implicitCast() async { + createAnalysisOptionsFile(implicitCasts: false); + await resolveTestCode(''' +int foo = +'''); + await assertNoFix( + errorFilter: (e) { + return e.errorCode == CompileTimeErrorCode.INVALID_ASSIGNMENT; + }, + ); + } } diff --git a/pkg/analyzer/lib/src/analysis_options/error/option_codes.g.dart b/pkg/analyzer/lib/src/analysis_options/error/option_codes.g.dart index 46e25fae8dde..d32e2c0af44c 100644 --- a/pkg/analyzer/lib/src/analysis_options/error/option_codes.g.dart +++ b/pkg/analyzer/lib/src/analysis_options/error/option_codes.g.dart @@ -68,6 +68,15 @@ class AnalysisOptionsHintCode extends ErrorCode { correctionMessage: "It is no longer necessary to explicitly enable Dart 2.", ); + /// An error code indicating that strong-mode: true is deprecated. + static const AnalysisOptionsHintCode STRONG_MODE_SETTING_DEPRECATED = + AnalysisOptionsHintCode( + 'STRONG_MODE_SETTING_DEPRECATED', + "The 'strong-mode: true' setting is deprecated.", + correctionMessage: + "It is no longer necessary to explicitly enable strong mode.", + ); + /// Initialize a newly created error code to have the given [name]. const AnalysisOptionsHintCode( String name, @@ -137,6 +146,16 @@ class AnalysisOptionsWarningCode extends ErrorCode { "Invalid format for the '{0}' section.", ); + /// An error code indicating that strong-mode: false is has been removed. + static const AnalysisOptionsWarningCode SPEC_MODE_REMOVED = + AnalysisOptionsWarningCode( + 'SPEC_MODE_REMOVED', + "The option 'strong-mode: false' is no longer supported.", + correctionMessage: + "It's recommended to remove the 'strong-mode:' setting (and make your " + "code Dart 2 compliant).", + ); + /// An error code indicating that an unrecognized error code is being used to /// specify an error filter. /// diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart index 654270685f6e..29448a0bb25d 100644 --- a/pkg/analyzer/lib/src/context/context.dart +++ b/pkg/analyzer/lib/src/context/context.dart @@ -41,11 +41,13 @@ class AnalysisContextImpl implements AnalysisContext { // TODO() remove this method as well _typeSystemLegacy?.updateOptions( + implicitCasts: analysisOptions.implicitCasts, strictCasts: analysisOptions.strictCasts, strictInference: analysisOptions.strictInference, ); _typeSystemNonNullableByDefault?.updateOptions( + implicitCasts: analysisOptions.implicitCasts, strictCasts: analysisOptions.strictCasts, strictInference: analysisOptions.strictInference, ); @@ -89,6 +91,7 @@ class AnalysisContextImpl implements AnalysisContext { } _typeSystemLegacy = TypeSystemImpl( + implicitCasts: analysisOptions.implicitCasts, isNonNullableByDefault: false, strictCasts: analysisOptions.strictCasts, strictInference: analysisOptions.strictInference, @@ -96,6 +99,7 @@ class AnalysisContextImpl implements AnalysisContext { ); _typeSystemNonNullableByDefault = TypeSystemImpl( + implicitCasts: analysisOptions.implicitCasts, isNonNullableByDefault: true, strictCasts: analysisOptions.strictCasts, strictInference: analysisOptions.strictInference, diff --git a/pkg/analyzer/lib/src/dart/constant/value.dart b/pkg/analyzer/lib/src/dart/constant/value.dart index 2bd75a94aa2b..c6846567a649 100644 --- a/pkg/analyzer/lib/src/dart/constant/value.dart +++ b/pkg/analyzer/lib/src/dart/constant/value.dart @@ -527,6 +527,7 @@ class DartObjectImpl implements DartObject { DartObjectImpl isIdentical( TypeProvider typeProvider, DartObjectImpl rightOperand) { var typeSystem = TypeSystemImpl( + implicitCasts: false, isNonNullableByDefault: false, strictCasts: false, strictInference: false, diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart index 4b9aa4627961..97cd2eba60fc 100644 --- a/pkg/analyzer/lib/src/dart/element/type_system.dart +++ b/pkg/analyzer/lib/src/dart/element/type_system.dart @@ -55,6 +55,11 @@ class TypeSystemImpl implements TypeSystem { /// The provider of types for the system. final TypeProviderImpl typeProvider; + /// False if implicit casts should always be disallowed. + /// + /// This affects the behavior of [isAssignableTo]. + bool implicitCasts; + /// True if "strict casts" should be enforced. /// /// This affects the behavior of [isAssignableTo]. @@ -84,6 +89,7 @@ class TypeSystemImpl implements TypeSystem { late final SubtypeHelper _subtypeHelper; TypeSystemImpl({ + required this.implicitCasts, required this.isNonNullableByDefault, required this.strictCasts, required this.strictInference, @@ -680,9 +686,10 @@ class TypeSystemImpl implements TypeSystem { } } - // First make sure that the static analysis option, `strict-casts: true`, - // disables all downcasts, including casts from `dynamic`. - if (strictCasts) { + // First make sure that the static analysis options, `implicit-casts: false` + // and `strict-casts: true` disable all downcasts, including casts from + // `dynamic`. + if (!implicitCasts || strictCasts) { return false; } @@ -1631,9 +1638,11 @@ class TypeSystemImpl implements TypeSystem { } void updateOptions({ + required bool implicitCasts, required bool strictCasts, required bool strictInference, }) { + this.implicitCasts = implicitCasts; this.strictCasts = strictCasts; this.strictInference = strictInference; } diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart index 98d18f8fe6b6..a0088f5ef062 100644 --- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart +++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart @@ -706,6 +706,7 @@ class FileResolver { } var analysisOptions = AnalysisOptionsImpl() + ..implicitCasts = fileAnalysisOptions.implicitCasts ..strictInference = fileAnalysisOptions.strictInference; if (fsState == null) { diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart index 0b79683a76cf..6b8540bfbd2f 100644 --- a/pkg/analyzer/lib/src/error/codes.g.dart +++ b/pkg/analyzer/lib/src/error/codes.g.dart @@ -5242,6 +5242,126 @@ class CompileTimeErrorCode extends AnalyzerErrorCode { ErrorType get type => ErrorType.COMPILE_TIME_ERROR; } +class LanguageCode extends ErrorCode { + /// Parameters: + /// 0: the name of the field + static const LanguageCode IMPLICIT_DYNAMIC_FIELD = LanguageCode( + 'IMPLICIT_DYNAMIC_FIELD', + "Missing field type for '{0}'.", + correctionMessage: + "Try adding an explicit type, or remove implicit-dynamic from your " + "analysis options file.", + ); + + /// Parameters: + /// 0: the name of the function + /// 1: the names of the type arguments + static const LanguageCode IMPLICIT_DYNAMIC_FUNCTION = LanguageCode( + 'IMPLICIT_DYNAMIC_FUNCTION', + "Missing type arguments for generic function '{0}<{1}>'.", + correctionMessage: + "Try adding an explicit type, or remove implicit-dynamic from your " + "analysis options file.", + ); + + /// Parameters: + /// 0: the name of type + static const LanguageCode IMPLICIT_DYNAMIC_INVOKE = LanguageCode( + 'IMPLICIT_DYNAMIC_INVOKE', + "Missing type arguments for calling generic function type '{0}'.", + correctionMessage: + "Try adding an explicit type, or remove implicit-dynamic from your " + "analysis options file.", + ); + + static const LanguageCode IMPLICIT_DYNAMIC_LIST_LITERAL = LanguageCode( + 'IMPLICIT_DYNAMIC_LIST_LITERAL', + "Missing type argument for list literal.", + correctionMessage: + "Try adding an explicit type, or remove implicit-dynamic from your " + "analysis options file.", + ); + + static const LanguageCode IMPLICIT_DYNAMIC_MAP_LITERAL = LanguageCode( + 'IMPLICIT_DYNAMIC_MAP_LITERAL', + "Missing type arguments for map literal.", + correctionMessage: + "Try adding an explicit type, or remove implicit-dynamic from your " + "analysis options file.", + ); + + /// Parameters: + /// 0: the name of the function + /// 1: the names of the type arguments + static const LanguageCode IMPLICIT_DYNAMIC_METHOD = LanguageCode( + 'IMPLICIT_DYNAMIC_METHOD', + "Missing type arguments for generic method '{0}<{1}>'.", + correctionMessage: + "Try adding an explicit type, or remove implicit-dynamic from your " + "analysis options file.", + ); + + /// Parameters: + /// 0: the name of the parameter + static const LanguageCode IMPLICIT_DYNAMIC_PARAMETER = LanguageCode( + 'IMPLICIT_DYNAMIC_PARAMETER', + "Missing parameter type for '{0}'.", + correctionMessage: + "Try adding an explicit type, or remove implicit-dynamic from your " + "analysis options file.", + ); + + /// Parameters: + /// 0: the name of the function or method + static const LanguageCode IMPLICIT_DYNAMIC_RETURN = LanguageCode( + 'IMPLICIT_DYNAMIC_RETURN', + "Missing return type for '{0}'.", + correctionMessage: + "Try adding an explicit type, or remove implicit-dynamic from your " + "analysis options file.", + ); + + /// Parameters: + /// 0: the name of the type + static const LanguageCode IMPLICIT_DYNAMIC_TYPE = LanguageCode( + 'IMPLICIT_DYNAMIC_TYPE', + "Missing type arguments for generic type '{0}'.", + correctionMessage: + "Try adding an explicit type, or remove implicit-dynamic from your " + "analysis options file.", + ); + + /// Parameters: + /// 0: the name of the variable + static const LanguageCode IMPLICIT_DYNAMIC_VARIABLE = LanguageCode( + 'IMPLICIT_DYNAMIC_VARIABLE', + "Missing variable type for '{0}'.", + correctionMessage: + "Try adding an explicit type, or remove implicit-dynamic from your " + "analysis options file.", + ); + + /// Initialize a newly created error code to have the given [name]. + const LanguageCode( + String name, + String problemMessage, { + super.correctionMessage, + super.hasPublishedDocs = false, + super.isUnresolvedIdentifier = false, + String? uniqueName, + }) : super( + name: name, + problemMessage: problemMessage, + uniqueName: 'LanguageCode.${uniqueName ?? name}', + ); + + @override + ErrorSeverity get errorSeverity => ErrorType.COMPILE_TIME_ERROR.severity; + + @override + ErrorType get type => ErrorType.COMPILE_TIME_ERROR; +} + class StaticWarningCode extends AnalyzerErrorCode { /// No parameters. static const StaticWarningCode DEAD_NULL_AWARE_EXPRESSION = StaticWarningCode( diff --git a/pkg/analyzer/lib/src/error/error_code_values.g.dart b/pkg/analyzer/lib/src/error/error_code_values.g.dart index 87ec09ffbb27..bd98bdb8c87f 100644 --- a/pkg/analyzer/lib/src/error/error_code_values.g.dart +++ b/pkg/analyzer/lib/src/error/error_code_values.g.dart @@ -23,10 +23,12 @@ const List errorCodeValues = [ AnalysisOptionsErrorCode.INCLUDED_FILE_PARSE_ERROR, AnalysisOptionsErrorCode.PARSE_ERROR, AnalysisOptionsHintCode.PREVIEW_DART_2_SETTING_DEPRECATED, + AnalysisOptionsHintCode.STRONG_MODE_SETTING_DEPRECATED, AnalysisOptionsWarningCode.INCLUDED_FILE_WARNING, AnalysisOptionsWarningCode.INCLUDE_FILE_NOT_FOUND, AnalysisOptionsWarningCode.INVALID_OPTION, AnalysisOptionsWarningCode.INVALID_SECTION_FORMAT, + AnalysisOptionsWarningCode.SPEC_MODE_REMOVED, AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE, AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITHOUT_VALUES, AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE, @@ -674,6 +676,16 @@ const List errorCodeValues = [ HintCode.UNUSED_RESULT, HintCode.UNUSED_RESULT_WITH_MESSAGE, HintCode.UNUSED_SHOWN_NAME, + LanguageCode.IMPLICIT_DYNAMIC_FIELD, + LanguageCode.IMPLICIT_DYNAMIC_FUNCTION, + LanguageCode.IMPLICIT_DYNAMIC_INVOKE, + LanguageCode.IMPLICIT_DYNAMIC_LIST_LITERAL, + LanguageCode.IMPLICIT_DYNAMIC_MAP_LITERAL, + LanguageCode.IMPLICIT_DYNAMIC_METHOD, + LanguageCode.IMPLICIT_DYNAMIC_PARAMETER, + LanguageCode.IMPLICIT_DYNAMIC_RETURN, + LanguageCode.IMPLICIT_DYNAMIC_TYPE, + LanguageCode.IMPLICIT_DYNAMIC_VARIABLE, ManifestWarningCode.CAMERA_PERMISSIONS_INCOMPATIBLE, ManifestWarningCode.NON_RESIZABLE_ACTIVITY, ManifestWarningCode.NO_TOUCHSCREEN_FEATURE, diff --git a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart index f40a62944b7c..ce1acff9838f 100644 --- a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart +++ b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart @@ -148,6 +148,7 @@ class TypeArgumentsVerifier { node.function.staticType, node.staticInvokeType, ); + _checkForImplicitDynamicInvoke(node); } void checkFunctionReference(FunctionReference node) { @@ -170,6 +171,7 @@ class TypeArgumentsVerifier { _checkTypeArgumentCount(typeArguments, 1, CompileTimeErrorCode.EXPECTED_ONE_LIST_TYPE_ARGUMENTS); } + _checkForImplicitDynamicTypedLiteral(node); } void checkMapLiteral(SetOrMapLiteral node) { @@ -184,6 +186,7 @@ class TypeArgumentsVerifier { _checkTypeArgumentCount(typeArguments, 2, CompileTimeErrorCode.EXPECTED_TWO_MAP_TYPE_ARGUMENTS); } + _checkForImplicitDynamicTypedLiteral(node); } void checkMethodInvocation(MethodInvocation node) { @@ -192,6 +195,7 @@ class TypeArgumentsVerifier { node.function.staticType, node.staticInvokeType, ); + _checkForImplicitDynamicInvoke(node); } void checkNamedType(NamedType node) { @@ -215,6 +219,62 @@ class TypeArgumentsVerifier { _checkTypeArgumentCount(typeArguments, 1, CompileTimeErrorCode.EXPECTED_ONE_SET_TYPE_ARGUMENTS); } + _checkForImplicitDynamicTypedLiteral(node); + } + + void _checkForImplicitDynamicInvoke(InvocationExpression node) { + if (_options.implicitDynamic || node.typeArguments != null) { + return; + } + var invokeType = node.staticInvokeType; + var declaredType = node.function.staticType; + if (invokeType is FunctionType && + declaredType is FunctionType && + declaredType.typeFormals.isNotEmpty) { + List typeArgs = node.typeArgumentTypes!; + if (typeArgs.any((t) => t.isDynamic)) { + // Issue an error depending on what we're trying to call. + Expression function = node.function; + if (function is Identifier) { + var element = function.staticElement; + if (element is MethodElement) { + _errorReporter.reportErrorForNode( + LanguageCode.IMPLICIT_DYNAMIC_METHOD, + node.function, + [element.displayName, element.typeParameters.join(', ')]); + return; + } + + if (element is FunctionElement) { + _errorReporter.reportErrorForNode( + LanguageCode.IMPLICIT_DYNAMIC_FUNCTION, + node.function, + [element.displayName, element.typeParameters.join(', ')]); + return; + } + } + + // The catch all case if neither of those matched. + // For example, invoking a function expression. + _errorReporter.reportErrorForNode(LanguageCode.IMPLICIT_DYNAMIC_INVOKE, + node.function, [declaredType]); + } + } + } + + void _checkForImplicitDynamicTypedLiteral(TypedLiteral node) { + if (_options.implicitDynamic || node.typeArguments != null) { + return; + } + DartType type = node.typeOrThrow; + // It's an error if either the key or value was inferred as dynamic. + if (type is InterfaceType && type.typeArguments.any((t) => t.isDynamic)) { + // TODO(brianwilkerson) Add StrongModeCode.IMPLICIT_DYNAMIC_SET_LITERAL + ErrorCode errorCode = node is ListLiteral + ? LanguageCode.IMPLICIT_DYNAMIC_LIST_LITERAL + : LanguageCode.IMPLICIT_DYNAMIC_MAP_LITERAL; + _errorReporter.reportErrorForNode(errorCode, node); + } } /// Checks a type annotation for a raw generic type, and reports the diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart index 020ec0397dcc..0fc9372b930d 100644 --- a/pkg/analyzer/lib/src/generated/engine.dart +++ b/pkg/analyzer/lib/src/generated/engine.dart @@ -197,6 +197,22 @@ class AnalysisOptionsImpl implements AnalysisOptions { /// `true`. List? _lintRules; + /// A flag indicating whether implicit casts are allowed in [strongMode] + /// (they are always allowed in Dart 1.0 mode). + /// + /// This option is experimental and subject to change. + bool implicitCasts = true; + + /// A flag indicating whether implicit dynamic type is allowed, on by default. + /// + /// This flag can be used without necessarily enabling [strongMode], but it is + /// designed with strong mode's type inference in mind. Without type inference, + /// it will raise many errors. Also it does not provide type safety without + /// strong mode. + /// + /// This option is experimental and subject to change. + bool implicitDynamic = true; + /// Indicates whether linter exceptions should be propagated to the caller (by /// re-throwing them) bool propagateLinterExceptions = false; @@ -245,6 +261,8 @@ class AnalysisOptionsImpl implements AnalysisOptions { lintRules = options.lintRules; if (options is AnalysisOptionsImpl) { enableTiming = options.enableTiming; + implicitCasts = options.implicitCasts; + implicitDynamic = options.implicitDynamic; propagateLinterExceptions = options.propagateLinterExceptions; strictInference = options.strictInference; strictRawTypes = options.strictRawTypes; @@ -301,6 +319,8 @@ class AnalysisOptionsImpl implements AnalysisOptions { } // Append boolean flags. + buffer.addBool(implicitCasts); + buffer.addBool(implicitDynamic); buffer.addBool(propagateLinterExceptions); buffer.addBool(strictCasts); buffer.addBool(strictInference); diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart index f81f9c974237..f2e85ea550ca 100644 --- a/pkg/analyzer/lib/src/generated/error_verifier.dart +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart @@ -768,6 +768,7 @@ class ErrorVerifier extends RecursiveAstVisitor } _checkForTypeAnnotationDeferredClass(returnType); _returnTypeVerifier.verifyReturnType(returnType); + _checkForImplicitDynamicReturn(node.name, node.declaredElement!); _checkForMainFunction1(node.name, node.declaredElement!); _checkForMainFunction2(node); super.visitFunctionDeclaration(node); @@ -828,6 +829,20 @@ class ErrorVerifier extends RecursiveAstVisitor try { _checkForTypeAnnotationDeferredClass(node.returnType); + // TODO(jmesserly): ideally we'd use _checkForImplicitDynamicReturn, and + // we can get the function element via `node?.element?.type?.element` but + // it doesn't have hasImplicitReturnType set correctly. + if (!_options.implicitDynamic && node.returnType == null) { + DartType parameterType = node.declaredElement!.type; + if (parameterType is FunctionType && + parameterType.returnType.isDynamic) { + errorReporter.reportErrorForToken( + LanguageCode.IMPLICIT_DYNAMIC_RETURN, + node.name, + [node.name.lexeme]); + } + } + super.visitFunctionTypedFormalParameter(node); } finally { _isInFunctionTypedFormalParameter = old; @@ -852,6 +867,12 @@ class ErrorVerifier extends RecursiveAstVisitor node.whenClause?.accept(this); } + @override + void visitImplementsClause(ImplementsClause node) { + node.interfaces.forEach(_checkForImplicitDynamicType); + super.visitImplementsClause(node); + } + @override void visitImportDirective(ImportDirective node) { var importElement = node.element; @@ -900,6 +921,7 @@ class ErrorVerifier extends RecursiveAstVisitor } _checkForListConstructor(node, type); } + _checkForImplicitDynamicType(namedType); super.visitInstanceCreationExpression(node); } @@ -950,6 +972,7 @@ class ErrorVerifier extends RecursiveAstVisitor _checkForExtensionDeclaresMemberOfObject(node); _checkForTypeAnnotationDeferredClass(returnType); _returnTypeVerifier.verifyReturnType(returnType); + _checkForImplicitDynamicReturn(node.name, node.declaredElement!); _checkForWrongTypeParameterVarianceInMethod(node); super.visitMethodDeclaration(node); }); @@ -1137,6 +1160,15 @@ class ErrorVerifier extends RecursiveAstVisitor _checkForPrivateOptionalParameter(node); _checkForTypeAnnotationDeferredClass(node.type); + // Checks for an implicit dynamic parameter type. + // + // We can skip other parameter kinds besides simple formal, because: + // - DefaultFormalParameter contains a simple one, so it gets here, + // - FieldFormalParameter error should be reported on the field, + // - FunctionTypedFormalParameter is a function type, not dynamic. + _checkForImplicitDynamicIdentifier(node, node.name, + variable: node.declaredElement!); + super.visitSimpleFormalParameter(node); } @@ -1287,6 +1319,7 @@ class ErrorVerifier extends RecursiveAstVisitor _checkForBuiltInIdentifierAsName(node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_PARAMETER_NAME); _checkForTypeAnnotationDeferredClass(node.bound); + _checkForImplicitDynamicType(node.bound); _checkForGenericFunctionType(node.bound); node.bound?.accept(_uninstantiatedBoundChecker); super.visitTypeParameter(node); @@ -1304,6 +1337,8 @@ class ErrorVerifier extends RecursiveAstVisitor final nameToken = node.name; var initializerNode = node.initializer; // do checks + _checkForImplicitDynamicIdentifier(node, nameToken, + variable: node.declaredElement!); _checkForAbstractOrExternalVariableInitializer(node); // visit initializer String name = nameToken.lexeme; @@ -1342,6 +1377,12 @@ class ErrorVerifier extends RecursiveAstVisitor _isInLateLocalVariable.removeLast(); } + @override + void visitWithClause(WithClause node) { + node.mixinTypes.forEach(_checkForImplicitDynamicType); + super.visitWithClause(node); + } + /// Checks the class for problems with the superclass, mixins, or implemented /// interfaces. void _checkClassInheritance( @@ -1356,6 +1397,7 @@ class ErrorVerifier extends RecursiveAstVisitor !_checkForImplementsClauseErrorCodes(implementsClause) && !_checkForAllMixinErrorCodes(withClause) && !_checkForNoGenerativeConstructorsInSuperclass(superclass)) { + _checkForImplicitDynamicType(superclass); _checkForExtendsDeferredClass(superclass); _checkForRepeatedType(implementsClause?.interfaces, CompileTimeErrorCode.IMPLEMENTS_REPEATED); @@ -2812,6 +2854,61 @@ class ErrorVerifier extends RecursiveAstVisitor return foundError; } + void _checkForImplicitDynamicIdentifier( + AstNode node, + Token? id, { + required VariableElement variable, + }) { + if (id == null) { + return; + } + if (_options.implicitDynamic) { + return; + } + if (variable.hasImplicitType && variable.type.isDynamic) { + ErrorCode errorCode; + if (variable is FieldElement) { + errorCode = LanguageCode.IMPLICIT_DYNAMIC_FIELD; + } else if (variable is ParameterElement) { + errorCode = LanguageCode.IMPLICIT_DYNAMIC_PARAMETER; + } else { + errorCode = LanguageCode.IMPLICIT_DYNAMIC_VARIABLE; + } + // Parameters associated with a variable always have a name, so we can + // safely rely on [id] being non-`null`. + errorReporter.reportErrorForNode(errorCode, node, [id.lexeme]); + } + } + + void _checkForImplicitDynamicReturn( + Token functionName, ExecutableElement element) { + if (_options.implicitDynamic) { + return; + } + if (element is PropertyAccessorElement && element.isSetter) { + return; + } + if (element.hasImplicitReturnType && element.returnType.isDynamic) { + errorReporter.reportErrorForToken(LanguageCode.IMPLICIT_DYNAMIC_RETURN, + functionName, [element.displayName]); + } + } + + void _checkForImplicitDynamicType(TypeAnnotation? node) { + if (_options.implicitDynamic || + node == null || + (node is NamedType && node.typeArguments != null)) { + return; + } + DartType type = node.typeOrThrow; + if (type is ParameterizedType && + type.typeArguments.isNotEmpty && + type.typeArguments.any((t) => t.isDynamic)) { + errorReporter + .reportErrorForNode(LanguageCode.IMPLICIT_DYNAMIC_TYPE, node, [type]); + } + } + /// Check that if the visiting library is not system, then any given library /// should not be SDK internal library. The [importElement] is the /// [LibraryImportElement] retrieved from the node, if the element in the node was diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart index 0e080f195b02..440abf13395e 100644 --- a/pkg/analyzer/lib/src/task/options.dart +++ b/pkg/analyzer/lib/src/task/options.dart @@ -129,10 +129,16 @@ class AnalyzerOptions { static const String language = 'language'; static const String optionalChecks = 'optional-checks'; static const String plugins = 'plugins'; + static const String strongMode = 'strong-mode'; // Optional checks options. static const String chromeOsManifestChecks = 'chrome-os-manifest-checks'; + // Strong mode options (see AnalysisOptionsImpl for documentation). + static const String declarationCasts = 'declaration-casts'; + static const String implicitCasts = 'implicit-casts'; + static const String implicitDynamic = 'implicit-dynamic'; + // Language options (see AnalysisOptionsImpl for documentation). static const String strictCasts = 'strict-casts'; static const String strictInference = 'strict-inference'; @@ -165,6 +171,14 @@ class AnalyzerOptions { optionalChecks, plugins, propagateLinterExceptions, + strongMode, + ]; + + /// Supported `analyzer` strong-mode options. + static const List strongModeOptions = [ + declarationCasts, // deprecated + implicitCasts, + implicitDynamic, ]; /// Supported `analyzer` language options. @@ -194,6 +208,7 @@ class AnalyzerOptionsValidator extends CompositeValidator { AnalyzerOptionsValidator() : super([ TopLevelAnalyzerOptionsValidator(), + StrongModeOptionValueValidator(), ErrorFilterOptionValidator(), EnabledExperimentsValidator(), LanguageOptionValidator(), @@ -607,6 +622,64 @@ class OptionsFileValidator { } } +/// Validates `analyzer` strong-mode value configuration options. +class StrongModeOptionValueValidator extends OptionsValidator { + final ErrorBuilder _builder = ErrorBuilder(AnalyzerOptions.strongModeOptions); + + @override + void validate(ErrorReporter reporter, YamlMap options) { + var analyzer = options.valueAt(AnalyzerOptions.analyzer); + if (analyzer is YamlMap) { + var v = analyzer.valueAt(AnalyzerOptions.strongMode); + if (v is YamlScalar) { + var value = toLowerCase(v.value); + if (!AnalyzerOptions.trueOrFalse.contains(value)) { + reporter.reportErrorForSpan( + AnalysisOptionsWarningCode.UNSUPPORTED_VALUE, v.span, [ + AnalyzerOptions.strongMode, + v.value, + AnalyzerOptions.trueOrFalseProposal + ]); + } else if (value == 'false') { + reporter.reportErrorForSpan( + AnalysisOptionsWarningCode.SPEC_MODE_REMOVED, v.span); + } else if (value == 'true') { + reporter.reportErrorForSpan( + AnalysisOptionsHintCode.STRONG_MODE_SETTING_DEPRECATED, v.span); + } + } else if (v is YamlMap) { + v.nodes.forEach((k, v) { + String? key, value; + bool validKey = false; + if (k is YamlScalar) { + key = k.value?.toString(); + if (!AnalyzerOptions.strongModeOptions.contains(key)) { + _builder.reportError(reporter, AnalyzerOptions.strongMode, k); + } else if (key != AnalyzerOptions.declarationCasts) { + // If we have a valid key, go on and check the value. + validKey = true; + } + } + if (validKey && v is YamlScalar) { + value = toLowerCase(v.value); + if (!AnalyzerOptions.trueOrFalse.contains(value)) { + reporter.reportErrorForSpan( + AnalysisOptionsWarningCode.UNSUPPORTED_VALUE, + v.span, + [key!, v.value, AnalyzerOptions.trueOrFalseProposal]); + } + } + }); + } else if (v != null) { + reporter.reportErrorForSpan( + AnalysisOptionsWarningCode.INVALID_SECTION_FORMAT, + v.span, + [AnalyzerOptions.enableExperiment]); + } + } + } +} + /// Validates `analyzer` top-level options. class TopLevelAnalyzerOptionsValidator extends TopLevelOptionValidator { TopLevelAnalyzerOptionsValidator() @@ -657,6 +730,10 @@ class _OptionsProcessor { } var analyzer = optionMap.valueAt(AnalyzerOptions.analyzer); if (analyzer is YamlMap) { + // Process strong mode option. + var strongMode = analyzer.valueAt(AnalyzerOptions.strongMode); + _applyStrongOptions(options, strongMode); + // Process filters. var filters = analyzer.valueAt(AnalyzerOptions.errors); _applyProcessors(options, filters); @@ -796,6 +873,32 @@ class _OptionsProcessor { options.errorProcessors = config.processors; } + void _applyStrongModeOption( + AnalysisOptionsImpl options, String? feature, Object value) { + var boolValue = toBool(value); + if (boolValue != null) { + if (feature == AnalyzerOptions.implicitCasts) { + options.implicitCasts = boolValue; + } + if (feature == AnalyzerOptions.implicitDynamic) { + options.implicitDynamic = boolValue; + } + if (feature == AnalyzerOptions.propagateLinterExceptions) { + options.propagateLinterExceptions = boolValue; + } + } + } + + void _applyStrongOptions(AnalysisOptionsImpl options, YamlNode? config) { + if (config is YamlMap) { + config.nodes.forEach((k, v) { + if (k is YamlScalar && v is YamlScalar) { + _applyStrongModeOption(options, k.value?.toString(), v.value); + } + }); + } + } + void _applyUnignorables(AnalysisOptionsImpl options, YamlNode? cannotIgnore) { if (cannotIgnore is YamlList) { var names = {}; diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml index 1fe45cc32436..d5a5ed81e58e 100644 --- a/pkg/analyzer/messages.yaml +++ b/pkg/analyzer/messages.yaml @@ -60,6 +60,10 @@ AnalysisOptionsHintCode: comment: |- An error code indicating that the enablePreviewDart2 setting is deprecated. + STRONG_MODE_SETTING_DEPRECATED: + problemMessage: "The 'strong-mode: true' setting is deprecated." + correctionMessage: It is no longer necessary to explicitly enable strong mode. + comment: "An error code indicating that strong-mode: true is deprecated." AnalysisOptionsWarningCode: INCLUDED_FILE_WARNING: problemMessage: "Warning in the included options file {0}({1}..{2}): {3}" @@ -96,6 +100,10 @@ AnalysisOptionsWarningCode: Parameters: 0: the section name + SPEC_MODE_REMOVED: + problemMessage: "The option 'strong-mode: false' is no longer supported." + correctionMessage: "It's recommended to remove the 'strong-mode:' setting (and make your code Dart 2 compliant)." + comment: "An error code indicating that strong-mode: false is has been removed." UNRECOGNIZED_ERROR_CODE: problemMessage: "'{0}' isn't a recognized error code." comment: |- @@ -21489,6 +21497,63 @@ HintCode: var x = min(0, 1); ``` +LanguageCode: + IMPLICIT_DYNAMIC_FIELD: + problemMessage: "Missing field type for '{0}'." + correctionMessage: Try adding an explicit type, or remove implicit-dynamic from your analysis options file. + comment: |- + Parameters: + 0: the name of the field + IMPLICIT_DYNAMIC_FUNCTION: + problemMessage: "Missing type arguments for generic function '{0}<{1}>'." + correctionMessage: Try adding an explicit type, or remove implicit-dynamic from your analysis options file. + comment: |- + Parameters: + 0: the name of the function + 1: the names of the type arguments + IMPLICIT_DYNAMIC_INVOKE: + problemMessage: "Missing type arguments for calling generic function type '{0}'." + correctionMessage: Try adding an explicit type, or remove implicit-dynamic from your analysis options file. + comment: |- + Parameters: + 0: the name of type + IMPLICIT_DYNAMIC_LIST_LITERAL: + problemMessage: Missing type argument for list literal. + correctionMessage: Try adding an explicit type, or remove implicit-dynamic from your analysis options file. + IMPLICIT_DYNAMIC_MAP_LITERAL: + problemMessage: Missing type arguments for map literal. + correctionMessage: Try adding an explicit type, or remove implicit-dynamic from your analysis options file. + IMPLICIT_DYNAMIC_METHOD: + problemMessage: "Missing type arguments for generic method '{0}<{1}>'." + correctionMessage: Try adding an explicit type, or remove implicit-dynamic from your analysis options file. + comment: |- + Parameters: + 0: the name of the function + 1: the names of the type arguments + IMPLICIT_DYNAMIC_PARAMETER: + problemMessage: "Missing parameter type for '{0}'." + correctionMessage: Try adding an explicit type, or remove implicit-dynamic from your analysis options file. + comment: |- + Parameters: + 0: the name of the parameter + IMPLICIT_DYNAMIC_RETURN: + problemMessage: "Missing return type for '{0}'." + correctionMessage: Try adding an explicit type, or remove implicit-dynamic from your analysis options file. + comment: |- + Parameters: + 0: the name of the function or method + IMPLICIT_DYNAMIC_TYPE: + problemMessage: "Missing type arguments for generic type '{0}'." + correctionMessage: Try adding an explicit type, or remove implicit-dynamic from your analysis options file. + comment: |- + Parameters: + 0: the name of the type + IMPLICIT_DYNAMIC_VARIABLE: + problemMessage: "Missing variable type for '{0}'." + correctionMessage: Try adding an explicit type, or remove implicit-dynamic from your analysis options file. + comment: |- + Parameters: + 0: the name of the variable ManifestWarningCode: CAMERA_PERMISSIONS_INCOMPATIBLE: problemMessage: Camera permissions make app incompatible for Chrome OS, consider adding optional features "android.hardware.camera" and "android.hardware.camera.autofocus". diff --git a/pkg/analyzer/test/generated/test_analysis_context.dart b/pkg/analyzer/test/generated/test_analysis_context.dart index 489a5b63ab8e..fb38dea77806 100644 --- a/pkg/analyzer/test/generated/test_analysis_context.dart +++ b/pkg/analyzer/test/generated/test_analysis_context.dart @@ -41,6 +41,7 @@ class TestAnalysisContext implements AnalysisContext { ); _typeSystemLegacy = TypeSystemImpl( + implicitCasts: _analysisOptions.implicitCasts, isNonNullableByDefault: false, strictCasts: _analysisOptions.strictCasts, strictInference: _analysisOptions.strictInference, @@ -48,6 +49,7 @@ class TestAnalysisContext implements AnalysisContext { ); _typeSystemNonNullableByDefault = TypeSystemImpl( + implicitCasts: _analysisOptions.implicitCasts, isNonNullableByDefault: true, strictCasts: _analysisOptions.strictCasts, strictInference: _analysisOptions.strictInference, diff --git a/pkg/analyzer/test/source/analysis_options_provider_test.dart b/pkg/analyzer/test/source/analysis_options_provider_test.dart index 84cc1f224e0e..735733e2e1a8 100644 --- a/pkg/analyzer/test/source/analysis_options_provider_test.dart +++ b/pkg/analyzer/test/source/analysis_options_provider_test.dart @@ -70,7 +70,7 @@ linter: test('test_bad_yaml (1)', () { var src = ''' analyzer: # <= bang -language: true +strong-mode: true '''; var optionsProvider = AnalysisOptionsProvider(); @@ -81,7 +81,7 @@ language: true test('test_bad_yaml (2)', () { var src = ''' analyzer: - language:true # missing space (sdk/issues/24885) + strong-mode:true # missing space (sdk/issues/24885) '''; var optionsProvider = AnalysisOptionsProvider(); diff --git a/pkg/analyzer/test/source/error_processor_test.dart b/pkg/analyzer/test/source/error_processor_test.dart index c0d7a9c81d1e..20bbac0431c2 100644 --- a/pkg/analyzer/test/source/error_processor_test.dart +++ b/pkg/analyzer/test/source/error_processor_test.dart @@ -62,6 +62,14 @@ analyzer: expect(context.getProcessor(unused_local_variable), isNull); expect(context.getProcessor(use_of_void_result), isNull); }); + + test('does not upgrade other warnings to errors in strong mode', () { + context.configureOptions(''' +analyzer: + strong-mode: true +'''); + expect(context.getProcessor(unused_local_variable), isNull); + }); }); group('ErrorConfig', () { diff --git a/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart b/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart index 25f9a9f1a5b7..f2e65b6ae7a7 100644 --- a/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart +++ b/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart @@ -230,6 +230,8 @@ environment: actual.lintRules.map((l) => l.name), unorderedEquals(expected.lintRules.map((l) => l.name)), ); + expect(actual.implicitCasts, expected.implicitCasts); + expect(actual.implicitDynamic, expected.implicitDynamic); expect( actual.propagateLinterExceptions, expected.propagateLinterExceptions); expect(actual.strictInference, expected.strictInference); diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart index 3f8620d9471b..1fe4df51bb3b 100644 --- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart +++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart @@ -808,8 +808,8 @@ class FileResolverTest extends FileResolutionTest { test_analysisOptions_default_fromPackageUri() async { newFile('/workspace/dart/analysis_options/lib/default.yaml', r''' analyzer: - language: - strict-casts: true + strong-mode: + implicit-casts: false '''); await assertErrorsInCode(r''' @@ -823,8 +823,8 @@ int b = a; test_analysisOptions_file_inPackage() async { newAnalysisOptionsYamlFile('/workspace/dart/test', r''' analyzer: - language: - strict-casts: true + strong-mode: + implicit-casts: false '''); await assertErrorsInCode(r''' @@ -838,14 +838,14 @@ int b = a; test_analysisOptions_file_inThirdParty() async { newFile('/workspace/dart/analysis_options/lib/third_party.yaml', r''' analyzer: - language: - strict-casts: true + strong-mode: + implicit-casts: false '''); newAnalysisOptionsYamlFile('/workspace/third_party/dart/aaa', r''' analyzer: - language: - strict-casts: false + strong-mode: + implicit-casts: true '''); var aPath = convertPath('/workspace/third_party/dart/aaa/lib/a.dart'); @@ -860,14 +860,14 @@ int b = a; test_analysisOptions_file_inThirdPartyDartLang() async { newFile('/workspace/dart/analysis_options/lib/third_party.yaml', r''' analyzer: - language: - strict-casts: true + strong-mode: + implicit-casts: false '''); newAnalysisOptionsYamlFile('/workspace/third_party/dart_lang/aaa', r''' analyzer: - language: - strict-casts: false + strong-mode: + implicit-casts: true '''); var aPath = convertPath('/workspace/third_party/dart_lang/aaa/lib/a.dart'); @@ -2482,15 +2482,15 @@ int b = a; newFile('/workspace/dart/aaa/BUILD', ''); newAnalysisOptionsYamlFile('/workspace/dart/aaa', r''' analyzer: - language: - strict-casts: true + strong-mode: + implicit-casts: false '''); newFile('/workspace/dart/bbb/BUILD', ''); newAnalysisOptionsYamlFile('/workspace/dart/bbb', r''' analyzer: - language: - strict-casts: false + strong-mode: + implicit-casts: true '''); // Implicit casts are disabled in 'aaa'. diff --git a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart index d5e68b038815..b92e96fc6799 100644 --- a/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart +++ b/pkg/analyzer/test/src/dart/resolution/context_collection_resolution.dart @@ -41,6 +41,8 @@ export 'package:analyzer/src/test_utilities/package_config_file_builder.dart'; class AnalysisOptionsFileConfig { final List experiments; + final bool implicitCasts; + final bool implicitDynamic; final List lints; final bool strictCasts; final bool strictInference; @@ -49,6 +51,8 @@ class AnalysisOptionsFileConfig { AnalysisOptionsFileConfig({ this.experiments = const [], + this.implicitCasts = true, + this.implicitDynamic = true, this.lints = const [], this.strictCasts = false, this.strictInference = false, @@ -68,6 +72,9 @@ class AnalysisOptionsFileConfig { buffer.writeln(' strict-casts: $strictCasts'); buffer.writeln(' strict-inference: $strictInference'); buffer.writeln(' strict-raw-types: $strictRawTypes'); + buffer.writeln(' strong-mode:'); + buffer.writeln(' implicit-casts: $implicitCasts'); + buffer.writeln(' implicit-dynamic: $implicitDynamic'); buffer.writeln(' cannot-ignore:'); for (var name in unignorableNames) { buffer.writeln(' - $name'); @@ -528,6 +535,35 @@ mixin WithLanguage218Mixin on PubPackageResolutionTest { String? get testPackageLanguageVersion => '2.18'; } +mixin WithNoImplicitCastsMixin on PubPackageResolutionTest { + /// Asserts that no errors are reported in [code] when implicit casts are + /// allowed, and that [expectedErrors] are reported for the same [code] when + /// implicit casts are not allowed. + Future assertErrorsWithNoImplicitCasts( + String code, + List expectedErrors, + ) async { + await resolveTestCode(code); + assertNoErrorsInResult(); + + await disposeAnalysisContextCollection(); + + writeTestPackageAnalysisOptionsFile( + AnalysisOptionsFileConfig( + implicitCasts: false, + ), + ); + + await resolveTestFile(); + assertErrorsInResult(expectedErrors); + } + + /// Asserts that no errors are reported in [code], both when implicit casts + /// are allowed and when implicit casts are not allowed. + Future assertNoErrorsWithNoImplicitCasts(String code) async => + assertErrorsWithNoImplicitCasts(code, []); +} + mixin WithoutConstructorTearoffsMixin on PubPackageResolutionTest { @override String? get testPackageLanguageVersion => '2.14'; diff --git a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart index a57addfb824e..c21f468fedad 100644 --- a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart +++ b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart @@ -11,6 +11,8 @@ import '../dart/resolution/context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(ArgumentTypeNotAssignableTest); + defineReflectiveTests( + ArgumentTypeNotAssignableWithoutNullSafetyAndNoImplicitCastsTest); defineReflectiveTests(ArgumentTypeNotAssignableWithoutNullSafetyTest); defineReflectiveTests(ArgumentTypeNotAssignableWithStrictCastsTest); }); @@ -824,6 +826,31 @@ g(C c) { } } +@reflectiveTest +class ArgumentTypeNotAssignableWithoutNullSafetyAndNoImplicitCastsTest + extends PubPackageResolutionTest + with WithoutNullSafetyMixin, WithNoImplicitCastsMixin { + test_functionCall() async { + await assertErrorsWithNoImplicitCasts(r''' +int f(int i) => i; +num n = 0; +var v = f(n); +''', [ + error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 40, 1), + ]); + } + + test_operator() async { + await assertErrorsWithNoImplicitCasts(r''' +num n = 0; +int i = 0; +var v = i & n; +''', [ + error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 34, 1), + ]); + } +} + @reflectiveTest class ArgumentTypeNotAssignableWithoutNullSafetyTest extends PubPackageResolutionTest diff --git a/pkg/analyzer/test/src/diagnostics/field_initializer_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/field_initializer_not_assignable_test.dart index 4c15e47f63c7..eb14c4f54d1d 100644 --- a/pkg/analyzer/test/src/diagnostics/field_initializer_not_assignable_test.dart +++ b/pkg/analyzer/test/src/diagnostics/field_initializer_not_assignable_test.dart @@ -10,6 +10,8 @@ import '../dart/resolution/context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(FieldInitializerNotAssignableTest); + defineReflectiveTests( + FieldInitializerNotAssignableWithoutNullSafetyAndNoImplicitCastsTest); defineReflectiveTests(FieldInitializerNotAssignableWithStrictCastsTest); }); } @@ -66,6 +68,22 @@ enum E { } } +@reflectiveTest +class FieldInitializerNotAssignableWithoutNullSafetyAndNoImplicitCastsTest + extends PubPackageResolutionTest + with WithoutNullSafetyMixin, WithNoImplicitCastsMixin { + test_constructorInitializer() async { + await assertErrorsWithNoImplicitCasts(''' +class A { + int i; + A(num n) : i = n; +} +''', [ + error(CompileTimeErrorCode.FIELD_INITIALIZER_NOT_ASSIGNABLE, 36, 1), + ]); + } +} + @reflectiveTest class FieldInitializerNotAssignableWithStrictCastsTest extends PubPackageResolutionTest with WithStrictCastsMixin { diff --git a/pkg/analyzer/test/src/diagnostics/implicit_dynamic_field_test.dart b/pkg/analyzer/test/src/diagnostics/implicit_dynamic_field_test.dart new file mode 100644 index 000000000000..1bfd6807368c --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/implicit_dynamic_field_test.dart @@ -0,0 +1,120 @@ +// 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:analyzer/src/error/codes.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../dart/resolution/context_collection_resolution.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(ImplicitDynamicFieldTest); + defineReflectiveTests(ImplicitDynamicFieldWithoutNullSafetyTest); + }); +} + +@reflectiveTest +class ImplicitDynamicFieldTest extends PubPackageResolutionTest + with ImplicitDynamicFieldTestCases {} + +mixin ImplicitDynamicFieldTestCases on PubPackageResolutionTest { + @override + void setUp() { + super.setUp(); + writeTestPackageAnalysisOptionsFile( + AnalysisOptionsFileConfig(implicitDynamic: false), + ); + } + + test_instance_explicitDynamic_initialized() async { + await assertNoErrorsInCode(''' +class C { + dynamic f = ([])[0]; +} +'''); + } + + test_instance_explicitDynamic_uninitialized() async { + await assertNoErrorsInCode(''' +class C { + dynamic f; +} +'''); + } + + test_instance_final_initialized() async { + await assertErrorsInCode(''' +class C { + final f = ([])[0]; +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FIELD, 18, 20, + messageContains: ["'f'"]), + ]); + } + + test_instance_final_uninitialized() async { + await assertErrorsInCode(''' +class C { + final f; + C(this.f); +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FIELD, 18, 1), + ]); + } + + test_instance_var_initialized() async { + await assertErrorsInCode(''' +class C { + var f = ([])[0]; +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FIELD, 16, 20), + ]); + } + + test_instance_var_initialized_inference() async { + await assertNoErrorsInCode(''' +class C { + var f = 0; +} +'''); + } + + test_instance_var_uninitialized() async { + await assertErrorsInCode(''' +class C { + var f; +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FIELD, 16, 1), + ]); + } + + test_instance_var_uninitialized_multiple() async { + await assertErrorsInCode(''' +class C { + var f, g = 42, h; +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FIELD, 16, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_FIELD, 27, 1), + ]); + } + + test_static_var_initialized() async { + await assertErrorsInCode(''' +class C { + static var f = ([])[0]; +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FIELD, 23, 20), + ]); + } +} + +@reflectiveTest +class ImplicitDynamicFieldWithoutNullSafetyTest extends PubPackageResolutionTest + with ImplicitDynamicFieldTestCases, WithoutNullSafetyMixin {} diff --git a/pkg/analyzer/test/src/diagnostics/implicit_dynamic_function_test.dart b/pkg/analyzer/test/src/diagnostics/implicit_dynamic_function_test.dart new file mode 100644 index 000000000000..1ec587d9379c --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/implicit_dynamic_function_test.dart @@ -0,0 +1,142 @@ +// 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:analyzer/src/error/codes.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../dart/resolution/context_collection_resolution.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(ImplicitDynamicFunctionTest); + defineReflectiveTests(ImplicitDynamicFunctionWithoutNullSafetyTest); + }); +} + +@reflectiveTest +class ImplicitDynamicFunctionTest extends PubPackageResolutionTest + with ImplicitDynamicFunctionTestCases {} + +mixin ImplicitDynamicFunctionTestCases on PubPackageResolutionTest { + @override + void setUp() { + super.setUp(); + writeTestPackageAnalysisOptionsFile( + AnalysisOptionsFileConfig(implicitDynamic: false), + ); + } + + test_local_downwardInferenceGivesInt() async { + await assertNoErrorsInCode(''' +void f(int d) { + T g() => throw 'x'; + d = g(); +} +'''); + } + + test_local_noDownwardsInference() async { + await assertErrorsInCode(''' +void f(dynamic d) { + T a() => throw 'x'; + d = a(); +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FUNCTION, 51, 1), + ]); + } + + test_local_noInference() async { + await assertErrorsInCode(''' +void f(dynamic d) { + void a() {}; + a(); +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FUNCTION, 40, 1), + ]); + } + + test_local_upwardsInferenceGivesDynamic() async { + await assertErrorsInCode(''' +void f(dynamic d) { + void a(T t) {}; + a(d); +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FUNCTION, 43, 1), + ]); + } + + test_local_upwardsInferenceGivesInt() async { + await assertNoErrorsInCode(''' +void f() { + void a(T t) {}; + a(42); +} +'''); + } + + test_topLevel_downwardInferenceGivesDynamic() async { + await assertErrorsInCode(''' +external T a(); + +void f(dynamic d) { + d = a(); +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FUNCTION, 46, 1), + ]); + } + + test_topLevel_downwardInferenceGivesInt() async { + await assertNoErrorsInCode(''' +external T a(); + +void f(int d) { + d = a(); +} +'''); + } + + test_topLevel_dynamicAssignmentToTypeVariable() async { + await assertErrorsInCode(''' +T a(T t) => t; + +void f(dynamic d) { + a(d); + a(42); +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FUNCTION, 41, 1), + ]); + } + + test_topLevel_intAssignmentToTypeVariable() async { + await assertNoErrorsInCode(''' +T a(T t) => t; + +void f() { + a(42); +} +'''); + } + + test_topLevel_noInference() async { + await assertErrorsInCode(''' +void a() {} + +void f() { + a(); +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_FUNCTION, 29, 1), + ]); + } +} + +@reflectiveTest +class ImplicitDynamicFunctionWithoutNullSafetyTest + extends PubPackageResolutionTest + with ImplicitDynamicFunctionTestCases, WithoutNullSafetyMixin {} diff --git a/pkg/analyzer/test/src/diagnostics/implicit_dynamic_list_literal_test.dart b/pkg/analyzer/test/src/diagnostics/implicit_dynamic_list_literal_test.dart new file mode 100644 index 000000000000..85f8b7920698 --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/implicit_dynamic_list_literal_test.dart @@ -0,0 +1,92 @@ +// 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:analyzer/src/error/codes.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../dart/resolution/context_collection_resolution.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(ImplicitDynamicListLiteralTest); + defineReflectiveTests(ImplicitDynamicListLiteralWithoutNullSafetyTest); + }); +} + +@reflectiveTest +class ImplicitDynamicListLiteralTest extends PubPackageResolutionTest + with ImplicitDynamicListLiteralTestCases {} + +mixin ImplicitDynamicListLiteralTestCases on PubPackageResolutionTest { + @override + void setUp() { + super.setUp(); + writeTestPackageAnalysisOptionsFile( + AnalysisOptionsFileConfig(implicitDynamic: false), + ); + } + + test_assignedToListWithExplicitTypeArgument_dynamic() async { + await assertErrorsInCode(''' +List a = []; +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_LIST_LITERAL, 18, 2), + ]); + } + + test_assignedToListWithExplicitTypeArgument_int() async { + await assertNoErrorsInCode(''' +List a = []; +'''); + } + + test_assignedToRawList() async { + await assertErrorsInCode(''' +List a = []; +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_LIST_LITERAL, 9, 2), + ]); + } + + test_assignedToVar_empty() async { + await assertErrorsInCode(''' +var a = []; +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_LIST_LITERAL, 8, 2), + ]); + } + + test_assignedToVar_nonDynamicElements() async { + await assertNoErrorsInCode(''' +var a = [42]; +'''); + } + + test_dynamicElements() async { + await assertErrorsInCode(''' +void f(dynamic d) { + [d, d]; +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_LIST_LITERAL, 22, 6), + ]); + } + + test_explicitTypeArgument_dynamic() async { + await assertNoErrorsInCode(''' +var a = []; +'''); + } + + test_explicitTypeArgument_int() async { + await assertNoErrorsInCode(''' +var a = []; +'''); + } +} + +@reflectiveTest +class ImplicitDynamicListLiteralWithoutNullSafetyTest + extends PubPackageResolutionTest + with ImplicitDynamicListLiteralTestCases, WithoutNullSafetyMixin {} diff --git a/pkg/analyzer/test/src/diagnostics/implicit_dynamic_map_literal_test.dart b/pkg/analyzer/test/src/diagnostics/implicit_dynamic_map_literal_test.dart new file mode 100644 index 000000000000..b9941ca71f9d --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/implicit_dynamic_map_literal_test.dart @@ -0,0 +1,100 @@ +// 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:analyzer/src/error/codes.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../dart/resolution/context_collection_resolution.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(ImplicitDynamicMapLiteralTest); + defineReflectiveTests(ImplicitDynamicMapLiteralWithoutNullSafetyTest); + }); +} + +@reflectiveTest +class ImplicitDynamicMapLiteralTest extends PubPackageResolutionTest + with ImplicitDynamicMapLiteralTestCases {} + +mixin ImplicitDynamicMapLiteralTestCases on PubPackageResolutionTest { + @override + void setUp() { + super.setUp(); + writeTestPackageAnalysisOptionsFile( + AnalysisOptionsFileConfig(implicitDynamic: false), + ); + } + + test_assignedToMapWithExplicitTypeArguments_dynamic() async { + await assertErrorsInCode(''' +Map a = {}; +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_MAP_LITERAL, 26, 2), + ]); + } + + test_assignedToMapWithExplicitTypeArguments_int() async { + await assertNoErrorsInCode(''' +Map a = {}; +'''); + } + + test_assignedToRawMap() async { + await assertErrorsInCode(''' +Map a = {}; +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_MAP_LITERAL, 8, 2), + ]); + } + + test_assignedToVar_empty() async { + await assertErrorsInCode(''' +var a = {}; +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_MAP_LITERAL, 8, 2), + ]); + } + + test_assignedToVar_nonDynamicElements() async { + await assertNoErrorsInCode(''' +var a = {0: 1}; +'''); + } + + test_dynamicKey() async { + await assertErrorsInCode(''' +dynamic d = 1; +var a = {d: 'x'}; +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_MAP_LITERAL, 23, 8), + ]); + } + + test_dynamicValue() async { + await assertErrorsInCode(''' +dynamic d = 1; +var a = {'x': d}; +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_MAP_LITERAL, 23, 8), + ]); + } + + test_explicitTypeArguments_dynamic() async { + await assertNoErrorsInCode(''' +var a = {}; +'''); + } + + test_explicitTypeArguments_int() async { + await assertNoErrorsInCode(''' +var a = {}; +'''); + } +} + +@reflectiveTest +class ImplicitDynamicMapLiteralWithoutNullSafetyTest + extends PubPackageResolutionTest + with ImplicitDynamicMapLiteralTestCases, WithoutNullSafetyMixin {} diff --git a/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart index 0550fee78ce1..fc2905ab8dbf 100644 --- a/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart +++ b/pkg/analyzer/test/src/diagnostics/invalid_assignment_test.dart @@ -11,6 +11,8 @@ main() { defineReflectiveSuite(() { defineReflectiveTests(InvalidAssignment_ImplicitCallReferenceTest); defineReflectiveTests(InvalidAssignmentTest); + defineReflectiveTests( + InvalidAssignmentWithoutNullSafetyAndNoImplicitCastsTest); defineReflectiveTests(InvalidAssignmentWithoutNullSafetyTest); defineReflectiveTests(InvalidAssignmentWithStrictCastsTest); }); @@ -1021,6 +1023,76 @@ main() { } } +@reflectiveTest +class InvalidAssignmentWithoutNullSafetyAndNoImplicitCastsTest + extends PubPackageResolutionTest + with WithoutNullSafetyMixin, WithNoImplicitCastsMixin { + test_assignment() async { + await assertErrorsWithNoImplicitCasts(''' +void f(num n, int i) { + i = n; +} +''', [ + error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 29, 1), + ]); + } + + test_compoundAssignment() async { + await assertErrorsWithNoImplicitCasts(''' +void f(num n, int i) { + i += n; +} +''', [ + error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 30, 1), + ]); + } + + @failingTest + test_list_spread_dynamic() async { + // TODO(mfairhurst) fix this, see https://github.com/dart-lang/sdk/issues/36267 + await assertErrorsWithNoImplicitCasts(r''' +void f(dynamic a) { + [...a]; +} +''', [ + error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 26, 1), + ]); + } + + @failingTest + test_map_spread_dynamic() async { + // TODO(mfairhurst) fix this, see https://github.com/dart-lang/sdk/issues/36267 + await assertErrorsWithNoImplicitCasts(r''' +void f(dynamic a) { + {...a}; +} +''', [ + error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 44, 1), + ]); + } + + test_numericOps() async { + // Regression test for https://github.com/dart-lang/sdk/issues/26912 + await assertNoErrorsWithNoImplicitCasts(''' +void f(int x, int y) { + x += y; +} +'''); + } + + @failingTest + test_set_spread_dynamic() async { + // TODO(mfairhurst) fix this, see https://github.com/dart-lang/sdk/issues/36267 + await assertErrorsWithNoImplicitCasts(r''' +void f(dynamic a) { + {...a}; +} +''', [ + error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 35, 1), + ]); + } +} + @reflectiveTest class InvalidAssignmentWithoutNullSafetyTest extends PubPackageResolutionTest with InvalidAssignmentTestCases, WithoutNullSafetyMixin { diff --git a/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart index 43773a826cc3..6a85dc3878e2 100644 --- a/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart +++ b/pkg/analyzer/test/src/diagnostics/list_element_type_not_assignable_test.dart @@ -10,6 +10,8 @@ import '../dart/resolution/context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(ListElementTypeNotAssignableTest); + defineReflectiveTests( + ListElementTypeNotAssignableWithoutNullSafetyAndNoImplicitCastsTest); defineReflectiveTests(ListElementTypeNotAssignableWithoutNullSafetyTest); defineReflectiveTests(ListElementTypeNotAssignableWithStrictCastsTest); }); @@ -232,6 +234,61 @@ var v = [42]; } } +@reflectiveTest +class ListElementTypeNotAssignableWithoutNullSafetyAndNoImplicitCastsTest + extends PubPackageResolutionTest + with WithoutNullSafetyMixin, WithNoImplicitCastsMixin { + test_ifElement_falseBranch_dynamic() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, dynamic a) { + [if (c) 0 else a]; +} +''', [ + error(CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE, 50, 1), + ]); + } + + test_ifElement_falseBranch_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, num a) { + [if (c) 0 else a]; +} +''', [ + error(CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE, 46, 1), + ]); + } + + test_ifElement_trueBranch_dynamic() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, dynamic a) { + [if (c) a]; +} +''', [ + error(CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE, 43, 1), + ]); + } + + test_ifElement_trueBranch_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, num a) { + [if (c) a]; +} +''', [ + error(CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE, 39, 1), + ]); + } + + test_spread_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(Iterable a) { + [...a]; +} +''', [ + error(CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE, 37, 1), + ]); + } +} + @reflectiveTest class ListElementTypeNotAssignableWithoutNullSafetyTest extends PubPackageResolutionTest diff --git a/pkg/analyzer/test/src/diagnostics/map_key_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/map_key_type_not_assignable_test.dart index 4b8a88e825ea..ca3c915224f6 100644 --- a/pkg/analyzer/test/src/diagnostics/map_key_type_not_assignable_test.dart +++ b/pkg/analyzer/test/src/diagnostics/map_key_type_not_assignable_test.dart @@ -10,6 +10,8 @@ import '../dart/resolution/context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(MapKeyTypeNotAssignableTest); + defineReflectiveTests( + MapKeyTypeNotAssignableWithoutNullSafetyAndNoImplicitCastsTest); defineReflectiveTests(MapKeyTypeNotAssignableWithoutNullSafetyTest); defineReflectiveTests(MapKeyTypeNotAssignableWithStrictCastsTest); }); @@ -237,6 +239,61 @@ var v = {...{a: 'a'}}; } } +@reflectiveTest +class MapKeyTypeNotAssignableWithoutNullSafetyAndNoImplicitCastsTest + extends PubPackageResolutionTest + with WithoutNullSafetyMixin, WithNoImplicitCastsMixin { + test_ifElement_falseBranch_key_dynamic() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, dynamic a) { + {if (c) 0: 0 else a: 0}; +} +''', [ + error(CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE, 58, 1), + ]); + } + + test_ifElement_falseBranch_key_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, num a) { + {if (c) 0: 0 else a: 0}; +} +''', [ + error(CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE, 54, 1), + ]); + } + + test_ifElement_trueBranch_key_dynamic() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, dynamic a) { + {if (c) a: 0 }; +} +''', [ + error(CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE, 48, 1), + ]); + } + + test_ifElement_trueBranch_key_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, num a) { + {if (c) a: 0}; +} +''', [ + error(CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE, 44, 1), + ]); + } + + test_spread_key_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(Map a) { + {...a}; +} +''', [ + error(CompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE, 50, 1), + ]); + } +} + @reflectiveTest class MapKeyTypeNotAssignableWithoutNullSafetyTest extends PubPackageResolutionTest diff --git a/pkg/analyzer/test/src/diagnostics/map_value_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/map_value_type_not_assignable_test.dart index 0ef7767b97fe..4cebc256d5e6 100644 --- a/pkg/analyzer/test/src/diagnostics/map_value_type_not_assignable_test.dart +++ b/pkg/analyzer/test/src/diagnostics/map_value_type_not_assignable_test.dart @@ -10,6 +10,8 @@ import '../dart/resolution/context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(MapValueTypeNotAssignableTest); + defineReflectiveTests( + MapValueTypeNotAssignableWithoutNullSafetyAndNoImplicitCastsTest); defineReflectiveTests(MapValueTypeNotAssignableWithoutNullSafetyTest); defineReflectiveTests(MapValueTypeNotAssignableWithStrictCastsTest); }); @@ -231,6 +233,61 @@ var v = {...{true: a}}; } } +@reflectiveTest +class MapValueTypeNotAssignableWithoutNullSafetyAndNoImplicitCastsTest + extends PubPackageResolutionTest + with WithoutNullSafetyMixin, WithNoImplicitCastsMixin { + test_ifElement_falseBranch_value_dynamic() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, dynamic a) { + {if (c) 0: 0 else 0: a}; +} +''', [ + error(CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE, 61, 1), + ]); + } + + test_ifElement_falseBranch_value_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, num a) { + {if (c) 0: 0 else 0: a}; +} +''', [ + error(CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE, 57, 1), + ]); + } + + test_ifElement_trueBranch_value_dynamic() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, dynamic a) { + {if (c) 0: a}; +} +''', [ + error(CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE, 51, 1), + ]); + } + + test_ifElement_trueBranch_value_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, num a) { + {if (c) 0: a}; +} +''', [ + error(CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE, 47, 1), + ]); + } + + test_spread_value_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(Map a) { + {...a}; +} +''', [ + error(CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE, 50, 1), + ]); + } +} + @reflectiveTest class MapValueTypeNotAssignableWithoutNullSafetyTest extends PubPackageResolutionTest diff --git a/pkg/analyzer/test/src/diagnostics/non_bool_condition_test.dart b/pkg/analyzer/test/src/diagnostics/non_bool_condition_test.dart index 4c1cf44ddcc8..03a7c939a618 100644 --- a/pkg/analyzer/test/src/diagnostics/non_bool_condition_test.dart +++ b/pkg/analyzer/test/src/diagnostics/non_bool_condition_test.dart @@ -10,6 +10,8 @@ import '../dart/resolution/context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(NonBoolConditionWithoutNullSafetyTest); + defineReflectiveTests( + NonBoolConditionWithoutNullSafetyAndNoImplicitCastsTest); defineReflectiveTests(NonBoolConditionTest); defineReflectiveTests(NonBoolConditionWithStrictCastsTest); }); @@ -38,6 +40,51 @@ void f(Null a) { } } +@reflectiveTest +class NonBoolConditionWithoutNullSafetyAndNoImplicitCastsTest + extends PubPackageResolutionTest + with WithoutNullSafetyMixin, WithNoImplicitCastsMixin { + test_map_ifElement_condition_dynamic() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(dynamic c) { + {if (c) 0: 0}; +} +''', [ + error(CompileTimeErrorCode.NON_BOOL_CONDITION, 37, 1), + ]); + } + + test_map_ifElement_condition_object() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(Object c) { + {if (c) 0: 0}; +} +''', [ + error(CompileTimeErrorCode.NON_BOOL_CONDITION, 36, 1), + ]); + } + + test_set_ifElement_condition_dynamic() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(dynamic c) { + {if (c) 0}; +} +''', [ + error(CompileTimeErrorCode.NON_BOOL_CONDITION, 32, 1), + ]); + } + + test_set_ifElement_condition_object() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(Object c) { + {if (c) 0}; +} +''', [ + error(CompileTimeErrorCode.NON_BOOL_CONDITION, 31, 1), + ]); + } +} + @reflectiveTest class NonBoolConditionWithoutNullSafetyTest extends PubPackageResolutionTest with WithoutNullSafetyMixin { diff --git a/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart b/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart index e84775e73979..3b54f2e7048b 100644 --- a/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart +++ b/pkg/analyzer/test/src/diagnostics/return_of_invalid_type_test.dart @@ -10,6 +10,8 @@ import '../dart/resolution/context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(ReturnOfInvalidTypeTest); + defineReflectiveTests( + ReturnOfInvalidTypeWithoutNullSafetyAndNoImplicitCastsTest); defineReflectiveTests(ReturnOfInvalidTypeWithoutNullSafetyTest); defineReflectiveTests(ReturnOfInvalidTypeWithStrictCastsTest); }); @@ -554,6 +556,28 @@ Map f() => {...[1, 2, 3, 4]}; } } +@reflectiveTest +class ReturnOfInvalidTypeWithoutNullSafetyAndNoImplicitCastsTest + extends PubPackageResolutionTest + with WithoutNullSafetyMixin, WithNoImplicitCastsMixin { + test_return() async { + await assertErrorsWithNoImplicitCasts('int f(num n) => n;', [ + error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 16, 1), + ]); + } + + test_return_async() async { + await assertErrorsWithNoImplicitCasts(r''' +Future> f() async { + List x = ['hello', 'world']; + return x; +} +''', [ + error(CompileTimeErrorCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 89, 1), + ]); + } +} + @reflectiveTest class ReturnOfInvalidTypeWithoutNullSafetyTest extends PubPackageResolutionTest with ReturnOfInvalidTypeTestCases, WithoutNullSafetyMixin {} diff --git a/pkg/analyzer/test/src/diagnostics/set_element_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/set_element_type_not_assignable_test.dart index 91cb6e5cff50..d5cb62bf1fe2 100644 --- a/pkg/analyzer/test/src/diagnostics/set_element_type_not_assignable_test.dart +++ b/pkg/analyzer/test/src/diagnostics/set_element_type_not_assignable_test.dart @@ -10,6 +10,8 @@ import '../dart/resolution/context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(SetElementTypeNotAssignableTest); + defineReflectiveTests( + SetElementTypeNotAssignableWithoutNullSafetyAndNoImplicitCastsTest); defineReflectiveTests(SetElementTypeNotAssignableWithoutNullSafetyTest); defineReflectiveTests(SetElementTypeNotAssignableWithStrictCastsTest); }); @@ -197,6 +199,61 @@ var v = {'abc'}; } } +@reflectiveTest +class SetElementTypeNotAssignableWithoutNullSafetyAndNoImplicitCastsTest + extends PubPackageResolutionTest + with WithoutNullSafetyMixin, WithNoImplicitCastsMixin { + test_ifElement_falseBranch_dynamic() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, dynamic a) { + {if (c) 0 else a}; +} +''', [ + error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 50, 1), + ]); + } + + test_ifElement_falseBranch_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, num a) { + {if (c) 0 else a}; +} +''', [ + error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 46, 1), + ]); + } + + test_ifElement_trueBranch_dynamic() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, dynamic a) { + {if (c) a}; +} +''', [ + error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 43, 1), + ]); + } + + test_ifElement_trueBranch_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(bool c, num a) { + {if (c) a}; +} +''', [ + error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 39, 1), + ]); + } + + test_spread_supertype() async { + await assertErrorsWithNoImplicitCasts(r''' +void f(Iterable a) { + {...a}; +} +''', [ + error(CompileTimeErrorCode.SET_ELEMENT_TYPE_NOT_ASSIGNABLE, 37, 1), + ]); + } +} + @reflectiveTest class SetElementTypeNotAssignableWithoutNullSafetyTest extends PubPackageResolutionTest diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart index 633242f08d8f..9eac6d42b981 100644 --- a/pkg/analyzer/test/src/diagnostics/test_all.dart +++ b/pkg/analyzer/test/src/diagnostics/test_all.dart @@ -296,6 +296,11 @@ import 'implements_repeated_test.dart' as implements_repeated; import 'implements_super_class_test.dart' as implements_super_class; import 'implements_type_alias_expands_to_type_parameter_test.dart' as implements_type_alias_expands_to_type_parameter; +import 'implicit_dynamic_field_test.dart' as implicit_dynamic_field; +import 'implicit_dynamic_function_test.dart' as implicit_dynamic_function; +import 'implicit_dynamic_list_literal_test.dart' + as implicit_dynamic_list_literal; +import 'implicit_dynamic_map_literal_test.dart' as implicit_dynamic_map_literal; import 'implicit_this_reference_in_initializer_test.dart' as implicit_this_reference_in_initializer; import 'import_deferred_library_with_load_function_test.dart' @@ -1016,6 +1021,10 @@ main() { implements_repeated.main(); implements_super_class.main(); implements_type_alias_expands_to_type_parameter.main(); + implicit_dynamic_field.main(); + implicit_dynamic_function.main(); + implicit_dynamic_list_literal.main(); + implicit_dynamic_map_literal.main(); implicit_this_reference_in_initializer.main(); import_deferred_library_with_load_function.main(); import_internal_library.main(); diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart index e863a7522c54..be8bb6e61667 100644 --- a/pkg/analyzer/test/src/task/options_test.dart +++ b/pkg/analyzer/test/src/task/options_test.dart @@ -445,6 +445,52 @@ analyzer: ''', []); } + test_analyzer_strong_mode_deprecated() { + validate(''' +analyzer: + strong-mode: true +''', [AnalysisOptionsHintCode.STRONG_MODE_SETTING_DEPRECATED]); + } + + test_analyzer_strong_mode_error_code_supported() { + validate(''' +analyzer: + errors: + invalid_cast_method: ignore +''', []); + } + + test_analyzer_strong_mode_false_removed() { + validate(''' +analyzer: + strong-mode: false +''', [AnalysisOptionsWarningCode.SPEC_MODE_REMOVED]); + } + + test_analyzer_strong_mode_notAMap() { + validate(''' +analyzer: + strong-mode: + - implicit_casts +''', [AnalysisOptionsWarningCode.INVALID_SECTION_FORMAT]); + } + + test_analyzer_strong_mode_unsupported_key() { + validate(''' +analyzer: + strong-mode: + unsupported: true +''', [AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES]); + } + + test_analyzer_strong_mode_unsupported_value() { + validate(''' +analyzer: + strong-mode: + implicit-dynamic: foo +''', [AnalysisOptionsWarningCode.UNSUPPORTED_VALUE]); + } + test_analyzer_supported_exclude() { validate(''' analyzer: @@ -453,6 +499,13 @@ analyzer: ''', []); } + test_analyzer_supported_strong_mode_supported_bad_value() { + validate(''' +analyzer: + strong-mode: w00t +''', [AnalysisOptionsWarningCode.UNSUPPORTED_VALUE]); + } + test_analyzer_unsupported_option() { validate(''' analyzer: diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart index c3c72a710d3e..121541b56513 100644 --- a/pkg/analyzer/test/src/task/strong/checker_test.dart +++ b/pkg/analyzer/test/src/task/strong/checker_test.dart @@ -1795,6 +1795,217 @@ main() { ]); } + test_implicitDynamic_method() async { + _disableTestPackageImplicitDynamic(); + await assertErrorsInCode(r''' +class C { + T m(T s) => s; + T n() => null; +} +class D { + T m(T s) => s; + T n() => null; +} +void f() { + dynamic d; + int i; + new C().m(d); + new C().m(42); + new C().n(); + d = new C().n(); + i = new C().n(); + + new D().m(d); + new D().m(42); + new D().n(); + d = new D().n(); + i = new D().n(); +} +''', [ + error(HintCode.UNUSED_LOCAL_VARIABLE, 137, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_METHOD, 150, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_METHOD, 183, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_METHOD, 202, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_METHOD, 242, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_METHOD, 285, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_METHOD, 309, 1), + ]); + } + + test_implicitDynamic_parameter() async { + _disableTestPackageImplicitDynamic(); + await assertErrorsInCode(r''' +const dynamic DYNAMIC_VALUE = 42; + +// simple formal +void f0(x) {} +void f1(dynamic x) {} + +// default formal +void df0([x = DYNAMIC_VALUE]) {} +void df1([dynamic x = DYNAMIC_VALUE]) {} + +// https://github.com/dart-lang/sdk/issues/25794 +void df2([x = 42]) {} + +// default formal (named) +void nf0({x = DYNAMIC_VALUE}) {} +void nf1({dynamic x = DYNAMIC_VALUE}) {} + +// https://github.com/dart-lang/sdk/issues/25794 +void nf2({x = 42}) {} + +// field formal +class C { + var x; + C(this.x); +} + +// function typed formal +void ftf0(void x(y)) {} +void ftf1(void x(int y)) {} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_PARAMETER, 60, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_PARAMETER, 117, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_PARAMETER, 241, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_PARAMETER, 290, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_PARAMETER, 414, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_FIELD, 459, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_PARAMETER, 520, 1), + ]); + } + + test_implicitDynamic_return() async { + _disableTestPackageImplicitDynamic(); + await assertErrorsInCode(r''' +// function +f0() {return f0();} +dynamic f1() { return 42; } + +// nested function +void main() { + g0() {return g0();} + dynamic g1() { return 42; } +} + +// methods +class B { + int m1() => 42; +} +class C extends B { + m0() => 123; + m1() => 123; + dynamic m2() => 'hi'; +} + +// accessors +set x(int value) {} +get y0 => 42; +dynamic get y1 => 42; + +// function typed formals +void ftf0(f(int x)) {} +void ftf1(dynamic f(int x)) {} + +// function expressions +var fe0 = (int x) => x as dynamic; +var fe1 = (int x) => x; +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_RETURN, 12, 2, + messageContains: ["'f0'"]), + error(LanguageCode.IMPLICIT_DYNAMIC_RETURN, 96, 2, + messageContains: ["'g0'"]), + error(HintCode.UNUSED_ELEMENT, 96, 2), + error(HintCode.UNUSED_ELEMENT, 126, 2), + error(LanguageCode.IMPLICIT_DYNAMIC_RETURN, 212, 2, + messageContains: ["'m0'"]), + error(LanguageCode.IMPLICIT_DYNAMIC_RETURN, 304, 2, + messageContains: ["'y0'"]), + error(LanguageCode.IMPLICIT_DYNAMIC_RETURN, 373, 1, + messageContains: ["'f'"]), + ]); + } + + test_implicitDynamic_static() async { + _disableTestPackageImplicitDynamic(); + await assertNoErrorsInCode(r''' +class C { + static void test(int body()) {} +} + +void main() { + C.test(() { + return 42; + }); +} +'''); + } + + test_implicitDynamic_type() async { + _disableTestPackageImplicitDynamic(); + await assertErrorsInCode(r''' +class C {} +class M1 {} +class M2 {} +class I {} +class D extends C + with M1, M2 + implements I {} +class D2 = C + with M1, M2 + implements I; + +C f(D d) { + D x = new D(); + D y = new D(); + D z = new D(); + return new C(); +} + +class A {} +class N1> {} +class N2 {} +class J {} +class B extends A with N1, N2 implements J {} +A g(B b) { + B y = new B(); + return new A(); +} +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_TYPE, 33, 4), + error(LanguageCode.IMPLICIT_DYNAMIC_TYPE, 93, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_TYPE, 108, 2), + error(LanguageCode.IMPLICIT_DYNAMIC_TYPE, 126, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_TYPE, 148, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_TYPE, 163, 2), + error(LanguageCode.IMPLICIT_DYNAMIC_TYPE, 181, 1), + error(HintCode.UNUSED_LOCAL_VARIABLE, 200, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_TYPE, 208, 1), + error(HintCode.UNUSED_LOCAL_VARIABLE, 231, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_TYPE, 239, 1), + error(HintCode.UNUSED_LOCAL_VARIABLE, 262, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_TYPE, 270, 1), + error(LanguageCode.IMPLICIT_DYNAMIC_TYPE, 288, 1), + error(HintCode.UNUSED_LOCAL_VARIABLE, 493, 1), + ]); + } + + test_implicitDynamic_variable() async { + _disableTestPackageImplicitDynamic(); + await assertErrorsInCode(r''' +var x0; +var x1 = ([])[0]; +var x2, x3 = 42, x4; +dynamic y0; +dynamic y1 = ([])[0]; +''', [ + error(LanguageCode.IMPLICIT_DYNAMIC_VARIABLE, 4, 2), + error(LanguageCode.IMPLICIT_DYNAMIC_VARIABLE, 12, 21), + error(LanguageCode.IMPLICIT_DYNAMIC_VARIABLE, 39, 2), + error(LanguageCode.IMPLICIT_DYNAMIC_VARIABLE, 52, 2), + ]); + } + test_interfaceOverridesAreAllChecked() { // Regression test for https://github.com/dart-lang/sdk/issues/29766 return assertErrorsInCode(r''' @@ -3257,4 +3468,12 @@ void main () { error(CompileTimeErrorCode.USE_OF_VOID_RESULT, 58, 3), ]); } + + void _disableTestPackageImplicitDynamic() { + writeTestPackageAnalysisOptionsFile( + AnalysisOptionsFileConfig( + implicitDynamic: false, + ), + ); + } } diff --git a/pkg/analyzer/tool/messages/error_code_info.dart b/pkg/analyzer/tool/messages/error_code_info.dart index f0bb4f55d3f0..f2ce958bb737 100644 --- a/pkg/analyzer/tool/messages/error_code_info.dart +++ b/pkg/analyzer/tool/messages/error_code_info.dart @@ -34,6 +34,10 @@ const List errorClasses = [ superclass: 'AnalyzerErrorCode', type: 'COMPILE_TIME_ERROR', extraImports: ['package:analyzer/src/error/analyzer_error_code.dart']), + ErrorClassInfo( + filePath: 'lib/src/error/codes.g.dart', + name: 'LanguageCode', + type: 'COMPILE_TIME_ERROR'), ErrorClassInfo( filePath: 'lib/src/error/codes.g.dart', name: 'StaticWarningCode', diff --git a/pkg/nnbd_migration/lib/src/fix_builder.dart b/pkg/nnbd_migration/lib/src/fix_builder.dart index 7044ed2a3494..52a078c9e4e5 100644 --- a/pkg/nnbd_migration/lib/src/fix_builder.dart +++ b/pkg/nnbd_migration/lib/src/fix_builder.dart @@ -323,6 +323,7 @@ class FixBuilder { // TODO(paulberry): do we need to test both possible values of // strictInference? return TypeSystemImpl( + implicitCasts: typeSystem.implicitCasts, isNonNullableByDefault: true, strictCasts: typeSystem.strictCasts, strictInference: typeSystem.strictInference, diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart index ec7214e68739..08e42504ce73 100644 --- a/pkg/nnbd_migration/test/edge_builder_test.dart +++ b/pkg/nnbd_migration/test/edge_builder_test.dart @@ -68,6 +68,7 @@ class AssignmentCheckerTest extends Object var decoratedClassHierarchy = _DecoratedClassHierarchyForTesting(); var checker = AssignmentCheckerForTesting( TypeSystemImpl( + implicitCasts: true, isNonNullableByDefault: false, strictCasts: false, strictInference: false, @@ -498,6 +499,7 @@ class AssignmentCheckerTest extends Object static void _setCoreLibrariesTypeSystem(TypeProviderImpl typeProvider) { var typeSystem = TypeSystemImpl( isNonNullableByDefault: false, + implicitCasts: true, strictCasts: false, strictInference: false, typeProvider: typeProvider, diff --git a/pkg/nnbd_migration/test/migration_cli_test.dart b/pkg/nnbd_migration/test/migration_cli_test.dart index 9bccda820506..fe320695f22c 100644 --- a/pkg/nnbd_migration/test/migration_cli_test.dart +++ b/pkg/nnbd_migration/test/migration_cli_test.dart @@ -637,6 +637,9 @@ int? y = 0; projectContents['example/$filePath'] = subProject[filePath]; } projectContents['example/analysis_options.yaml'] = ''' +analyzer: + strong-mode: + implicit-casts: false linter: rules: - empty_constructor_bodies