Skip to content

Commit 5bd7d75

Browse files
chloestefantsovaCommit Bot
authored and
Commit Bot
committed
[cfe] Report errors on restricted instance members in enums
Part of #47453 Change-Id: I2fddd2ad5da82807fef7e9ed1d7a6781fde38600 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/237365 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 5f7d226 commit 5bd7d75

38 files changed

+3609
-34
lines changed

pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,15 +2777,39 @@ const MessageCode messageEnumConstructorTearoff = const MessageCode(
27772777
"EnumConstructorTearoff",
27782778
problemMessage: r"""Enum constructors can't be torn off.""");
27792779

2780+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2781+
const Template<Message Function(String name)>
2782+
templateEnumContainsRestrictedInstanceDeclaration =
2783+
const Template<Message Function(String name)>(
2784+
problemMessageTemplate:
2785+
r"""An enum can't declare a non-abstract member named '#name'.""",
2786+
withArguments: _withArgumentsEnumContainsRestrictedInstanceDeclaration);
2787+
2788+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2789+
const Code<Message Function(String name)>
2790+
codeEnumContainsRestrictedInstanceDeclaration =
2791+
const Code<Message Function(String name)>(
2792+
"EnumContainsRestrictedInstanceDeclaration",
2793+
);
2794+
2795+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2796+
Message _withArgumentsEnumContainsRestrictedInstanceDeclaration(String name) {
2797+
if (name.isEmpty) throw 'No name provided';
2798+
name = demangleMixinApplicationName(name);
2799+
return new Message(codeEnumContainsRestrictedInstanceDeclaration,
2800+
problemMessage:
2801+
"""An enum can't declare a non-abstract member named '${name}'.""",
2802+
arguments: {'name': name});
2803+
}
2804+
27802805
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
27812806
const Code<Null> codeEnumContainsValuesDeclaration =
27822807
messageEnumContainsValuesDeclaration;
27832808

27842809
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
27852810
const MessageCode messageEnumContainsValuesDeclaration = const MessageCode(
27862811
"EnumContainsValuesDeclaration",
2787-
problemMessage:
2788-
r"""Enums can't contain declarations of members with the name 'values'.""");
2812+
problemMessage: r"""An enum can't declare a member named 'values'.""");
27892813

27902814
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
27912815
const Code<Null> codeEnumDeclarationEmpty = messageEnumDeclarationEmpty;

pkg/front_end/lib/src/fasta/source/source_enum_builder.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import '../fasta_codes.dart'
3636
templateDuplicatedDeclaration,
3737
templateDuplicatedDeclarationCause,
3838
templateDuplicatedDeclarationSyntheticCause,
39+
templateEnumContainsRestrictedInstanceDeclaration,
3940
templateEnumConstantSameNameAsEnclosing;
4041

4142
import '../kernel/body_builder.dart';
@@ -271,6 +272,28 @@ class SourceEnumBuilder extends SourceClassBuilder {
271272
fileUri);
272273
}
273274

