mirror of
https://github.com/dart-lang/sdk
synced 2024-10-07 10:14:53 +00:00
Extend AST for enhanced enums.
Change-Id: Ief64e4ba23311543702e7aa1b855e1a3519172a0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/222120 Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
24e681927a
commit
abd1dc8465
|
@ -1577,7 +1577,9 @@ abstract class EnumConstantDeclaration implements Declaration {
|
|||
/// The declaration of an enumeration.
|
||||
///
|
||||
/// enumType ::=
|
||||
/// metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
|
||||
/// metadata 'enum' [SimpleIdentifier] [TypeParameterList]?
|
||||
/// [WithClause]? [ImplementsClause]? '{' [SimpleIdentifier]
|
||||
/// (',' [SimpleIdentifier])* (';' [ClassMember]+)? '}'
|
||||
///
|
||||
/// Clients may not extend, implement or mix-in this class.
|
||||
abstract class EnumDeclaration implements NamedCompilationUnitMember {
|
||||
|
@ -1590,6 +1592,10 @@ abstract class EnumDeclaration implements NamedCompilationUnitMember {
|
|||
/// Return the 'enum' keyword.
|
||||
Token get enumKeyword;
|
||||
|
||||
/// Returns the `implements` clause for the enumeration, or `null` if the
|
||||
/// enumeration does not implement any interfaces.
|
||||
ImplementsClause? get implementsClause;
|
||||
|
||||
/// Return the left curly bracket.
|
||||
Token get leftBracket;
|
||||
|
||||
|
@ -1601,6 +1607,14 @@ abstract class EnumDeclaration implements NamedCompilationUnitMember {
|
|||
|
||||
/// Return the right curly bracket.
|
||||
Token get rightBracket;
|
||||
|
||||
/// Returns the type parameters for the enumeration, or `null` if the
|
||||
/// enumeration does not have any type parameters.
|
||||
TypeParameterList? get typeParameters;
|
||||
|
||||
/// Return the `with` clause for the enumeration, or `null` if the
|
||||
/// enumeration does not have a `with` clause.
|
||||
WithClause? get withClause;
|
||||
}
|
||||
|
||||
/// An export directive.
|
||||
|
|
|
@ -301,6 +301,7 @@ abstract class AstFactory {
|
|||
/// [comment] and [metadata] can be `null` if the declaration does not have
|
||||
/// the corresponding attribute. The list of [constants] must contain at least
|
||||
/// one value.
|
||||
@Deprecated('Use enumDeclaration2() instead')
|
||||
EnumDeclaration enumDeclaration(
|
||||
Comment? comment,
|
||||
List<Annotation>? metadata,
|
||||
|
@ -308,9 +309,26 @@ abstract class AstFactory {
|
|||
SimpleIdentifier name,
|
||||
Token leftBracket,
|
||||
List<EnumConstantDeclaration> constants,
|
||||
List<ClassMember> members,
|
||||
Token rightBracket);
|
||||
|
||||
/// Returns a newly created enumeration declaration. Either or both of the
|
||||
/// [comment] and [metadata] can be `null` if the declaration does not have
|
||||
/// the corresponding attribute. The list of [constants] must contain at least
|
||||
/// one value.
|
||||
EnumDeclaration enumDeclaration2({
|
||||
required Comment? comment,
|
||||
required List<Annotation>? metadata,
|
||||
required Token enumKeyword,
|
||||
required SimpleIdentifier name,
|
||||
required TypeParameterList? typeParameters,
|
||||
required WithClause? withClause,
|
||||
required ImplementsClause? implementsClause,
|
||||
required Token leftBracket,
|
||||
required List<EnumConstantDeclaration> constants,
|
||||
required List<ClassMember> members,
|
||||
required Token rightBracket,
|
||||
});
|
||||
|
||||
/// Returns a newly created export directive. Either or both of the
|
||||
/// [comment] and [metadata] can be `null` if the directive does not have the
|
||||
/// corresponding attribute. The list of [combinators] can be `null` if there
|
||||
|
|
|
@ -3286,14 +3286,27 @@ class EnumConstantDeclarationImpl extends DeclarationImpl
|
|||
/// The declaration of an enumeration.
|
||||
///
|
||||
/// enumType ::=
|
||||
/// metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier]
|
||||
/// (',' [SimpleIdentifier])* (',')? '}'
|
||||
/// metadata 'enum' [SimpleIdentifier] [TypeParameterList]?
|
||||
/// [WithClause]? [ImplementsClause]? '{' [SimpleIdentifier]
|
||||
/// (',' [SimpleIdentifier])* (';' [ClassMember]+)? '}'
|
||||
class EnumDeclarationImpl extends NamedCompilationUnitMemberImpl
|
||||
implements EnumDeclaration {
|
||||
/// The 'enum' keyword.
|
||||
@override
|
||||
Token enumKeyword;
|
||||
|
||||
/// The type parameters, or `null` if the enumeration does not have any
|
||||
/// type parameters.
|
||||
TypeParameterListImpl? _typeParameters;
|
||||
|
||||
/// The `with` clause for the enumeration, or `null` if the class does not
|
||||
/// have a `with` clause.
|
||||
WithClauseImpl? _withClause;
|
||||
|
||||
/// The `implements` clause for the enumeration, or `null` if the enumeration
|
||||
/// does not implement any interfaces.
|
||||
ImplementsClauseImpl? _implementsClause;
|
||||
|
||||
/// The left curly bracket.
|
||||
@override
|
||||
Token leftBracket;
|
||||
|
@ -3317,11 +3330,17 @@ class EnumDeclarationImpl extends NamedCompilationUnitMemberImpl
|
|||
List<Annotation>? metadata,
|
||||
this.enumKeyword,
|
||||
SimpleIdentifierImpl name,
|
||||
this._typeParameters,
|
||||
this._withClause,
|
||||
this._implementsClause,
|
||||
this.leftBracket,
|
||||
List<EnumConstantDeclaration> constants,
|
||||
List<ClassMember> members,
|
||||
this.rightBracket)
|
||||
: super(comment, metadata, name) {
|
||||
_becomeParentOf(_typeParameters);
|
||||
_becomeParentOf(_withClause);
|
||||
_becomeParentOf(_implementsClause);
|
||||
_constants._initialize(this, constants);
|
||||
_members._initialize(this, members);
|
||||
}
|
||||
|
@ -3331,6 +3350,9 @@ class EnumDeclarationImpl extends NamedCompilationUnitMemberImpl
|
|||
Iterable<SyntacticEntity> get childEntities => super._childEntities
|
||||
..add(enumKeyword)
|
||||
..add(_name)
|
||||
..add(_typeParameters)
|
||||
..add(_withClause)
|
||||
..add(_implementsClause)
|
||||
..add(leftBracket)
|
||||
..addAll(_constants)
|
||||
..addAll(_members)
|
||||
|
@ -3348,9 +3370,31 @@ class EnumDeclarationImpl extends NamedCompilationUnitMemberImpl
|
|||
@override
|
||||
Token get firstTokenAfterCommentAndMetadata => enumKeyword;
|
||||
|
||||
@override
|
||||
ImplementsClauseImpl? get implementsClause => _implementsClause;
|
||||
|
||||
set implementsClause(ImplementsClause? implementsClause) {
|
||||
_implementsClause =
|
||||
_becomeParentOf(implementsClause as ImplementsClauseImpl?);
|
||||
}
|
||||
|
||||
@override
|
||||
NodeListImpl<ClassMember> get members => _members;
|
||||
|
||||
@override
|
||||
TypeParameterListImpl? get typeParameters => _typeParameters;
|
||||
|
||||
set typeParameters(TypeParameterList? typeParameters) {
|
||||
_typeParameters = _becomeParentOf(typeParameters as TypeParameterListImpl?);
|
||||
}
|
||||
|
||||
@override
|
||||
WithClauseImpl? get withClause => _withClause;
|
||||
|
||||
set withClause(WithClause? withClause) {
|
||||
_withClause = _becomeParentOf(withClause as WithClauseImpl?);
|
||||
}
|
||||
|
||||
@override
|
||||
E? accept<E>(AstVisitor<E> visitor) => visitor.visitEnumDeclaration(this);
|
||||
|
||||
|
@ -3358,6 +3402,9 @@ class EnumDeclarationImpl extends NamedCompilationUnitMemberImpl
|
|||
void visitChildren(AstVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
_name.accept(visitor);
|
||||
_typeParameters?.accept(visitor);
|
||||
_withClause?.accept(visitor);
|
||||
_implementsClause?.accept(visitor);
|
||||
_constants.accept(visitor);
|
||||
_members.accept(visitor);
|
||||
}
|
||||
|
|
|
@ -383,6 +383,7 @@ class AstFactoryImpl extends AstFactory {
|
|||
EnumConstantDeclarationImpl(
|
||||
comment as CommentImpl?, metadata, name as SimpleIdentifierImpl);
|
||||
|
||||
@Deprecated('Use enumDeclaration2() instead')
|
||||
@override
|
||||
EnumDeclarationImpl enumDeclaration(
|
||||
Comment? comment,
|
||||
|
@ -391,17 +392,48 @@ class AstFactoryImpl extends AstFactory {
|
|||
SimpleIdentifier name,
|
||||
Token leftBracket,
|
||||
List<EnumConstantDeclaration> constants,
|
||||
List<ClassMember> members,
|
||||
Token rightBracket) =>
|
||||
EnumDeclarationImpl(
|
||||
comment as CommentImpl?,
|
||||
metadata,
|
||||
enumKeyword,
|
||||
name as SimpleIdentifierImpl,
|
||||
leftBracket,
|
||||
constants,
|
||||
members,
|
||||
rightBracket);
|
||||
enumDeclaration2(
|
||||
comment: comment,
|
||||
metadata: metadata,
|
||||
enumKeyword: enumKeyword,
|
||||
name: name,
|
||||
typeParameters: null,
|
||||
withClause: null,
|
||||
implementsClause: null,
|
||||
leftBracket: leftBracket,
|
||||
constants: constants,
|
||||
members: [],
|
||||
rightBracket: rightBracket);
|
||||
|
||||
@override
|
||||
EnumDeclarationImpl enumDeclaration2({
|
||||
required Comment? comment,
|
||||
required List<Annotation>? metadata,
|
||||
required Token enumKeyword,
|
||||
required SimpleIdentifier name,
|
||||
required TypeParameterList? typeParameters,
|
||||
required WithClause? withClause,
|
||||
required ImplementsClause? implementsClause,
|
||||
required Token leftBracket,
|
||||
required List<EnumConstantDeclaration> constants,
|
||||
required List<ClassMember> members,
|
||||
required Token rightBracket,
|
||||
}) {
|
||||
return EnumDeclarationImpl(
|
||||
comment as CommentImpl?,
|
||||
metadata,
|
||||
enumKeyword,
|
||||
name as SimpleIdentifierImpl,
|
||||
typeParameters as TypeParameterListImpl?,
|
||||
withClause as WithClauseImpl?,
|
||||
implementsClause as ImplementsClauseImpl?,
|
||||
leftBracket,
|
||||
constants,
|
||||
members,
|
||||
rightBracket,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ExportDirectiveImpl exportDirective(
|
||||
|
|
|
@ -314,8 +314,12 @@ class ToSourceVisitor implements AstVisitor<void> {
|
|||
_visitNodeList(node.metadata, separator: ' ', suffix: ' ');
|
||||
sink.write('enum ');
|
||||
_visitNode(node.name);
|
||||
_visitNode(node.typeParameters);
|
||||
_visitNode(node.withClause, prefix: ' ');
|
||||
_visitNode(node.implementsClause, prefix: ' ');
|
||||
sink.write(' {');
|
||||
_visitNodeList(node.constants, separator: ', ');
|
||||
_visitNodeList(node.members, prefix: '; ', separator: ' ');
|
||||
sink.write('}');
|
||||
}
|
||||
|
||||
|
|
|
@ -2002,8 +2002,19 @@ class NodeReplacer implements AstVisitor<bool> {
|
|||
if (identical(node.name, _oldNode)) {
|
||||
node.name = _newNode as SimpleIdentifier;
|
||||
return true;
|
||||
} else if (identical(node.typeParameters, _oldNode)) {
|
||||
node.typeParameters = _newNode as TypeParameterList;
|
||||
return true;
|
||||
} else if (identical(node.withClause, _oldNode)) {
|
||||
node.withClause = _newNode as WithClause;
|
||||
return true;
|
||||
} else if (identical(node.implementsClause, _oldNode)) {
|
||||
node.implementsClause = _newNode as ImplementsClause;
|
||||
return true;
|
||||
} else if (_replaceInList(node.constants)) {
|
||||
return true;
|
||||
} else if (_replaceInList(node.members)) {
|
||||
return true;
|
||||
}
|
||||
return visitAnnotatedNode(node);
|
||||
}
|
||||
|
|
|
@ -2813,8 +2813,21 @@ class AstBuilder extends StackListener {
|
|||
);
|
||||
}
|
||||
|
||||
declarations.add(enumDeclaration = ast.enumDeclaration(comment, metadata,
|
||||
enumKeyword, name, leftBrace, [], [], leftBrace.endGroup!));
|
||||
declarations.add(
|
||||
enumDeclaration = ast.enumDeclaration2(
|
||||
comment: comment,
|
||||
metadata: metadata,
|
||||
enumKeyword: enumKeyword,
|
||||
name: name,
|
||||
typeParameters: typeParameters,
|
||||
withClause: withClause,
|
||||
implementsClause: implementsClause,
|
||||
leftBracket: leftBrace,
|
||||
constants: [],
|
||||
members: [],
|
||||
rightBracket: leftBrace.endGroup!,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -458,30 +458,6 @@ class AstTestFactory {
|
|||
static EmptyStatementImpl emptyStatement() => astFactory
|
||||
.emptyStatement(TokenFactory.tokenFromType(TokenType.SEMICOLON));
|
||||
|
||||
static EnumDeclarationImpl enumDeclaration(
|
||||
SimpleIdentifier name, List<EnumConstantDeclaration> constants) =>
|
||||
astFactory.enumDeclaration(
|
||||
null,
|
||||
null,
|
||||
TokenFactory.tokenFromKeyword(Keyword.ENUM),
|
||||
name,
|
||||
TokenFactory.tokenFromType(TokenType.OPEN_CURLY_BRACKET),
|
||||
constants,
|
||||
[],
|
||||
TokenFactory.tokenFromType(TokenType.CLOSE_CURLY_BRACKET));
|
||||
|
||||
static EnumDeclarationImpl enumDeclaration2(
|
||||
String name, List<String> constantNames) {
|
||||
var constants = constantNames.map((name) {
|
||||
return astFactory.enumConstantDeclaration(
|
||||
null,
|
||||
null,
|
||||
identifier3(name),
|
||||
);
|
||||
}).toList();
|
||||
return enumDeclaration(identifier3(name), constants);
|
||||
}
|
||||
|
||||
static ExportDirectiveImpl exportDirective(
|
||||
List<Annotation> metadata, String uri,
|
||||
[List<Combinator> combinators = const []]) =>
|
||||
|
|
|
@ -123,6 +123,10 @@ class FindNode {
|
|||
return _node(search, (n) => n is DoubleLiteral);
|
||||
}
|
||||
|
||||
EnumConstantDeclaration enumConstantDeclaration(String search) {
|
||||
return _node(search, (n) => n is EnumConstantDeclaration);
|
||||
}
|
||||
|
||||
EnumDeclaration enumDeclaration(String search) {
|
||||
return _node(search, (n) => n is EnumDeclaration);
|
||||
}
|
||||
|
|
|
@ -1649,12 +1649,44 @@ void f() {
|
|||
}
|
||||
|
||||
void test_enumDeclaration() {
|
||||
var node = AstTestFactory.enumDeclaration2("E", ["ONE", "TWO"]);
|
||||
node.documentationComment = astFactory.endOfLineComment(EMPTY_TOKEN_LIST);
|
||||
node.metadata
|
||||
.add(AstTestFactory.annotation(AstTestFactory.identifier3("a")));
|
||||
_assertReplace(node, Getter_NodeReplacerTest_test_enumDeclaration());
|
||||
_testAnnotatedNode(node);
|
||||
var findNode = _parseStringToFindNode(r'''
|
||||
enum E1<T> with M1 implements I1 {one, two}
|
||||
enum E2<U> with M2 implements I2 {one, two}
|
||||
''');
|
||||
_assertReplace2<EnumDeclaration>(
|
||||
destination: findNode.enumDeclaration('enum E1'),
|
||||
source: findNode.enumDeclaration('enum E2'),
|
||||
getters: [
|
||||
(node) => node.name,
|
||||
(node) => node.typeParameters!,
|
||||
(node) => node.withClause!,
|
||||
(node) => node.implementsClause!,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void test_enumDeclaration_constants() {
|
||||
var findNode = _parseStringToFindNode(r'''
|
||||
enum E1 {one}
|
||||
enum E2 {two}
|
||||
''');
|
||||
_assertReplaceInList(
|
||||
destination: findNode.enumDeclaration('enum E1'),
|
||||
child: findNode.enumConstantDeclaration('one'),
|
||||
replacement: findNode.enumConstantDeclaration('two'),
|
||||
);
|
||||
}
|
||||
|
||||
void test_enumDeclaration_members() {
|
||||
var findNode = _parseStringToFindNode(r'''
|
||||
enum E1 {one; void foo() {}}
|
||||
enum E2 {two; void bar() {}}
|
||||
''');
|
||||
_assertReplaceInList(
|
||||
destination: findNode.enumDeclaration('enum E1'),
|
||||
child: findNode.methodDeclaration('foo'),
|
||||
replacement: findNode.methodDeclaration('bar'),
|
||||
);
|
||||
}
|
||||
|
||||
void test_exportDirective() {
|
||||
|
@ -2303,12 +2335,24 @@ class B extends A {
|
|||
}
|
||||
}
|
||||
|
||||
void _assertReplaceInList({
|
||||
required AstNode destination,
|
||||
required AstNode child,
|
||||
required AstNode replacement,
|
||||
}) {
|
||||
expect(child.parent, destination);
|
||||
|
||||
NodeReplacer.replace(child, replacement);
|
||||
expect(replacement.parent, destination);
|
||||
}
|
||||
|
||||
FindNode _parseStringToFindNode(String content) {
|
||||
var parseResult = parseString(
|
||||
content: content,
|
||||
featureSet: FeatureSet.fromEnableFlags2(
|
||||
sdkLanguageVersion: ExperimentStatus.currentVersion,
|
||||
flags: [
|
||||
Feature.enhanced_enums.enableString,
|
||||
Feature.super_parameters.enableString,
|
||||
],
|
||||
),
|
||||
|
|
|
@ -2,14 +2,17 @@
|
|||
// 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/dart/analysis/features.dart';
|
||||
import 'package:analyzer/dart/analysis/utilities.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/token.dart';
|
||||
import 'package:analyzer/src/dart/analysis/experiments.dart';
|
||||
import 'package:analyzer/src/dart/ast/ast_factory.dart';
|
||||
import 'package:analyzer/src/dart/ast/to_source_visitor.dart';
|
||||
import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
|
||||
import 'package:analyzer/src/generated/testing/token_factory.dart';
|
||||
import 'package:analyzer/src/summary2/ast_binary_tokens.dart';
|
||||
import 'package:analyzer/src/test_utilities/find_node.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
|
@ -765,14 +768,62 @@ class ToSourceVisitor2Test {
|
|||
_assertSource(";", AstTestFactory.emptyStatement());
|
||||
}
|
||||
|
||||
void test_visitEnumDeclaration_multiple() {
|
||||
_assertSource("enum E {ONE, TWO}",
|
||||
AstTestFactory.enumDeclaration2("E", ["ONE", "TWO"]));
|
||||
void test_visitEnumDeclaration_constants_multiple() {
|
||||
var findNode = _parseStringToFindNode(r'''
|
||||
enum E {one, two}
|
||||
''');
|
||||
_assertSource(
|
||||
'enum E {one, two}',
|
||||
findNode.enumDeclaration('E'),
|
||||
);
|
||||
}
|
||||
|
||||
void test_visitEnumDeclaration_single() {
|
||||
void test_visitEnumDeclaration_constants_single() {
|
||||
var findNode = _parseStringToFindNode(r'''
|
||||
enum E {one}
|
||||
''');
|
||||
_assertSource(
|
||||
"enum E {ONE}", AstTestFactory.enumDeclaration2("E", ["ONE"]));
|
||||
'enum E {one}',
|
||||
findNode.enumDeclaration('E'),
|
||||
);
|
||||
}
|
||||
|
||||
void test_visitEnumDeclaration_field_constructor() {
|
||||
var findNode = _parseStringToFindNode(r'''
|
||||
enum E {
|
||||
one, two;
|
||||
final int field;
|
||||
E(this.field);
|
||||
}
|
||||
''');
|
||||
_assertSource(
|
||||
'enum E {one, two; final int field; E(this.field);}',
|
||||
findNode.enumDeclaration('enum E'),
|
||||
);
|
||||
}
|
||||
|
||||
void test_visitEnumDeclaration_method() {
|
||||
var findNode = _parseStringToFindNode(r'''
|
||||
enum E {
|
||||
one, two;
|
||||
void myMethod() {}
|
||||
int get myGetter => 0;
|
||||
}
|
||||
''');
|
||||
_assertSource(
|
||||
'enum E {one, two; void myMethod() {} int get myGetter => 0;}',
|
||||
findNode.enumDeclaration('enum E'),
|
||||
);
|
||||
}
|
||||
|
||||
void test_visitEnumDeclaration_withoutMembers() {
|
||||
var findNode = _parseStringToFindNode(r'''
|
||||
enum E<T> with M1, M2 implements I1, I2 {one, two}
|
||||
''');
|
||||
_assertSource(
|
||||
'enum E<T> with M1, M2 implements I1, I2 {one, two}',
|
||||
findNode.enumDeclaration('E'),
|
||||
);
|
||||
}
|
||||
|
||||
void test_visitExportDirective_combinator() {
|
||||
|
@ -3356,4 +3407,18 @@ import 'foo.dart'
|
|||
node.accept(ToSourceVisitor(buffer));
|
||||
expect(buffer.toString(), expectedSource);
|
||||
}
|
||||
|
||||
FindNode _parseStringToFindNode(String content) {
|
||||
var parseResult = parseString(
|
||||
content: content,
|
||||
featureSet: FeatureSet.fromEnableFlags2(
|
||||
sdkLanguageVersion: ExperimentStatus.currentVersion,
|
||||
flags: [
|
||||
Feature.enhanced_enums.enableString,
|
||||
Feature.super_parameters.enableString,
|
||||
],
|
||||
),
|
||||
);
|
||||
return FindNode(parseResult.content, parseResult.unit);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue