Add EnumConstantArguments and EnumConstantConstructorName.
Change-Id: I64ec609b8c505eec1db6100f7eaf5b518eefa6f7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/228760
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index a0b7a9c..748df11 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -402,6 +402,8 @@
R? visitConstructorReference(ConstructorReference node);
+ R? visitConstructorSelector(ConstructorSelector node);
+
R? visitContinueStatement(ContinueStatement node);
R? visitDeclaredIdentifier(DeclaredIdentifier node);
@@ -418,6 +420,8 @@
R? visitEmptyStatement(EmptyStatement node);
+ R? visitEnumConstantArguments(EnumConstantArguments node);
+
R? visitEnumConstantDeclaration(EnumConstantDeclaration node);
R? visitEnumDeclaration(EnumDeclaration node);
@@ -1365,6 +1369,20 @@
ConstructorElement? get staticElement;
}
+/// The name of a constructor being invoked.
+///
+/// constructorSelector ::=
+/// '.' identifier
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class ConstructorSelector implements AstNode {
+ /// Return the constructor name.
+ SimpleIdentifier get name;
+
+ /// Return the period before the constructor name.
+ Token get period;
+}
+
/// A continue statement.
///
/// continueStatement ::=
@@ -1563,10 +1581,41 @@
Token get semicolon;
}
+/// The arguments part of an enum constant.
+///
+/// enumConstantArguments ::=
+/// [TypeArgumentList]? [ConstructorSelector]? [ArgumentList]
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class EnumConstantArguments implements AstNode {
+ /// Return the explicit arguments (there are always implicit `index` and
+ /// `name` leading arguments) to the invoked constructor.
+ ArgumentList get argumentList;
+
+ /// Return the selector of the constructor that is invoked by this enum
+ /// constant, or `null` if the default constructor is invoked.
+ ConstructorSelector? get constructorSelector;
+
+ /// Return the type arguments applied to the enclosing enum declaration
+ /// when invoking the constructor, or `null` if no type arguments were
+ /// provided.
+ TypeArgumentList? get typeArguments;
+}
+
/// The declaration of an enum constant.
///
/// Clients may not extend, implement or mix-in this class.
abstract class EnumConstantDeclaration implements Declaration {
+ /// Return the explicit arguments (there are always implicit `index` and
+ /// `name` leading arguments) to the invoked constructor, or `null` if this
+ /// constant does not provide any explicit arguments.
+ EnumConstantArguments? get arguments;
+
+ /// Return the constructor that is invoked by this enum constant, or `null`
+ /// if the AST structure has not been resolved, or if the constructor could
+ /// not be resolved.
+ ConstructorElement? get constructorElement;
+
/// Return the name of the constant.
SimpleIdentifier get name;
}
diff --git a/pkg/analyzer/lib/dart/ast/visitor.dart b/pkg/analyzer/lib/dart/ast/visitor.dart
index a77a83e..309fcf1 100644
--- a/pkg/analyzer/lib/dart/ast/visitor.dart
+++ b/pkg/analyzer/lib/dart/ast/visitor.dart
@@ -230,6 +230,9 @@
visitExpression(node);
@override
+ R? visitConstructorSelector(ConstructorSelector node) => visitNode(node);
+
+ @override
R? visitContinueStatement(ContinueStatement node) => visitStatement(node);
R? visitDeclaration(Declaration node) => visitAnnotatedNode(node);
@@ -259,6 +262,9 @@
R? visitEmptyStatement(EmptyStatement node) => visitStatement(node);
@override
+ R? visitEnumConstantArguments(EnumConstantArguments node) => visitNode(node);
+
+ @override
R? visitEnumConstantDeclaration(EnumConstantDeclaration node) =>
visitDeclaration(node);
@@ -803,6 +809,12 @@
}
@override
+ R? visitConstructorSelector(ConstructorSelector node) {
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
R? visitContinueStatement(ContinueStatement node) {
node.visitChildren(this);
return null;
@@ -851,6 +863,12 @@
}
@override
+ R? visitEnumConstantArguments(EnumConstantArguments node) {
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
R? visitEnumConstantDeclaration(EnumConstantDeclaration node) {
node.visitChildren(this);
return null;
@@ -1511,6 +1529,9 @@
R? visitConstructorReference(ConstructorReference node) => null;
@override
+ R? visitConstructorSelector(ConstructorSelector node) => null;
+
+ @override
R? visitContinueStatement(ContinueStatement node) => null;
@override
@@ -1535,6 +1556,9 @@
R? visitEmptyStatement(EmptyStatement node) => null;
@override
+ R? visitEnumConstantArguments(EnumConstantArguments node) => null;
+
+ @override
R? visitEnumConstantDeclaration(EnumConstantDeclaration node) => null;
@override
@@ -1917,6 +1941,9 @@
R? visitConstructorReference(ConstructorReference node) => _throw(node);
@override
+ R? visitConstructorSelector(ConstructorSelector node) => _throw(node);
+
+ @override
R? visitContinueStatement(ContinueStatement node) => _throw(node);
@override
@@ -1941,6 +1968,9 @@
R? visitEmptyStatement(EmptyStatement node) => _throw(node);
@override
+ R? visitEnumConstantArguments(EnumConstantArguments node) => _throw(node);
+
+ @override
R? visitEnumConstantDeclaration(EnumConstantDeclaration node) => _throw(node);
@override
@@ -2466,6 +2496,14 @@
}
@override
+ T? visitConstructorSelector(ConstructorSelector node) {
+ stopwatch.start();
+ T? result = _baseVisitor.visitConstructorSelector(node);
+ stopwatch.stop();
+ return result;
+ }
+
+ @override
T? visitContinueStatement(ContinueStatement node) {
stopwatch.start();
T? result = _baseVisitor.visitContinueStatement(node);
@@ -2530,6 +2568,14 @@
}
@override
+ T? visitEnumConstantArguments(EnumConstantArguments node) {
+ stopwatch.start();
+ T? result = _baseVisitor.visitEnumConstantArguments(node);
+ stopwatch.stop();
+ return result;
+ }
+
+ @override
T? visitEnumConstantDeclaration(EnumConstantDeclaration node) {
stopwatch.start();
T? result = _baseVisitor.visitEnumConstantDeclaration(node);
@@ -3387,6 +3433,9 @@
R? visitConstructorReference(ConstructorReference node) => visitNode(node);
@override
+ R? visitConstructorSelector(ConstructorSelector node) => visitNode(node);
+
+ @override
R? visitContinueStatement(ContinueStatement node) => visitNode(node);
@override
@@ -3412,6 +3461,9 @@
R? visitEmptyStatement(EmptyStatement node) => visitNode(node);
@override
+ R? visitEnumConstantArguments(EnumConstantArguments node) => visitNode(node);
+
+ @override
R? visitEnumConstantDeclaration(EnumConstantDeclaration node) =>
visitNode(node);
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index ca91eb4..5218135 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -2725,6 +2725,41 @@
}
}
+class ConstructorSelectorImpl extends AstNodeImpl
+ implements ConstructorSelector {
+ @override
+ final Token period;
+
+ @override
+ final SimpleIdentifierImpl name;
+
+ ConstructorSelectorImpl({
+ required this.period,
+ required this.name,
+ }) {
+ _becomeParentOf(name);
+ }
+
+ @override
+ Token get beginToken => period;
+
+ @override
+ Iterable<SyntacticEntity> get childEntities => ChildEntities()
+ ..add(period)
+ ..add(name);
+
+ @override
+ Token get endToken => name.token;
+
+ @override
+ E? accept<E>(AstVisitor<E> visitor) {
+ return visitor.visitConstructorSelector(this);
+ }
+
+ @override
+ void visitChildren(AstVisitor visitor) {}
+}
+
/// A continue statement.
///
/// continueStatement ::=
@@ -3242,31 +3277,89 @@
}
}
+class EnumConstantArgumentsImpl extends AstNodeImpl
+ implements EnumConstantArguments {
+ @override
+ final TypeArgumentListImpl? typeArguments;
+
+ @override
+ final ConstructorSelectorImpl? constructorSelector;
+
+ @override
+ final ArgumentListImpl argumentList;
+
+ EnumConstantArgumentsImpl({
+ required this.typeArguments,
+ required this.constructorSelector,
+ required this.argumentList,
+ }) {
+ _becomeParentOf(typeArguments);
+ _becomeParentOf(constructorSelector);
+ _becomeParentOf(argumentList);
+ }
+
+ @override
+ Token get beginToken =>
+ (typeArguments ?? constructorSelector ?? argumentList).beginToken;
+
+ @override
+ Iterable<SyntacticEntity> get childEntities => ChildEntities()
+ ..add(typeArguments)
+ ..add(constructorSelector)
+ ..add(argumentList);
+
+ @override
+ Token get endToken => argumentList.endToken;
+
+ @override
+ E? accept<E>(AstVisitor<E> visitor) {
+ return visitor.visitEnumConstantArguments(this);
+ }
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ typeArguments?.accept(visitor);
+ constructorSelector?.accept(visitor);
+ argumentList.accept(visitor);
+ }
+}
+
/// The declaration of an enum constant.
class EnumConstantDeclarationImpl extends DeclarationImpl
implements EnumConstantDeclaration {
/// The name of the constant.
SimpleIdentifierImpl _name;
+ @override
+ final EnumConstantArgumentsImpl? arguments;
+
+ @override
+ ConstructorElement? constructorElement;
+
/// Initialize a newly created enum constant declaration. Either or both of
- /// the [comment] and [metadata] can be `null` if the constant does not have
- /// the corresponding attribute. (Technically, enum constants cannot have
- /// metadata, but we allow it for consistency.)
- EnumConstantDeclarationImpl(
- CommentImpl? comment, List<Annotation>? metadata, this._name)
- : super(comment, metadata) {
+ /// the [documentationComment] and [metadata] can be `null` if the constant
+ /// does not have the corresponding attribute.
+ EnumConstantDeclarationImpl({
+ required CommentImpl? documentationComment,
+ required List<Annotation>? metadata,
+ required SimpleIdentifierImpl name,
+ required this.arguments,
+ }) : _name = name,
+ super(documentationComment, metadata) {
_becomeParentOf(_name);
+ _becomeParentOf(arguments);
}
@override
- Iterable<SyntacticEntity> get childEntities =>
- super._childEntities..add(_name);
+ Iterable<SyntacticEntity> get childEntities => super._childEntities
+ ..add(_name)
+ ..add(arguments);
@override
FieldElement get declaredElement => _name.staticElement as FieldElement;
@override
- Token get endToken => _name.endToken;
+ Token get endToken => (arguments ?? _name).endToken;
@override
Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
@@ -3286,6 +3379,7 @@
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_name.accept(visitor);
+ arguments?.accept(visitor);
}
}
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index 806d84e..37cfef3 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -385,7 +385,11 @@
EnumConstantDeclarationImpl enumConstantDeclaration(Comment? comment,
List<Annotation>? metadata, SimpleIdentifier name) =>
EnumConstantDeclarationImpl(
- comment as CommentImpl?, metadata, name as SimpleIdentifierImpl);
+ documentationComment: comment as CommentImpl?,
+ metadata: metadata,
+ name: name as SimpleIdentifierImpl,
+ arguments: null,
+ );
@Deprecated('Use enumDeclaration2() instead')
@override
diff --git a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
index 294a89f..d2c7f88 100644
--- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
@@ -249,6 +249,12 @@
}
@override
+ void visitConstructorSelector(ConstructorSelector node) {
+ _visitToken(node.period);
+ _visitNode(node.name);
+ }
+
+ @override
void visitContinueStatement(ContinueStatement node) {
sink.write('continue');
_visitNode(node.label, prefix: ' ');
@@ -306,9 +312,17 @@
}
@override
+ void visitEnumConstantArguments(EnumConstantArguments node) {
+ _visitNode(node.typeArguments);
+ _visitNode(node.constructorSelector);
+ _visitNode(node.argumentList);
+ }
+
+ @override
void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
_visitNodeList(node.metadata, separator: ' ', suffix: ' ');
_visitNode(node.name);
+ _visitNode(node.arguments);
}
@override
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index 4db6958..1aca07f 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -350,6 +350,13 @@
}
@override
+ bool visitConstructorSelector(ConstructorSelector node) {
+ var other = _other as ConstructorSelector;
+ return isEqualTokens(node.period, other.period) &&
+ isEqualNodes(node.name, other.name);
+ }
+
+ @override
bool visitContinueStatement(ContinueStatement node) {
ContinueStatement other = _other as ContinueStatement;
return isEqualTokens(node.continueKeyword, other.continueKeyword) &&
@@ -415,6 +422,14 @@
}
@override
+ bool visitEnumConstantArguments(EnumConstantArguments node) {
+ var other = _other as EnumConstantArguments;
+ return isEqualNodes(node.typeArguments, other.typeArguments) &&
+ isEqualNodes(node.constructorSelector, other.constructorSelector) &&
+ isEqualNodes(node.argumentList, other.argumentList);
+ }
+
+ @override
bool visitEnumConstantDeclaration(EnumConstantDeclaration node) {
EnumConstantDeclaration other = _other as EnumConstantDeclaration;
return isEqualNodes(
@@ -1913,6 +1928,11 @@
}
@override
+ bool visitConstructorSelector(ConstructorSelector node) {
+ throw UnimplementedError();
+ }
+
+ @override
bool visitContinueStatement(covariant ContinueStatementImpl node) {
if (identical(node.label, _oldNode)) {
node.label = _newNode as SimpleIdentifier;
@@ -1981,6 +2001,11 @@
bool visitEmptyStatement(EmptyStatement node) => visitNode(node);
@override
+ bool visitEnumConstantArguments(EnumConstantArguments node) {
+ throw UnimplementedError();
+ }
+
+ @override
bool visitEnumConstantDeclaration(
covariant EnumConstantDeclarationImpl node) {
if (identical(node.name, _oldNode)) {
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 576a41f..db03646 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -64,6 +64,9 @@
ClassDeclarationImpl,
CompilationUnitImpl,
ConstructorNameImpl,
+ EnumConstantArgumentsImpl,
+ ConstructorSelectorImpl,
+ EnumConstantDeclarationImpl,
EnumDeclarationImpl,
ExtensionDeclarationImpl,
ImportDirectiveImpl,
@@ -2809,17 +2812,17 @@
@override
void handleEnumElement(Token beginToken) {
debugEvent("EnumElement");
- var arguments = pop() as MethodInvocationImpl?;
- var constructorName = pop() as ConstructorNameImpl?;
+ var tmpArguments = pop() as MethodInvocationImpl?;
+ var tmpConstructor = pop() as ConstructorNameImpl?;
if (!enableEnhancedEnums &&
- (arguments != null ||
- constructorName != null &&
- (constructorName.type2.typeArguments != null ||
- constructorName.name != null))) {
- Token token = arguments != null
- ? arguments.argumentList.beginToken
- : constructorName!.beginToken;
+ (tmpArguments != null ||
+ tmpConstructor != null &&
+ (tmpConstructor.type2.typeArguments != null ||
+ tmpConstructor.name != null))) {
+ Token token = tmpArguments != null
+ ? tmpArguments.argumentList.beginToken
+ : tmpConstructor!.beginToken;
var feature = ExperimentalFeatures.enhanced_enums;
handleRecoverableError(
templateExperimentNotEnabled.withArguments(
@@ -2830,6 +2833,37 @@
token,
);
}
+
+ var constant = pop() as EnumConstantDeclarationImpl;
+
+ // Replace the constant to include arguments.
+ if (tmpArguments != null) {
+ TypeArgumentListImpl? typeArguments;
+ ConstructorSelectorImpl? constructorName;
+ if (tmpConstructor != null) {
+ typeArguments = tmpConstructor.type2.typeArguments;
+ var constructorNamePeriod = tmpConstructor.period;
+ var constructorNameId = tmpConstructor.name;
+ if (constructorNamePeriod != null && constructorNameId != null) {
+ constructorName = ConstructorSelectorImpl(
+ period: constructorNamePeriod,
+ name: constructorNameId,
+ );
+ }
+ }
+ constant = EnumConstantDeclarationImpl(
+ documentationComment: constant.documentationComment,
+ metadata: constant.metadata,
+ name: constant.name,
+ arguments: EnumConstantArgumentsImpl(
+ typeArguments: typeArguments,
+ constructorSelector: constructorName,
+ argumentList: tmpArguments.argumentList,
+ ),
+ );
+ }
+
+ push(constant);
}
@override
diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
index 082ba9d..eac40aa 100644
--- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
@@ -810,6 +810,30 @@
_assertSource(";", AstTestFactory.emptyStatement());
}
+ void test_visitEnumDeclaration_constant_arguments_named() {
+ var findNode = _parseStringToFindNode(r'''
+enum E {
+ v<double>.named(42)
+}
+''');
+ _assertSource(
+ 'enum E {v<double>.named(42)}',
+ findNode.enumDeclaration('enum E'),
+ );
+ }
+
+ void test_visitEnumDeclaration_constant_arguments_unnamed() {
+ var findNode = _parseStringToFindNode(r'''
+enum E {
+ v<double>(42)
+}
+''');
+ _assertSource(
+ 'enum E {v<double>(42)}',
+ findNode.enumDeclaration('enum E'),
+ );
+ }
+
void test_visitEnumDeclaration_constants_multiple() {
var findNode = _parseStringToFindNode(r'''
enum E {one, two}