From f15518dffc2c6df7ee43ad2a00a963cb8ce69cff Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Mon, 7 Feb 2022 21:47:45 +0000 Subject: [PATCH] Report ILLEGAL_ENUM_VALUES_DECLARATION/INHERITANCE Change-Id: I31a02b7c0fe50362ed6d9cb66159db3386f3b56e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/232020 Reviewed-by: Brian Wilkerson Commit-Queue: Konstantin Shcheglov --- pkg/analyzer/lib/error/error.dart | 2 + pkg/analyzer/lib/src/error/codes.g.dart | 20 ++ .../error/duplicate_definition_verifier.dart | 2 +- .../lib/src/error/inheritance_override.dart | 36 +++ pkg/analyzer/messages.yaml | 9 + .../illegal_enum_values_declaration_test.dart | 215 ++++++++++++++++++ .../illegal_enum_values_inheritance_test.dart | 151 ++++++++++++ .../test/src/diagnostics/test_all.dart | 6 + 8 files changed, 440 insertions(+), 1 deletion(-) create mode 100644 pkg/analyzer/test/src/diagnostics/illegal_enum_values_declaration_test.dart create mode 100644 pkg/analyzer/test/src/diagnostics/illegal_enum_values_inheritance_test.dart diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart index e222aa97d62..8b7f406e702 100644 --- a/pkg/analyzer/lib/error/error.dart +++ b/pkg/analyzer/lib/error/error.dart @@ -212,6 +212,8 @@ const List errorCodeValues = [ CompileTimeErrorCode.IF_ELEMENT_CONDITION_FROM_DEFERRED_LIBRARY, CompileTimeErrorCode.ILLEGAL_ASYNC_GENERATOR_RETURN_TYPE, CompileTimeErrorCode.ILLEGAL_ASYNC_RETURN_TYPE, + CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, + CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, CompileTimeErrorCode.ILLEGAL_LANGUAGE_VERSION_OVERRIDE, CompileTimeErrorCode.ILLEGAL_NON_ABSTRACT_ENUM_INDEX, CompileTimeErrorCode.ILLEGAL_SYNC_GENERATOR_RETURN_TYPE, diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart index f9728974190..d6188ac44f0 100644 --- a/pkg/analyzer/lib/src/error/codes.g.dart +++ b/pkg/analyzer/lib/src/error/codes.g.dart @@ -5737,6 +5737,26 @@ class CompileTimeErrorCode extends AnalyzerErrorCode { hasPublishedDocs: true, ); + static const CompileTimeErrorCode ILLEGAL_ENUM_VALUES_DECLARATION = + CompileTimeErrorCode( + 'ILLEGAL_ENUM_VALUES_DECLARATION', + "An instance member named 'values' can't be declared in a class that " + "implements 'Enum'.", + correctionMessage: "Try using a different name.", + ); + + /** + * Parameters: + * 0: the name of the class that declares 'values' + */ + static const CompileTimeErrorCode ILLEGAL_ENUM_VALUES_INHERITANCE = + CompileTimeErrorCode( + 'ILLEGAL_ENUM_VALUES_INHERITANCE', + "An instance member named 'values' can't be inherited from '{0}' in a " + "class that implements 'Enum'.", + correctionMessage: "Try using a different name.", + ); + static const CompileTimeErrorCode ILLEGAL_LANGUAGE_VERSION_OVERRIDE = CompileTimeErrorCode( 'ILLEGAL_LANGUAGE_VERSION_OVERRIDE', diff --git a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart index a25b660b993..58934633579 100644 --- a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart +++ b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart @@ -107,7 +107,7 @@ class DuplicateDefinitionVerifier { var baseName = accessor.displayName; if (accessor.isStatic) { var instance = _getInterfaceMember(enumElement, baseName); - if (instance != null) { + if (instance != null && baseName != 'values') { _errorReporter.reportErrorForElement( CompileTimeErrorCode.CONFLICTING_STATIC_AND_INSTANCE, accessor, diff --git a/pkg/analyzer/lib/src/error/inheritance_override.dart b/pkg/analyzer/lib/src/error/inheritance_override.dart index 662fccebd64..d78da68c34a 100644 --- a/pkg/analyzer/lib/src/error/inheritance_override.dart +++ b/pkg/analyzer/lib/src/error/inheritance_override.dart @@ -199,6 +199,7 @@ class _ClassVerifier { _checkDeclaredMember(field.name, libraryUri, fieldElement.setter); if (!member.isStatic) { _checkIllegalNonAbstractEnumIndex(field.name); + _checkIllegalEnumValuesDeclaration(field.name); } } } else if (member is MethodDeclaration) { @@ -209,12 +210,17 @@ class _ClassVerifier { _checkDeclaredMember(member.name, libraryUri, member.declaredElement, methodParameterNodes: member.parameters?.parameters); + if (!member.isStatic) { + _checkIllegalEnumValuesDeclaration(member.name); + } if (!(member.isStatic || member.isAbstract || member.isSetter)) { _checkIllegalNonAbstractEnumIndex(member.name); } } } + _checkIllegalEnumValuesInheritance(); + GetterSetterTypesVerifier( typeSystem: typeSystem, errorReporter: reporter, @@ -625,6 +631,36 @@ class _ClassVerifier { return false; } + void _checkIllegalEnumValuesDeclaration(SimpleIdentifier name) { + if (implementsDartCoreEnum && name.name == 'values') { + reporter.reportErrorForNode( + CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, + name, + ); + } + } + + void _checkIllegalEnumValuesInheritance() { + if (implementsDartCoreEnum) { + var getter = inheritance.getInherited2( + classElement, + Name(libraryUri, 'values'), + ); + var setter = inheritance.getInherited2( + classElement, + Name(libraryUri, 'values='), + ); + var inherited = getter ?? setter; + if (inherited != null) { + reporter.reportErrorForNode( + CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, + classNameNode, + [inherited.enclosingElement.name!], + ); + } + } + } + void _checkIllegalNonAbstractEnumIndex(SimpleIdentifier name) { if (implementsDartCoreEnum && name.name == 'index') { reporter.reportErrorForNode( diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml index 903fa99dd1f..367c6f5ffa5 100644 --- a/pkg/analyzer/messages.yaml +++ b/pkg/analyzer/messages.yaml @@ -5018,6 +5018,15 @@ CompileTimeErrorCode: ```dart int f() => 0; ``` + ILLEGAL_ENUM_VALUES_DECLARATION: + problemMessage: An instance member named 'values' can't be declared in a class that implements 'Enum'. + correctionMessage: Try using a different name. + ILLEGAL_ENUM_VALUES_INHERITANCE: + problemMessage: An instance member named 'values' can't be inherited from '{0}' in a class that implements 'Enum'. + correctionMessage: Try using a different name. + comment: |- + Parameters: + 0: the name of the class that declares 'values' ILLEGAL_LANGUAGE_VERSION_OVERRIDE: problemMessage: The language version must be {0}. correctionMessage: Try removing the language version override and migrating the code. diff --git a/pkg/analyzer/test/src/diagnostics/illegal_enum_values_declaration_test.dart b/pkg/analyzer/test/src/diagnostics/illegal_enum_values_declaration_test.dart new file mode 100644 index 00000000000..bf6a079604c --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/illegal_enum_values_declaration_test.dart @@ -0,0 +1,215 @@ +// Copyright (c) 2022, 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(IllegalEnumValuesDeclarationTest); + }); +} + +@reflectiveTest +class IllegalEnumValuesDeclarationTest extends PubPackageResolutionTest { + test_class_field() async { + await assertErrorsInCode(r''' +abstract class A implements Enum { + int values = 0; +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 41, 6), + ]); + } + + test_class_field_static() async { + await assertNoErrorsInCode(r''' +abstract class A implements Enum { + static int values = 0; +} +'''); + } + + test_class_getter() async { + await assertErrorsInCode(r''' +abstract class A implements Enum { + int get values => 0; +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 45, 6), + ]); + } + + test_class_getter_static() async { + await assertNoErrorsInCode(r''' +abstract class A implements Enum { + static int get values => 0; +} +'''); + } + + test_class_method() async { + await assertErrorsInCode(r''' +abstract class A implements Enum { + void values() {} +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 42, 6), + ]); + } + + test_class_method_static() async { + await assertNoErrorsInCode(r''' +abstract class A implements Enum { + static void values() {} +} +'''); + } + + test_class_setter() async { + await assertErrorsInCode(r''' +abstract class A implements Enum { + set values(int _) {} +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 41, 6), + ]); + } + + test_class_setter_static() async { + await assertNoErrorsInCode(r''' +abstract class A implements Enum { + static set values(int _) {} +} +'''); + } + + test_enum_field() async { + await assertErrorsInCode(r''' +enum E { + v; + int values = 0; +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 20, 6), + ]); + } + + /// TODO(scheglov) this is wrong, we should get an error + test_enum_field_static() async { + await assertNoErrorsInCode(r''' +enum E { + v; + static int values = 0; +} +'''); + } + + test_enum_getter() async { + await assertErrorsInCode(r''' +enum E { + v; + int get values => 0; +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 24, 6), + ]); + } + + test_enum_method() async { + await assertErrorsInCode(r''' +enum E { + v; + void values() {} +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 21, 6), + ]); + } + + test_enum_setter() async { + await assertErrorsInCode(r''' +enum E { + v; + set values(int _) {} +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 20, 6), + ]); + } + + test_mixin_field() async { + await assertErrorsInCode(r''' +mixin M on Enum { + int values = 0; +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 24, 6), + ]); + } + + test_mixin_field_static() async { + await assertNoErrorsInCode(r''' +mixin M on Enum { + static int values = 0; +} +'''); + } + + test_mixin_getter() async { + await assertErrorsInCode(r''' +mixin M on Enum { + int get values => 0; +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 28, 6), + ]); + } + + test_mixin_getter_static() async { + await assertNoErrorsInCode(r''' +mixin M on Enum { + static int get values => 0; +} +'''); + } + + test_mixin_method() async { + await assertErrorsInCode(r''' +mixin M on Enum { + void values() {} +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 25, 6), + ]); + } + + test_mixin_method_static() async { + await assertNoErrorsInCode(r''' +mixin M on Enum { + static void values() {} +} +'''); + } + + test_mixin_setter() async { + await assertErrorsInCode(r''' +mixin M on Enum { + set values(int _) {} +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_DECLARATION, 24, 6), + ]); + } + + test_mixin_setter_static() async { + await assertNoErrorsInCode(r''' +mixin M on Enum { + static set values(int _) {} +} +'''); + } +} diff --git a/pkg/analyzer/test/src/diagnostics/illegal_enum_values_inheritance_test.dart b/pkg/analyzer/test/src/diagnostics/illegal_enum_values_inheritance_test.dart new file mode 100644 index 00000000000..234df7e1b4e --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/illegal_enum_values_inheritance_test.dart @@ -0,0 +1,151 @@ +// Copyright (c) 2022, 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(IllegalEnumValuesInheritanceTest); + }); +} + +@reflectiveTest +class IllegalEnumValuesInheritanceTest extends PubPackageResolutionTest { + test_class_field_fromExtends() async { + await assertErrorsInCode(r''' +class A { + int values = 0; +} + +abstract class B extends A implements Enum {} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, 46, 1), + ]); + } + + test_class_field_fromImplements() async { + await assertErrorsInCode(r''' +class A { + int values = 0; +} + +abstract class B implements A, Enum {} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, 46, 1), + ]); + } + + test_class_field_fromWith() async { + await assertErrorsInCode(r''' +mixin M { + int values = 0; +} + +abstract class B with M implements Enum {} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, 46, 1), + ]); + } + + test_class_getter() async { + await assertErrorsInCode(r''' +class A { + int get values => 0; +} + +abstract class B extends A implements Enum {} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, 51, 1), + ]); + } + + test_class_method() async { + await assertErrorsInCode(r''' +class A { + void values() {} +} + +abstract class B extends A implements Enum {} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, 47, 1), + ]); + } + + test_class_setter() async { + await assertErrorsInCode(r''' +class A { + set values(int _) {} +} + +abstract class B extends A implements Enum {} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, 51, 1), + ]); + } + + test_enum_method() async { + await assertErrorsInCode(r''' +mixin M { + int values() => 0; +} + +enum E with M { + v +} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, 39, 1), + ]); + } + + test_mixin_field() async { + await assertErrorsInCode(r''' +class A { + int values = 0; +} + +mixin M on A implements Enum {} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, 37, 1), + ]); + } + + test_mixin_getter() async { + await assertErrorsInCode(r''' +class A { + int get values => 0; +} + +mixin M on A implements Enum {} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, 42, 1), + ]); + } + + test_mixin_method() async { + await assertErrorsInCode(r''' +class A { + int values() => 0; +} + +mixin M on A implements Enum {} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, 40, 1), + ]); + } + + test_mixin_setter() async { + await assertErrorsInCode(r''' +class A { + set values(int _) {} +} + +mixin M on A implements Enum {} +''', [ + error(CompileTimeErrorCode.ILLEGAL_ENUM_VALUES_INHERITANCE, 42, 1), + ]); + } +} diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart index 26528a85023..739d2af21f1 100644 --- a/pkg/analyzer/test/src/diagnostics/test_all.dart +++ b/pkg/analyzer/test/src/diagnostics/test_all.dart @@ -253,6 +253,10 @@ import 'if_element_condition_from_deferred_library_test.dart' import 'illegal_async_generator_return_type_test.dart' as illegal_async_generator_return_type; import 'illegal_async_return_type_test.dart' as illegal_async_return_type; +import 'illegal_enum_values_declaration_test.dart' + as illegal_enum_values_declaration; +import 'illegal_enum_values_inheritance_test.dart' + as illegal_enum_values_inheritance; import 'illegal_language_version_override_test.dart' as illegal_language_version_override; import 'illegal_non_abstract_enum_index_test.dart' @@ -945,6 +949,8 @@ main() { if_element_condition_from_deferred_library.main(); illegal_async_generator_return_type.main(); illegal_async_return_type.main(); + illegal_enum_values_declaration.main(); + illegal_enum_values_inheritance.main(); illegal_language_version_override.main(); illegal_non_abstract_enum_index.main(); illegal_sync_generator_return_type.main();