275+
for (String restrictedInstanceMemberName in const [
276+
"index",
277+
"hashCode",
278+
"=="
279+
]) {
280+
Builder? customIndexDeclaration =
281+
scope.lookupLocalMember(restrictedInstanceMemberName, setter: false);
282+
if (customIndexDeclaration is MemberBuilder &&
283+
!customIndexDeclaration.isAbstract) {
284+
// Retrieve the earliest declaration for error reporting.
285+
while (customIndexDeclaration?.next != null) {
286+
customIndexDeclaration = customIndexDeclaration?.next;
287+
}
288+
parent.addProblem(
289+
templateEnumContainsRestrictedInstanceDeclaration
290+
.withArguments(restrictedInstanceMemberName),
291+
customIndexDeclaration!.charOffset,
292+
customIndexDeclaration.fullNameForErrors.length,
293+
fileUri);
294+
}
295+
}
296+
274297
SourceFieldBuilder valuesBuilder = new SourceFieldBuilder(
275298
/* metadata = */ null,
276299
listType,

pkg/front_end/messages.status

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ EnumConstructorSuperInitializer/analyzerCode: Fail
217217
EnumConstructorSuperInitializer/example: Fail
218218
EnumConstructorTearoff/analyzerCode: Fail
219219
EnumConstructorTearoff/example: Fail
220+
EnumContainsRestrictedInstanceDeclaration/analyzerCode: Fail
221+
EnumContainsRestrictedInstanceDeclaration/example: Fail
220222
EnumContainsValuesDeclaration/analyzerCode: Fail
221223
EnumContainsValuesDeclaration/example: Fail
222224
EnumDeclaresConstFactory/analyzerCode: Fail
@@ -225,6 +227,8 @@ EnumDeclaresFactory/analyzerCode: Fail
225227
EnumDeclaresFactory/example: Fail
226228
EnumFactoryRedirectsToConstructor/analyzerCode: Fail
227229
EnumFactoryRedirectsToConstructor/example: Fail
230+
EnumImplementerContainsForbiddedInstanceDeclaration/analyzerCode: Fail
231+
EnumImplementerContainsForbiddedInstanceDeclaration/example: Fail
228232
EnumImplementerContainsValuesDeclaration/analyzerCode: Fail
229233
EnumImplementerContainsValuesDeclaration/example: Fail
230234
EnumInstantiation/example: Fail

pkg/front_end/messages.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5493,7 +5493,7 @@ EnumFactoryRedirectsToConstructor:
54935493
problemMessage: "Enum factory constructors can't redirect to generative constructors."
54945494

54955495
EnumContainsValuesDeclaration:
5496-
problemMessage: "Enums can't contain declarations of members with the name 'values'."
5496+
problemMessage: "An enum can't declare a member named 'values'."
54975497

54985498
EnumImplementerContainsValuesDeclaration:
54995499
problemMessage: "'#name' has 'Enum' as a superinterface and can't contain non-static member with name 'values'."
@@ -5516,3 +5516,6 @@ NonAugmentationClassMemberConflictCause:
55165516

55175517
OptionalSuperParameterWithoutInitializer:
55185518
problemMessage: "Type '#type' of the optional super-initializer parameter '#name' doesn't allow 'null', but the parameter doesn't have a default value, and the default value can't be copied from the corresponding parameter of the super constructor."
5519+
5520+
EnumContainsRestrictedInstanceDeclaration:
5521+
problemMessage: "An enum can't declare a non-abstract member named '#name'."
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
enum E1 {
6+
element;
7+
8+
bool operator==(Object other) => true; // Error.
9+
}
10+
11+
enum E2 {
12+
element;
13+
14+
bool operator==(Object other); // Ok.
15+
}
16+
17+
abstract class I3 {
18+
bool operator==(Object other);
19+
}
20+
21+
enum E3 implements I3 { element } // Ok.
22+
23+
main() {}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/declared_equals.dart:8:16: Error: An enum can't declare a non-abstract member named '=='.
6+
// bool operator==(Object other) => true; // Error.
7+
// ^^
8+
//
9+
import self as self;
10+
import "dart:core" as core;
11+
12+
class E1 extends core::_Enum /*isEnum*/ {
13+
static const field core::List<self::E1> values = #C4;
14+
static const field self::E1 element = #C3;
15+
const constructor •(core::int index, core::String name) → self::E1
16+
: super core::_Enum::•(index, name)
17+
;
18+
method toString() → core::String
19+
return "E1.${this.{core::_Enum::_name}{core::String}}";
20+
operator ==(core::Object other) → core::bool
21+
return true;
22+
}
23+
class E2 extends core::_Enum /*isEnum*/ {
24+
static const field core::List<self::E2> values = #C6;
25+
static const field self::E2 element = #C5;
26+
const constructor •(core::int index, core::String name) → self::E2
27+
: super core::_Enum::•(index, name)
28+
;
29+
method toString() → core::String
30+
return "E2.${this.{core::_Enum::_name}{core::String}}";
31+
abstract operator ==(core::Object other) → core::bool;
32+
}
33+
abstract class I3 extends core::Object {
34+
synthetic constructor •() → self::I3
35+
: super core::Object::•()
36+
;
37+
abstract operator ==(core::Object other) → core::bool;
38+
}
39+
class E3 extends core::_Enum implements self::I3 /*isEnum*/ {
40+
static const field core::List<self::E3> values = #C8;
41+
static const field self::E3 element = #C7;
42+
const constructor •(core::int index, core::String name) → self::E3
43+
: super core::_Enum::•(index, name)
44+
;
45+
method toString() → core::String
46+
return "E3.${this.{core::_Enum::_name}{core::String}}";
47+
}
48+
static method main() → dynamic {}
49+
50+
constants {
51+
#C1 = 0
52+
#C2 = "element"
53+
#C3 = self::E1 {index:#C1, _name:#C2}
54+
#C4 = <self::E1>[#C3]
55+
#C5 = self::E2 {index:#C1, _name:#C2}
56+
#C6 = <self::E2>[#C5]
57+
#C7 = self::E3 {index:#C1, _name:#C2}
58+
#C8 = <self::E3>[#C7]
59+
}
60+
61+
62+
Constructor coverage from constants:
63+
org-dartlang-testcase:///declared_equals.dart:
64+
- E1. (from org-dartlang-testcase:///declared_equals.dart:5:6)
65+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
66+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
67+
- E2. (from org-dartlang-testcase:///declared_equals.dart:11:6)
68+
- E3. (from org-dartlang-testcase:///declared_equals.dart:21:6)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/declared_equals.dart:8:16: Error: An enum can't declare a non-abstract member named '=='.
6+
// bool operator==(Object other) => true; // Error.
7+
// ^^
8+
//
9+
import self as self;
10+
import "dart:core" as core;
11+
12+
class E1 extends core::_Enum /*isEnum*/ {
13+
static const field core::List<self::E1> values = #C4;
14+
static const field self::E1 element = #C3;
15+
const constructor •(core::int index, core::String name) → self::E1
16+
: super core::_Enum::•(index, name)
17+
;
18+
method toString() → core::String
19+
return "E1.${this.{core::_Enum::_name}{core::String}}";
20+
operator ==(core::Object other) → core::bool
21+
return true;
22+
}
23+
class E2 extends core::_Enum /*isEnum*/ {
24+
static const field core::List<self::E2> values = #C6;
25+
static const field self::E2 element = #C5;
26+
const constructor •(core::int index, core::String name) → self::E2
27+
: super core::_Enum::•(index, name)
28+
;
29+
method toString() → core::String
30+
return "E2.${this.{core::_Enum::_name}{core::String}}";
31+
abstract operator ==(core::Object other) → core::bool;
32+
}
33+
abstract class I3 extends core::Object {
34+
synthetic constructor •() → self::I3
35+
: super core::Object::•()
36+
;
37+
abstract operator ==(core::Object other) → core::bool;
38+
}
39+
class E3 extends core::_Enum implements self::I3 /*isEnum*/ {
40+
static const field core::List<self::E3> values = #C8;
41+
static const field self::E3 element = #C7;
42+
const constructor •(core::int index, core::String name) → self::E3
43+
: super core::_Enum::•(index, name)
44+
;
45+
method toString() → core::String
46+
return "E3.${this.{core::_Enum::_name}{core::String}}";
47+
}
48+
static method main() → dynamic {}
49+
50+
constants {
51+
#C1 = 0
52+
#C2 = "element"
53+
#C3 = self::E1 {index:#C1, _name:#C2}
54+
#C4 = <self::E1>[#C3]
55+
#C5 = self::E2 {index:#C1, _name:#C2}
56+
#C6 = <self::E2>[#C5]
57+
#C7 = self::E3 {index:#C1, _name:#C2}
58+
#C8 = <self::E3>[#C7]
59+
}
60+
61+
62+
Constructor coverage from constants:
63+
org-dartlang-testcase:///declared_equals.dart:
64+
- E1. (from org-dartlang-testcase:///declared_equals.dart:5:6)
65+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
66+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
67+
- E2. (from org-dartlang-testcase:///declared_equals.dart:11:6)
68+
- E3. (from org-dartlang-testcase:///declared_equals.dart:21:6)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
enum E1 {
2+
element;
3+
4+
bool operator ==(Object other) => true;
5+
}
6+
7+
enum E2 {
8+
element;
9+
10+
bool operator ==(Object other);
11+
}
12+
13+
abstract class I3 {
14+
bool operator ==(Object other);
15+
}
16+
17+
enum E3 implements I3 { element }
18+
19+
main() {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
abstract class I3 {
2+
bool operator ==(Object other);
3+
}
4+
5+
enum E1 {
6+
element;
7+
8+
bool operator ==(Object other) => true;
9+
}
10+
11+
enum E2 {
12+
element;
13+
14+
bool operator ==(Object other);
15+
}
16+
17+
enum E3 implements I3 { element }
18+
19+
main() {}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/declared_equals.dart:8:16: Error: An enum can't declare a non-abstract member named '=='.
6+
// bool operator==(Object other) => true; // Error.
7+
// ^^
8+
//
9+
import self as self;
10+
import "dart:core" as core;
11+
12+
class E1 extends core::_Enum /*isEnum*/ {
13+
static const field core::List<self::E1> values = #C4;
14+
static const field self::E1 element = #C3;
15+
const constructor •(core::int index, core::String name) → self::E1
16+
: super core::_Enum::•(index, name)
17+
;
18+
method toString() → core::String
19+
return "E1.${this.{core::_Enum::_name}{core::String}}";
20+
operator ==(core::Object other) → core::bool
21+
return true;
22+
}
23+
class E2 extends core::_Enum /*isEnum*/ {
24+
static const field core::List<self::E2> values = #C6;
25+
static const field self::E2 element = #C5;
26+
const constructor •(core::int index, core::String name) → self::E2
27+
: super core::_Enum::•(index, name)
28+
;
29+
method toString() → core::String
30+
return "E2.${this.{core::_Enum::_name}{core::String}}";
31+
abstract operator ==(core::Object other) → core::bool;
32+
}
33+
abstract class I3 extends core::Object {
34+
synthetic constructor •() → self::I3
35+
: super core::Object::•()
36+
;
37+
abstract operator ==(core::Object other) → core::bool;
38+
}
39+
class E3 extends core::_Enum implements self::I3 /*isEnum*/ {
40+
static const field core::List<self::E3> values = #C8;
41+
static const field self::E3 element = #C7;
42+
const constructor •(core::int index, core::String name) → self::E3
43+
: super core::_Enum::•(index, name)
44+
;
45+
method toString() → core::String
46+
return "E3.${this.{core::_Enum::_name}{core::String}}";
47+
}
48+
static method main() → dynamic {}
49+
50+
constants {
51+
#C1 = 0
52+
#C2 = "element"
53+
#C3 = self::E1 {index:#C1, _name:#C2}
54+
#C4 = <self::E1*>[#C3]
55+
#C5 = self::E2 {index:#C1, _name:#C2}
56+
#C6 = <self::E2*>[#C5]
57+
#C7 = self::E3 {index:#C1, _name:#C2}
58+
#C8 = <self::E3*>[#C7]
59+
}
60+
61+
62+
Constructor coverage from constants:
63+
org-dartlang-testcase:///declared_equals.dart:
64+
- E1. (from org-dartlang-testcase:///declared_equals.dart:5:6)
65+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
66+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
67+
- E2. (from org-dartlang-testcase:///declared_equals.dart:11:6)
68+
- E3. (from org-dartlang-testcase:///declared_equals.dart:21:6)

0 commit comments

Comments
 (0)