blob: 35fd43a9f87fda156c65ee1d20fbab4529282c35 [file] [log] [blame]
// Copyright (c) 2014, 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 'dart:collection';
import 'dart:math' as math;
import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
as shared;
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/doc_comment.dart';
import 'package:analyzer/dart/ast/precedence.dart';
import 'package:analyzer/dart/ast/syntactic_entity.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/scope.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/ast/to_source_visitor.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/resolver/typed_literal_resolver.dart';
import 'package:analyzer/src/fasta/token_utils.dart' as util show findPrevious;
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
/// Two or more string literals that are implicitly concatenated because of
/// being adjacent (separated only by whitespace).
///
/// While the grammar only allows adjacent strings when all of the strings are
/// of the same kind (single line or multi-line), this class doesn't enforce
/// that restriction.
///
/// adjacentStrings ::=
/// [StringLiteral] [StringLiteral]+
abstract final class AdjacentStrings implements StringLiteral {
/// Return the strings that are implicitly concatenated.
NodeList<StringLiteral> get strings;
}
/// Two or more string literals that are implicitly concatenated because of
/// being adjacent (separated only by whitespace).
///
/// While the grammar only allows adjacent strings when all of the strings are
/// of the same kind (single line or multi-line), this class doesn't enforce
/// that restriction.
///
/// adjacentStrings ::=
/// [StringLiteral] [StringLiteral]+
final class AdjacentStringsImpl extends StringLiteralImpl
implements AdjacentStrings {
/// The strings that are implicitly concatenated.
final NodeListImpl<StringLiteralImpl> _strings = NodeListImpl._();
/// Initialize a newly created list of adjacent strings. To be syntactically
/// valid, the list of [strings] must contain at least two elements.
AdjacentStringsImpl({
required List<StringLiteralImpl> strings,
}) {
_strings._initialize(this, strings);
}
@override
Token get beginToken => _strings.beginToken!;
@override
Token get endToken => _strings.endToken!;
@override
NodeListImpl<StringLiteralImpl> get strings => _strings;
@override
ChildEntities get _childEntities {
return ChildEntities()..addNodeList('strings', strings);
}
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitAdjacentStrings(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitAdjacentStrings(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_strings.accept(visitor);
}
@override
void _appendStringValue(StringBuffer buffer) {
int length = strings.length;
for (int i = 0; i < length; i++) {
strings[i]._appendStringValue(buffer);
}
}
}
/// An AST node that can be annotated with both a documentation comment and a
/// list of annotations.
abstract final class AnnotatedNode implements AstNode {
/// Return the documentation comment associated with this node, or `null` if
/// this node does not have a documentation comment associated with it.
Comment? get documentationComment;
/// Return the first token following the comment and metadata.
Token get firstTokenAfterCommentAndMetadata;
/// Return the annotations associated with this node.
NodeList<Annotation> get metadata;
/// Return a list containing the comment and annotations associated with this
/// node, sorted in lexical order.
List<AstNode> get sortedCommentAndAnnotations;
}
/// An AST node that can be annotated with both a documentation comment and a
/// list of annotations.
sealed class AnnotatedNodeImpl extends AstNodeImpl implements AnnotatedNode {
/// The documentation comment associated with this node, or `null` if this
/// node does not have a documentation comment associated with it.
CommentImpl? _comment;
/// The annotations associated with this node.
final NodeListImpl<AnnotationImpl> _metadata = NodeListImpl._();
/// Initialize a newly created annotated node. Either or both of the [comment]
/// and [metadata] can be `null` if the node does not have the corresponding
/// attribute.
AnnotatedNodeImpl({
required CommentImpl? comment,
required List<AnnotationImpl>? metadata,
}) : _comment = comment {
_becomeParentOf(_comment);
_metadata._initialize(this, metadata);
}
@override
Token get beginToken {
if (_comment == null) {
if (_metadata.isEmpty) {
return firstTokenAfterCommentAndMetadata;
}
return _metadata.beginToken!;
} else if (_metadata.isEmpty) {
return _comment!.beginToken;
}
Token commentToken = _comment!.beginToken;
Token metadataToken = _metadata.beginToken!;
if (commentToken.offset < metadataToken.offset) {
return commentToken;
}
return metadataToken;
}
@override
CommentImpl? get documentationComment => _comment;
set documentationComment(CommentImpl? comment) {
_comment = _becomeParentOf(comment);
}
@override
NodeListImpl<AnnotationImpl> get metadata => _metadata;
@override
List<AstNode> get sortedCommentAndAnnotations {
var comment = _comment;
return <AstNode>[
if (comment != null) comment,
..._metadata,
]..sort(AstNode.LEXICAL_ORDER);
}
@override
ChildEntities get _childEntities {
return ChildEntities()
..addNode('documentationComment', documentationComment)
..addNodeList('metadata', metadata);
}
@override
void visitChildren(AstVisitor visitor) {
if (_commentIsBeforeAnnotations()) {
_comment?.accept(visitor);
_metadata.accept(visitor);
} else {
List<AstNode> children = sortedCommentAndAnnotations;
int length = children.length;
for (int i = 0; i < length; i++) {
children[i].accept(visitor);
}
}
}
/// Return `true` if there are no annotations before the comment. Note that a
/// result of `true` does not imply that there is a comment, nor that there
/// are annotations associated with this node.
bool _commentIsBeforeAnnotations() {
if (_comment == null || _metadata.isEmpty) {
return true;
}
Annotation firstAnnotation = _metadata[0];
return _comment!.offset < firstAnnotation.offset;
}
}
/// An annotation that can be associated with an AST node.
///
/// metadata ::=
/// annotation*
///
/// annotation ::=
/// '@' metadatum
///
/// metadatum ::=
/// [Identifier]
/// | qualifiedName
/// | constructorDesignation argumentPart
abstract final class Annotation implements AstNode {
/// Return the arguments to the constructor being invoked, or `null` if this
/// annotation is not the invocation of a constructor.
ArgumentList? get arguments;
/// Return the at sign that introduced the annotation.
Token get atSign;
/// Return the name of the constructor being invoked, or `null` if this
/// annotation is not the invocation of a named constructor.
SimpleIdentifier? get constructorName;
/// Return the element associated with this annotation, or `null` if the AST
/// structure has not been resolved or if this annotation could not be
/// resolved.
Element? get element;
/// Return the element annotation representing this annotation in the element
/// model; `null` when the AST has not been resolved.
ElementAnnotation? get elementAnnotation;
/// Return the name of the class defining the constructor that is being
/// invoked or the name of the field that is being referenced.
Identifier get name;
@override
AstNode get parent;
/// Return the period before the constructor name, or `null` if this
/// annotation is not the invocation of a named constructor.
Token? get period;
/// Returns the type arguments to the constructor being invoked, or `null` if
/// (a) this annotation is not the invocation of a constructor or (b) this
/// annotation does not specify type arguments explicitly.
///
/// Note that type arguments are only valid if [Feature.generic_metadata] is
/// enabled.
TypeArgumentList? get typeArguments;
}
/// An annotation that can be associated with an AST node.
///
/// metadata ::=
/// annotation*
///
/// annotation ::=
/// '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
final class AnnotationImpl extends AstNodeImpl implements Annotation {
/// The at sign that introduced the annotation.
@override
final Token atSign;
/// The name of the class defining the constructor that is being invoked or
/// the name of the field that is being referenced.
IdentifierImpl _name;
/// The type arguments to the constructor being invoked, or `null` if (a) this
/// annotation is not the invocation of a constructor or (b) this annotation
/// does not specify type arguments explicitly.
///
/// Note that type arguments are only valid if [Feature.generic_metadata] is
/// enabled.
TypeArgumentListImpl? _typeArguments;
/// The period before the constructor name, or `null` if this annotation is
/// not the invocation of a named constructor.
@override
final Token? period;
/// The name of the constructor being invoked, or `null` if this annotation is
/// not the invocation of a named constructor.
SimpleIdentifierImpl? _constructorName;
/// The arguments to the constructor being invoked, or `null` if this
/// annotation is not the invocation of a constructor.
ArgumentListImpl? _arguments;
/// The element associated with this annotation, or `null` if the AST
/// structure has not been resolved or if this annotation could not be
/// resolved.
Element? _element;
/// The element annotation representing this annotation in the element model.
@override
ElementAnnotation? elementAnnotation;
/// Initialize a newly created annotation. Both the [period] and the
/// [constructorName] can be `null` if the annotation is not referencing a
/// named constructor. The [arguments] can be `null` if the annotation is not
/// referencing a constructor.
///
/// Note that type arguments are only valid if [Feature.generic_metadata] is
/// enabled.
AnnotationImpl({
required this.atSign,
required IdentifierImpl name,
required TypeArgumentListImpl? typeArguments,
required this.period,
required SimpleIdentifierImpl? constructorName,
required ArgumentListImpl? arguments,
}) : _name = name,
_typeArguments = typeArguments,
_constructorName = constructorName,
_arguments = arguments {
_becomeParentOf(_name);
_becomeParentOf(_typeArguments);
_becomeParentOf(_constructorName);
_becomeParentOf(_arguments);
}
@override
ArgumentListImpl? get arguments => _arguments;
set arguments(ArgumentListImpl? arguments) {
_arguments = _becomeParentOf(arguments);
}
@override
Token get beginToken => atSign;
@override
SimpleIdentifierImpl? get constructorName => _constructorName;
set constructorName(SimpleIdentifierImpl? name) {
_constructorName = _becomeParentOf(name);
}
@override
Element? get element {
if (_element case final element?) {
return element;
} else if (_constructorName == null) {
return _name.staticElement;
}
return null;
}
set element(Element? element) {
_element = element;
}
@override
Token get endToken {
if (arguments case final arguments?) {
return arguments.endToken;
} else if (constructorName case final constructorName?) {
return constructorName.endToken;
}
return _name.endToken;
}
@override
IdentifierImpl get name => _name;
set name(IdentifierImpl name) {
_name = _becomeParentOf(name)!;
}
@override
AstNode get parent => super.parent!;
@override
TypeArgumentListImpl? get typeArguments => _typeArguments;
/// Sets the type arguments to the constructor being invoked to the given
/// [typeArguments].
set typeArguments(TypeArgumentListImpl? typeArguments) {
_typeArguments = _becomeParentOf(typeArguments);
}
@override
ChildEntities get _childEntities {
return ChildEntities()
..addToken('atSign', atSign)
..addNode('name', name)
..addNode('typeArguments', typeArguments)
..addToken('period', period)
..addNode('constructorName', constructorName)
..addNode('arguments', arguments);
}
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitAnnotation(this);
@override
void visitChildren(AstVisitor visitor) {
_name.accept(visitor);
_typeArguments?.accept(visitor);
_constructorName?.accept(visitor);
_arguments?.accept(visitor);
}
}
/// A list of arguments in the invocation of an executable element (that is, a
/// function, method, or constructor).
///
/// argumentList ::=
/// '(' arguments? ')'
///
/// arguments ::=
/// [NamedExpression] (',' [NamedExpression])*
/// | [Expression] (',' [Expression])* (',' [NamedExpression])*
abstract final class ArgumentList implements AstNode {
/// Return the expressions producing the values of the arguments.
///
/// Although the language requires that positional arguments appear before
/// named arguments, this class allows them to be intermixed.
NodeList<Expression> get arguments;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right parenthesis.
Token get rightParenthesis;
}
/// A list of arguments in the invocation of an executable element (that is, a
/// function, method, or constructor).
///
/// argumentList ::=
/// '(' arguments? ')'
///
/// arguments ::=
/// [NamedExpression] (',' [NamedExpression])*
/// | [Expression] (',' [Expression])* (',' [NamedExpression])*
final class ArgumentListImpl extends AstNodeImpl implements ArgumentList {
/// The left parenthesis.
@override
final Token leftParenthesis;
/// The expressions producing the values of the arguments.
final NodeListImpl<ExpressionImpl> _arguments = NodeListImpl._();
/// The right parenthesis.
@override
final Token rightParenthesis;
/// A list containing the elements representing the parameters corresponding
/// to each of the arguments in this list, or `null` if the AST has not been
/// resolved or if the function or method being invoked could not be
/// determined based on static type information. The list must be the same
/// length as the number of arguments, but can contain `null` entries if a
/// given argument does not correspond to a formal parameter.
List<ParameterElement?>? _correspondingStaticParameters;
/// Initialize a newly created list of arguments. The list of [arguments] can
/// be `null` if there are no arguments.
ArgumentListImpl({
required this.leftParenthesis,
required List<ExpressionImpl> arguments,
required this.rightParenthesis,
}) {
_arguments._initialize(this, arguments);
}
@override
NodeListImpl<ExpressionImpl> get arguments => _arguments;
@override
Token get beginToken => leftParenthesis;
List<ParameterElement?>? get correspondingStaticParameters =>
_correspondingStaticParameters;
set correspondingStaticParameters(List<ParameterElement?>? parameters) {
if (parameters != null && parameters.length != _arguments.length) {
throw ArgumentError(
"Expected ${_arguments.length} parameters, not ${parameters.length}");
}
_correspondingStaticParameters = parameters;
}
@override
Token get endToken => rightParenthesis;
@override
// TODO(paulberry): Add commas.
ChildEntities get _childEntities => ChildEntities()
..addToken('leftParenthesis', leftParenthesis)
..addNodeList('arguments', arguments)
..addToken('rightParenthesis', rightParenthesis);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitArgumentList(this);
@override
void visitChildren(AstVisitor visitor) {
_arguments.accept(visitor);
}
/// If
/// * the given [expression] is a child of this list,
/// * the AST structure has been resolved,
/// * the function being invoked is known based on static type information,
/// and
/// * the expression corresponds to one of the parameters of the function
/// being invoked,
/// then return the parameter element representing the parameter to which the
/// value of the given expression will be bound. Otherwise, return `null`.
ParameterElement? _getStaticParameterElementFor(Expression expression) {
if (_correspondingStaticParameters == null ||
_correspondingStaticParameters!.length != _arguments.length) {
// Either the AST structure has not been resolved, the invocation of which
// this list is a part could not be resolved, or the argument list was
// modified after the parameters were set.
return null;
}
int index = _arguments.indexOf(expression);
if (index < 0) {
// The expression isn't a child of this node.
return null;
}
return _correspondingStaticParameters![index];
}
}
/// An as expression.
///
/// asExpression ::=
/// [Expression] 'as' [TypeAnnotation]
abstract final class AsExpression implements Expression {
/// Return the 'as' operator.
Token get asOperator;
/// Return the expression used to compute the value being cast.
Expression get expression;
/// Return the type being cast to.
TypeAnnotation get type;
}
/// An as expression.
///
/// asExpression ::=
/// [Expression] 'as' [NamedType]
final class AsExpressionImpl extends ExpressionImpl implements AsExpression {
/// The expression used to compute the value being cast.
ExpressionImpl _expression;
/// The 'as' operator.
@override
final Token asOperator;
/// The type being cast to.
TypeAnnotationImpl _type;
/// Initialize a newly created as expression.
AsExpressionImpl({
required ExpressionImpl expression,
required this.asOperator,
required TypeAnnotationImpl type,
}) : _expression = expression,
_type = type {
_becomeParentOf(_expression);
_becomeParentOf(_type);
}
@override
Token get beginToken => _expression.beginToken;
@override
Token get endToken => _type.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
Precedence get precedence => Precedence.relational;
@override
TypeAnnotationImpl get type => _type;
set type(TypeAnnotationImpl type) {
_type = _becomeParentOf(type);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('expression', expression)
..addToken('asOperator', asOperator)
..addNode('type', type);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitAsExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitAsExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
_type.accept(visitor);
}
}
/// An assert in the initializer list of a constructor.
///
/// assertInitializer ::=
/// 'assert' '(' [Expression] (',' [Expression])? ')'
abstract final class AssertInitializer
implements Assertion, ConstructorInitializer {}
/// An assert in the initializer list of a constructor.
///
/// assertInitializer ::=
/// 'assert' '(' [Expression] (',' [Expression])? ')'
final class AssertInitializerImpl extends ConstructorInitializerImpl
implements AssertInitializer {
@override
final Token assertKeyword;
@override
final Token leftParenthesis;
/// The condition that is being asserted to be `true`.
ExpressionImpl _condition;
@override
final Token? comma;
/// The message to report if the assertion fails, or `null` if no message was
/// supplied.
ExpressionImpl? _message;
@override
final Token rightParenthesis;
/// Initialize a newly created assert initializer.
AssertInitializerImpl({
required this.assertKeyword,
required this.leftParenthesis,
required ExpressionImpl condition,
required this.comma,
required ExpressionImpl? message,
required this.rightParenthesis,
}) : _condition = condition,
_message = message {
_becomeParentOf(_condition);
_becomeParentOf(_message);
}
@override
Token get beginToken => assertKeyword;
@override
ExpressionImpl get condition => _condition;
set condition(ExpressionImpl condition) {
_condition = _becomeParentOf(condition);
}
@override
Token get endToken => rightParenthesis;
@override
ExpressionImpl? get message => _message;
set message(ExpressionImpl? expression) {
_message = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('assertKeyword', assertKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('condition', condition)
..addToken('comma', comma)
..addNode('message', message)
..addToken('rightParenthesis', rightParenthesis);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitAssertInitializer(this);
@override
void visitChildren(AstVisitor visitor) {
_condition.accept(visitor);
message?.accept(visitor);
}
}
/// An assertion, either in a block or in the initializer list of a constructor.
abstract final class Assertion implements AstNode {
/// Return the token representing the 'assert' keyword.
Token get assertKeyword;
/// Return the comma between the [condition] and the [message], or `null` if
/// no message was supplied.
Token? get comma;
/// Return the condition that is being asserted to be `true`.
Expression get condition;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the message to report if the assertion fails, or `null` if no
/// message was supplied.
Expression? get message;
/// Return the right parenthesis.
Token get rightParenthesis;
}
/// An assert statement.
///
/// assertStatement ::=
/// 'assert' '(' [Expression] (',' [Expression])? ')' ';'
abstract final class AssertStatement implements Assertion, Statement {
/// Return the semicolon terminating the statement.
Token get semicolon;
}
/// An assert statement.
///
/// assertStatement ::=
/// 'assert' '(' [Expression] ')' ';'
final class AssertStatementImpl extends StatementImpl
implements AssertStatement {
@override
final Token assertKeyword;
@override
final Token leftParenthesis;
/// The condition that is being asserted to be `true`.
ExpressionImpl _condition;
@override
final Token? comma;
/// The message to report if the assertion fails, or `null` if no message was
/// supplied.
ExpressionImpl? _message;
@override
final Token rightParenthesis;
@override
final Token semicolon;
/// Initialize a newly created assert statement.
AssertStatementImpl({
required this.assertKeyword,
required this.leftParenthesis,
required ExpressionImpl condition,
required this.comma,
required ExpressionImpl? message,
required this.rightParenthesis,
required this.semicolon,
}) : _condition = condition,
_message = message {
_becomeParentOf(_condition);
_becomeParentOf(_message);
}
@override
Token get beginToken => assertKeyword;
@override
ExpressionImpl get condition => _condition;
set condition(ExpressionImpl condition) {
_condition = _becomeParentOf(condition);
}
@override
Token get endToken => semicolon;
@override
ExpressionImpl? get message => _message;
set message(ExpressionImpl? expression) {
_message = _becomeParentOf(expression as ExpressionImpl);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('assertKeyword', assertKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('condition', condition)
..addToken('comma', comma)
..addNode('message', message)
..addToken('rightParenthesis', rightParenthesis)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitAssertStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_condition.accept(visitor);
message?.accept(visitor);
}
}
/// A variable pattern in [PatternAssignment].
///
/// variablePattern ::= identifier
abstract final class AssignedVariablePattern implements VariablePattern {
/// Return the element referenced by this pattern, or `null` if either
/// [name] does not resolve to an element, or the AST structure has not
/// been resolved. In valid code this will be either [LocalVariableElement]
/// or [ParameterElement].
Element? get element;
}
/// A variable pattern in [PatternAssignment].
///
/// variablePattern ::= identifier
final class AssignedVariablePatternImpl extends VariablePatternImpl
implements AssignedVariablePattern {
@override
Element? element;
AssignedVariablePatternImpl({
required super.name,
});
@override
Token get beginToken => name;
@override
Token get endToken => name;
@override
PatternPrecedence get precedence => PatternPrecedence.primary;
@override
ChildEntities get _childEntities => ChildEntities()..addToken('name', name);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitAssignedVariablePattern(this);
}
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
final element = this.element;
if (element is PromotableElement) {
return resolverVisitor.analyzeAssignedVariablePatternSchema(element);
}
return resolverVisitor.operations.unknownType;
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
resolverVisitor.resolveAssignedVariablePattern(
node: this,
context: context,
);
}
@override
void visitChildren(AstVisitor visitor) {}
}
/// An assignment expression.
///
/// assignmentExpression ::=
/// [Expression] operator [Expression]
abstract final class AssignmentExpression
implements
NullShortableExpression,
MethodReferenceExpression,
CompoundAssignmentExpression {
/// Return the expression used to compute the left hand side.
Expression get leftHandSide;
/// Return the assignment operator being applied.
Token get operator;
/// Return the expression used to compute the right hand side.
Expression get rightHandSide;
}
/// An assignment expression.
///
/// assignmentExpression ::=
/// [Expression] operator [Expression]
final class AssignmentExpressionImpl extends ExpressionImpl
with NullShortableExpressionImpl, CompoundAssignmentExpressionImpl
implements AssignmentExpression {
/// The expression used to compute the left hand side.
ExpressionImpl _leftHandSide;
/// The assignment operator being applied.
@override
final Token operator;
/// The expression used to compute the right hand side.
ExpressionImpl _rightHandSide;
/// The element associated with the operator based on the static type of the
/// left-hand-side, or `null` if the AST structure has not been resolved, if
/// the operator is not a compound operator, or if the operator could not be
/// resolved.
@override
MethodElement? staticElement;
/// Initialize a newly created assignment expression.
AssignmentExpressionImpl({
required ExpressionImpl leftHandSide,
required this.operator,
required ExpressionImpl rightHandSide,
}) : _leftHandSide = leftHandSide,
_rightHandSide = rightHandSide {
_becomeParentOf(_leftHandSide);
_becomeParentOf(_rightHandSide);
}
@override
Token get beginToken => _leftHandSide.beginToken;
@override
Token get endToken => _rightHandSide.endToken;
@override
ExpressionImpl get leftHandSide => _leftHandSide;
set leftHandSide(ExpressionImpl expression) {
_leftHandSide = _becomeParentOf(expression);
}
@override
Precedence get precedence => Precedence.assignment;
@override
ExpressionImpl get rightHandSide => _rightHandSide;
set rightHandSide(ExpressionImpl expression) {
_rightHandSide = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('leftHandSide', leftHandSide)
..addToken('operator', operator)
..addNode('rightHandSide', rightHandSide);
@override
AstNode? get _nullShortingExtensionCandidate => parent;
/// If the AST structure has been resolved, and the function being invoked is
/// known based on static type information, then return the parameter element
/// representing the parameter to which the value of the right operand will be
/// bound. Otherwise, return `null`.
ParameterElement? get _staticParameterElementForRightHandSide {
Element? executableElement;
if (operator.type != TokenType.EQ) {
executableElement = staticElement;
} else {
executableElement = writeElement;
}
if (executableElement is ExecutableElement) {
List<ParameterElement> parameters = executableElement.parameters;
if (parameters.isEmpty) {
return null;
}
if (operator.type == TokenType.EQ && leftHandSide is IndexExpression) {
return parameters.length == 2 ? parameters[1] : null;
}
return parameters[0];
}
return null;
}
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitAssignmentExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitAssignmentExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_leftHandSide.accept(visitor);
_rightHandSide.accept(visitor);
}
@override
bool _extendsNullShorting(Expression descendant) =>
identical(descendant, _leftHandSide);
}
/// A node in the AST structure for a Dart program.
abstract final class AstNode implements SyntacticEntity {
/// A comparator that can be used to sort AST nodes in lexical order.
///
/// In other words, `compare` will return a negative value if the offset of
/// the first node is less than the offset of the second node, zero (0) if
/// the nodes have the same offset, and a positive value if the offset of the
/// first node is greater than the offset of the second node.
static Comparator<AstNode> LEXICAL_ORDER =
(AstNode first, AstNode second) => first.offset - second.offset;
/// Return the first token included in this node's source range.
Token get beginToken;
/// Return an iterator that can be used to iterate through all the entities
/// (either AST nodes or tokens) that make up the contents of this node,
/// including doc comments but excluding other comments.
Iterable<SyntacticEntity> get childEntities;
/// Return the offset of the character immediately following the last
/// character of this node's source range.
///
/// This is equivalent to `node.offset + node.length`. For a compilation unit
/// this will be equal to the length of the unit's source. For synthetic nodes
/// this will be equivalent to the node's offset (because the length is zero
/// (0) by definition).
@override
int get end;
/// Return the last token included in this node's source range.
Token get endToken;
/// Return `true` if this node is a synthetic node.
///
/// A synthetic node is a node that was introduced by the parser in order to
/// recover from an error in the code. Synthetic nodes always have a length
/// of zero (`0`).
bool get isSynthetic;
@override
int get length;
@override
int get offset;
/// Return this node's parent node, or `null` if this node is the root of an
/// AST structure.
///
/// Note that the relationship between an AST node and its parent node may
/// change over the lifetime of a node.
AstNode? get parent;
/// Return the node at the root of this node's AST structure.
///
/// Note that this method's performance is linear with respect to the depth
/// of the node in the AST structure (O(depth)).
AstNode get root;
/// Use the given [visitor] to visit this node.
///
/// Return the value returned by the visitor as a result of visiting this
/// node.
E? accept<E>(AstVisitor<E> visitor);
/// Return the token before [target] or `null` if it cannot be found.
Token? findPrevious(Token target);
/// Return the value of the property with the given [name], or `null` if this
/// node does not have a property with the given name.
E? getProperty<E>(String name);
/// Set the value of the property with the given [name] to the given [value].
/// If the value is `null`, the property will effectively be removed.
void setProperty(String name, Object? value);
/// Return either this node or the most immediate ancestor of this node for
/// which the [predicate] returns `true`, or `null` if there is no such node.
E? thisOrAncestorMatching<E extends AstNode>(
bool Function(AstNode) predicate,
);
/// Return either this node or the most immediate ancestor of this node that
/// has the given type, or `null` if there is no such node.
E? thisOrAncestorOfType<E extends AstNode>();
/// Return a textual description of this node in a form approximating valid
/// source.
///
/// The returned string will not be valid source primarily in the case where
/// the node itself is not well-formed.
String toSource();
/// Use the given [visitor] to visit all of the children of this node.
///
/// The children will be visited in lexical order.
void visitChildren(AstVisitor visitor);
}
/// A node in the AST structure for a Dart program.
sealed class AstNodeImpl implements AstNode {
/// The parent of the node, or `null` if the node is the root of an AST
/// structure.
AstNode? _parent;
/// A table mapping the names of properties to their values, or `null` if this
/// node does not have any properties associated with it.
Map<String, Object>? _propertyMap;
@override
Iterable<SyntacticEntity> get childEntities =>
_childEntities.syntacticEntities;
@override
int get end => offset + length;
@override
bool get isSynthetic => false;
@override
int get length {
final beginToken = this.beginToken;
final endToken = this.endToken;
return endToken.offset + endToken.length - beginToken.offset;
}
/// Return properties (tokens and nodes) of this node, with names, in the
/// order in which these entities should normally appear, not necessary in
/// the order they really are (because of recovery).
Iterable<ChildEntity> get namedChildEntities => _childEntities.entities;
@override
int get offset {
final beginToken = this.beginToken;
return beginToken.offset;
}
@override
AstNode? get parent => _parent;
@override
AstNode get root {
AstNode root = this;
var rootParent = parent;
while (rootParent != null) {
root = rootParent;
rootParent = root.parent;
}
return root;
}
ChildEntities get _childEntities => ChildEntities();
void detachFromParent() {
_parent = null;
}
@override
Token? findPrevious(Token target) =>
util.findPrevious(beginToken, target) ?? parent?.findPrevious(target);
@override
E? getProperty<E>(String name) {
return _propertyMap?[name] as E?;
}
@override
void setProperty(String name, Object? value) {
if (value == null) {
final propertyMap = _propertyMap;
if (propertyMap != null) {
propertyMap.remove(name);
if (propertyMap.isEmpty) {
_propertyMap = null;
}
}
} else {
(_propertyMap ??= HashMap<String, Object>())[name] = value;
}
}
@override
E? thisOrAncestorMatching<E extends AstNode>(
bool Function(AstNode) predicate,
) {
AstNode? node = this;
while (node != null && !predicate(node)) {
node = node.parent;
}
return node as E?;
}
@override
E? thisOrAncestorOfType<E extends AstNode>() {
AstNode? node = this;
while (node != null && node is! E) {
node = node.parent;
}
return node as E?;
}
@override
String toSource() {
StringBuffer buffer = StringBuffer();
accept(ToSourceVisitor(buffer));
return buffer.toString();
}
@override
String toString() => toSource();
/// Make this node the parent of the given [child] node. Return the child
/// node.
T _becomeParentOf<T extends AstNodeImpl?>(T child) {
child?._parent = this;
return child;
}
}
/// An object that can be used to visit an AST structure.
///
/// Clients may not extend, implement or mix-in this class. There are classes
/// that implement this interface that provide useful default behaviors in
/// `package:analyzer/dart/ast/visitor.dart`. A couple of the most useful
/// include
/// * SimpleAstVisitor which implements every visit method by doing nothing,
/// * RecursiveAstVisitor which will cause every node in a structure to be
/// visited, and
/// * ThrowingAstVisitor which implements every visit method by throwing an
/// exception.
abstract class AstVisitor<R> {
R? visitAdjacentStrings(AdjacentStrings node);
R? visitAnnotation(Annotation node);
R? visitArgumentList(ArgumentList node);
R? visitAsExpression(AsExpression node);
R? visitAssertInitializer(AssertInitializer node);
R? visitAssertStatement(AssertStatement assertStatement);
R? visitAssignedVariablePattern(AssignedVariablePattern node);
R? visitAssignmentExpression(AssignmentExpression node);
R? visitAugmentationImportDirective(AugmentationImportDirective node);
R? visitAwaitExpression(AwaitExpression node);
R? visitBinaryExpression(BinaryExpression node);
R? visitBlock(Block node);
R? visitBlockFunctionBody(BlockFunctionBody node);
R? visitBooleanLiteral(BooleanLiteral node);
R? visitBreakStatement(BreakStatement node);
R? visitCascadeExpression(CascadeExpression node);
R? visitCaseClause(CaseClause node);
R? visitCastPattern(CastPattern node);
R? visitCatchClause(CatchClause node);
R? visitCatchClauseParameter(CatchClauseParameter node);
R? visitClassDeclaration(ClassDeclaration node);
R? visitClassTypeAlias(ClassTypeAlias node);
R? visitComment(Comment node);
R? visitCommentReference(CommentReference node);
R? visitCompilationUnit(CompilationUnit node);
R? visitConditionalExpression(ConditionalExpression node);
R? visitConfiguration(Configuration node);
R? visitConstantPattern(ConstantPattern node);
R? visitConstructorDeclaration(ConstructorDeclaration node);
R? visitConstructorFieldInitializer(ConstructorFieldInitializer node);
R? visitConstructorName(ConstructorName node);
R? visitConstructorReference(ConstructorReference node);
R? visitConstructorSelector(ConstructorSelector node);
R? visitContinueStatement(ContinueStatement node);
R? visitDeclaredIdentifier(DeclaredIdentifier node);
R? visitDeclaredVariablePattern(DeclaredVariablePattern node);
R? visitDefaultFormalParameter(DefaultFormalParameter node);
R? visitDoStatement(DoStatement node);
R? visitDottedName(DottedName node);
R? visitDoubleLiteral(DoubleLiteral node);
R? visitEmptyFunctionBody(EmptyFunctionBody node);
R? visitEmptyStatement(EmptyStatement node);
R? visitEnumConstantArguments(EnumConstantArguments node);
R? visitEnumConstantDeclaration(EnumConstantDeclaration node);
R? visitEnumDeclaration(EnumDeclaration node);
R? visitExportDirective(ExportDirective node);
R? visitExpressionFunctionBody(ExpressionFunctionBody node);
R? visitExpressionStatement(ExpressionStatement node);
R? visitExtendsClause(ExtendsClause node);
R? visitExtensionDeclaration(ExtensionDeclaration node);
R? visitExtensionOverride(ExtensionOverride node);
R? visitExtensionTypeDeclaration(ExtensionTypeDeclaration node);
R? visitFieldDeclaration(FieldDeclaration node);
R? visitFieldFormalParameter(FieldFormalParameter node);
R? visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node);
R? visitForEachPartsWithIdentifier(ForEachPartsWithIdentifier node);
R? visitForEachPartsWithPattern(ForEachPartsWithPattern node);
R? visitForElement(ForElement node);
R? visitFormalParameterList(FormalParameterList node);
R? visitForPartsWithDeclarations(ForPartsWithDeclarations node);
R? visitForPartsWithExpression(ForPartsWithExpression node);
R? visitForPartsWithPattern(ForPartsWithPattern node);
R? visitForStatement(ForStatement node);
R? visitFunctionDeclaration(FunctionDeclaration node);
R? visitFunctionDeclarationStatement(FunctionDeclarationStatement node);
R? visitFunctionExpression(FunctionExpression node);
R? visitFunctionExpressionInvocation(FunctionExpressionInvocation node);
R? visitFunctionReference(FunctionReference node);
R? visitFunctionTypeAlias(FunctionTypeAlias functionTypeAlias);
R? visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node);
R? visitGenericFunctionType(GenericFunctionType node);
R? visitGenericTypeAlias(GenericTypeAlias node);
R? visitGuardedPattern(GuardedPattern node);
R? visitHideCombinator(HideCombinator node);
R? visitIfElement(IfElement node);
R? visitIfStatement(IfStatement node);
R? visitImplementsClause(ImplementsClause node);
R? visitImplicitCallReference(ImplicitCallReference node);
R? visitImportDirective(ImportDirective node);
R? visitImportPrefixReference(ImportPrefixReference node);
R? visitIndexExpression(IndexExpression node);
R? visitInstanceCreationExpression(InstanceCreationExpression node);
R? visitIntegerLiteral(IntegerLiteral node);
R? visitInterpolationExpression(InterpolationExpression node);
R? visitInterpolationString(InterpolationString node);
R? visitIsExpression(IsExpression node);
R? visitLabel(Label node);
R? visitLabeledStatement(LabeledStatement node);
R? visitLibraryAugmentationDirective(LibraryAugmentationDirective node);
R? visitLibraryDirective(LibraryDirective node);
R? visitLibraryIdentifier(LibraryIdentifier node);
R? visitListLiteral(ListLiteral node);
R? visitListPattern(ListPattern node);
R? visitLogicalAndPattern(LogicalAndPattern node);
R? visitLogicalOrPattern(LogicalOrPattern node);
R? visitMapLiteralEntry(MapLiteralEntry node);
R? visitMapPattern(MapPattern node);
R? visitMapPatternEntry(MapPatternEntry node);
R? visitMethodDeclaration(MethodDeclaration node);
R? visitMethodInvocation(MethodInvocation node);
R? visitMixinDeclaration(MixinDeclaration node);
R? visitNamedExpression(NamedExpression node);
R? visitNamedType(NamedType node);
R? visitNativeClause(NativeClause node);
R? visitNativeFunctionBody(NativeFunctionBody node);
R? visitNullAssertPattern(NullAssertPattern node);
R? visitNullCheckPattern(NullCheckPattern node);
R? visitNullLiteral(NullLiteral node);
R? visitObjectPattern(ObjectPattern node);
R? visitOnClause(OnClause node);
R? visitParenthesizedExpression(ParenthesizedExpression node);
R? visitParenthesizedPattern(ParenthesizedPattern node);
R? visitPartDirective(PartDirective node);
R? visitPartOfDirective(PartOfDirective node);
R? visitPatternAssignment(PatternAssignment node);
R? visitPatternField(PatternField node);
R? visitPatternFieldName(PatternFieldName node);
R? visitPatternVariableDeclaration(PatternVariableDeclaration node);
R? visitPatternVariableDeclarationStatement(
PatternVariableDeclarationStatement node);
R? visitPostfixExpression(PostfixExpression node);
R? visitPrefixedIdentifier(PrefixedIdentifier node);
R? visitPrefixExpression(PrefixExpression node);
R? visitPropertyAccess(PropertyAccess node);
R? visitRecordLiteral(RecordLiteral node);
R? visitRecordPattern(RecordPattern node);
R? visitRecordTypeAnnotation(RecordTypeAnnotation node);
R? visitRecordTypeAnnotationNamedField(RecordTypeAnnotationNamedField node);
R? visitRecordTypeAnnotationNamedFields(RecordTypeAnnotationNamedFields node);
R? visitRecordTypeAnnotationPositionalField(
RecordTypeAnnotationPositionalField node);
R? visitRedirectingConstructorInvocation(
RedirectingConstructorInvocation node);
R? visitRelationalPattern(RelationalPattern node);
R? visitRepresentationConstructorName(RepresentationConstructorName node);
R? visitRepresentationDeclaration(RepresentationDeclaration node);
R? visitRestPatternElement(RestPatternElement node);
R? visitRethrowExpression(RethrowExpression node);
R? visitReturnStatement(ReturnStatement node);
R? visitScriptTag(ScriptTag node);
R? visitSetOrMapLiteral(SetOrMapLiteral node);
R? visitShowCombinator(ShowCombinator node);
R? visitSimpleFormalParameter(SimpleFormalParameter node);
R? visitSimpleIdentifier(SimpleIdentifier node);
R? visitSimpleStringLiteral(SimpleStringLiteral node);
R? visitSpreadElement(SpreadElement node);
R? visitStringInterpolation(StringInterpolation node);
R? visitSuperConstructorInvocation(SuperConstructorInvocation node);
R? visitSuperExpression(SuperExpression node);
R? visitSuperFormalParameter(SuperFormalParameter node);
R? visitSwitchCase(SwitchCase node);
R? visitSwitchDefault(SwitchDefault node);
R? visitSwitchExpression(SwitchExpression node);
R? visitSwitchExpressionCase(SwitchExpressionCase node);
R? visitSwitchPatternCase(SwitchPatternCase node);
R? visitSwitchStatement(SwitchStatement node);
R? visitSymbolLiteral(SymbolLiteral node);
R? visitThisExpression(ThisExpression node);
R? visitThrowExpression(ThrowExpression node);
R? visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node);
R? visitTryStatement(TryStatement node);
R? visitTypeArgumentList(TypeArgumentList node);
R? visitTypeLiteral(TypeLiteral node);
R? visitTypeParameter(TypeParameter node);
R? visitTypeParameterList(TypeParameterList node);
R? visitVariableDeclaration(VariableDeclaration node);
R? visitVariableDeclarationList(VariableDeclarationList node);
R? visitVariableDeclarationStatement(VariableDeclarationStatement node);
R? visitWhenClause(WhenClause node);
R? visitWhileStatement(WhileStatement node);
R? visitWildcardPattern(WildcardPattern node);
R? visitWithClause(WithClause node);
R? visitYieldStatement(YieldStatement node);
}
/// An augmentation import directive.
///
/// importDirective ::=
/// [Annotation] 'import' 'augment' [StringLiteral] ';'
@experimental
abstract final class AugmentationImportDirective implements UriBasedDirective {
/// The token representing the 'augment' keyword.
Token get augmentKeyword;
@override
AugmentationImportElement? get element;
/// The token representing the 'import' keyword.
Token get importKeyword;
/// Return the semicolon terminating the directive.
Token get semicolon;
}
/// An augmentation import directive.
///
/// importDirective ::=
/// [Annotation] 'import' 'augment' [StringLiteral] ';'
final class AugmentationImportDirectiveImpl extends UriBasedDirectiveImpl
implements AugmentationImportDirective {
@override
final Token importKeyword;
@override
final Token augmentKeyword;
@override
final Token semicolon;
AugmentationImportDirectiveImpl({
required super.comment,
required super.metadata,
required this.importKeyword,
required this.augmentKeyword,
required this.semicolon,
required super.uri,
}) {
_becomeParentOf(_uri);
}
@override
AugmentationImportElementImpl? get element {
return super.element as AugmentationImportElementImpl?;
}
@override
Token get endToken => semicolon;
@override
Token get firstTokenAfterCommentAndMetadata => importKeyword;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('importKeyword', importKeyword)
..addToken('augmentKeyword', augmentKeyword)
..addNode('uri', uri)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitAugmentationImportDirective(this);
}
}
/// An await expression.
///
/// awaitExpression ::=
/// 'await' [Expression]
abstract final class AwaitExpression implements Expression {
/// Return the 'await' keyword.
Token get awaitKeyword;
/// Return the expression whose value is being waited on.
Expression get expression;
}
/// An await expression.
///
/// awaitExpression ::=
/// 'await' [Expression]
final class AwaitExpressionImpl extends ExpressionImpl
implements AwaitExpression {
/// The 'await' keyword.
@override
final Token awaitKeyword;
/// The expression whose value is being waited on.
ExpressionImpl _expression;
/// Initialize a newly created await expression.
AwaitExpressionImpl({
required this.awaitKeyword,
required ExpressionImpl expression,
}) : _expression = expression {
_becomeParentOf(_expression);
}
@override
Token get beginToken {
return awaitKeyword;
}
@override
Token get endToken => _expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
Precedence get precedence => Precedence.prefix;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('awaitKeyword', awaitKeyword)
..addNode('expression', expression);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitAwaitExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitAwaitExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
}
}
/// A binary (infix) expression.
///
/// binaryExpression ::=
/// [Expression] [Token] [Expression]
abstract final class BinaryExpression
implements Expression, MethodReferenceExpression {
/// Return the expression used to compute the left operand.
Expression get leftOperand;
/// Return the binary operator being applied.
Token get operator;
/// Return the expression used to compute the right operand.
Expression get rightOperand;
/// The function type of the invocation, or `null` if the AST structure has
/// not been resolved, or if the invocation could not be resolved.
FunctionType? get staticInvokeType;
}
/// A binary (infix) expression.
///
/// binaryExpression ::=
/// [Expression] [Token] [Expression]
final class BinaryExpressionImpl extends ExpressionImpl
implements BinaryExpression {
/// The expression used to compute the left operand.
ExpressionImpl _leftOperand;
/// The binary operator being applied.
@override
final Token operator;
/// The expression used to compute the right operand.
ExpressionImpl _rightOperand;
/// The element associated with the operator based on the static type of the
/// left operand, or `null` if the AST structure has not been resolved, if the
/// operator is not user definable, or if the operator could not be resolved.
@override
MethodElement? staticElement;
@override
FunctionType? staticInvokeType;
/// Initialize a newly created binary expression.
BinaryExpressionImpl({
required ExpressionImpl leftOperand,
required this.operator,
required ExpressionImpl rightOperand,
}) : _leftOperand = leftOperand,
_rightOperand = rightOperand {
_becomeParentOf(leftOperand);
_becomeParentOf(rightOperand);
}
@override
Token get beginToken => _leftOperand.beginToken;
@override
Token get endToken => _rightOperand.endToken;
@override
ExpressionImpl get leftOperand => _leftOperand;
set leftOperand(ExpressionImpl expression) {
_leftOperand = _becomeParentOf(expression);
}
@override
Precedence get precedence => Precedence.forTokenType(operator.type);
@override
ExpressionImpl get rightOperand => _rightOperand;
set rightOperand(ExpressionImpl expression) {
_rightOperand = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('leftOperand', leftOperand)
..addToken('operator', operator)
..addNode('rightOperand', rightOperand);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitBinaryExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitBinaryExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_leftOperand.accept(visitor);
_rightOperand.accept(visitor);
}
}
/// A sequence of statements.
///
/// block ::=
/// '{' statement* '}'
abstract final class Block implements Statement {
/// Return the left curly bracket.
Token get leftBracket;
/// Return the right curly bracket.
Token get rightBracket;
/// Return the statements contained in the block.
NodeList<Statement> get statements;
}
/// A function body that consists of a block of statements.
///
/// blockFunctionBody ::=
/// ('async' | 'async' '*' | 'sync' '*')? [Block]
abstract final class BlockFunctionBody implements FunctionBody {
/// Return the block representing the body of the function.
Block get block;
}
/// A function body that consists of a block of statements.
///
/// blockFunctionBody ::=
/// ('async' | 'async' '*' | 'sync' '*')? [Block]
final class BlockFunctionBodyImpl extends FunctionBodyImpl
implements BlockFunctionBody {
/// The token representing the 'async' or 'sync' keyword, or `null` if there
/// is no such keyword.
@override
final Token? keyword;
/// The star optionally following the 'async' or 'sync' keyword, or `null` if
/// there is wither no such keyword or no star.
@override
final Token? star;
/// The block representing the body of the function.
BlockImpl _block;
/// Initialize a newly created function body consisting of a block of
/// statements. The [keyword] can be `null` if there is no keyword specified
/// for the block. The [star] can be `null` if there is no star following the
/// keyword (and must be `null` if there is no keyword).
BlockFunctionBodyImpl({
required this.keyword,
required this.star,
required BlockImpl block,
}) : _block = block {
_becomeParentOf(_block);
}
@override
Token get beginToken {
if (keyword case final keyword?) {
return keyword;
}
return _block.beginToken;
}
@override
BlockImpl get block => _block;
set block(BlockImpl block) {
_block = _becomeParentOf(block);
}
@override
Token get endToken => _block.endToken;
@override
bool get isAsynchronous => keyword?.lexeme == Keyword.ASYNC.lexeme;
@override
bool get isGenerator => star != null;
@override
bool get isSynchronous => keyword?.lexeme != Keyword.ASYNC.lexeme;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('keyword', keyword)
..addToken('star', star)
..addNode('block', block);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitBlockFunctionBody(this);
@override
DartType resolve(ResolverVisitor resolver, DartType? imposedType) =>
resolver.visitBlockFunctionBody(this, imposedType: imposedType);
@override
void visitChildren(AstVisitor visitor) {
_block.accept(visitor);
}
}
/// A sequence of statements.
///
/// block ::=
/// '{' statement* '}'
final class BlockImpl extends StatementImpl implements Block {
/// The left curly bracket.
@override
final Token leftBracket;
/// The statements contained in the block.
final NodeListImpl<StatementImpl> _statements = NodeListImpl._();
/// The right curly bracket.
@override
final Token rightBracket;
/// Initialize a newly created block of code.
BlockImpl({
required this.leftBracket,
required List<StatementImpl> statements,
required this.rightBracket,
}) {
_statements._initialize(this, statements);
}
@override
Token get beginToken => leftBracket;
@override
Token get endToken => rightBracket;
@override
NodeListImpl<StatementImpl> get statements => _statements;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('leftBracket', leftBracket)
..addNodeList('statements', statements)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitBlock(this);
@override
void visitChildren(AstVisitor visitor) {
_statements.accept(visitor);
}
}
/// A boolean literal expression.
///
/// booleanLiteral ::=
/// 'false' | 'true'
abstract final class BooleanLiteral implements Literal {
/// Return the token representing the literal.
Token get literal;
/// Return the value of the literal.
bool get value;
}
/// A boolean literal expression.
///
/// booleanLiteral ::=
/// 'false' | 'true'
final class BooleanLiteralImpl extends LiteralImpl implements BooleanLiteral {
/// The token representing the literal.
@override
final Token literal;
/// The value of the literal.
@override
final bool value;
/// Initialize a newly created boolean literal.
BooleanLiteralImpl({
required this.literal,
required this.value,
});
@override
Token get beginToken => literal;
@override
Token get endToken => literal;
@override
bool get isSynthetic => literal.isSynthetic;
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('literal', literal);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitBooleanLiteral(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitBooleanLiteral(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
}
/// A break statement.
///
/// breakStatement ::=
/// 'break' [SimpleIdentifier]? ';'
abstract final class BreakStatement implements Statement {
/// Return the token representing the 'break' keyword.
Token get breakKeyword;
/// Return the label associated with the statement, or `null` if there is no
/// label.
SimpleIdentifier? get label;
/// Return the semicolon terminating the statement.
Token get semicolon;
/// Return the node from which this break statement is breaking.
///
/// This will be either a [Statement] (in the case of breaking out of a
/// loop), a [SwitchMember] (in the case of a labeled break statement whose
/// label matches a label on a switch case in an enclosing switch statement),
/// or `null` if the AST has not yet been resolved or if the target could not
/// be resolved. Note that if the source code has errors, the target might be
/// invalid (e.g. trying to break to a switch case).
AstNode? get target;
}
/// A break statement.
///
/// breakStatement ::=
/// 'break' [SimpleIdentifier]? ';'
final class BreakStatementImpl extends StatementImpl implements BreakStatement {
/// The token representing the 'break' keyword.
@override
final Token breakKeyword;
/// The label associated with the statement, or `null` if there is no label.
SimpleIdentifierImpl? _label;
/// The semicolon terminating the statement.
@override
final Token semicolon;
/// The AstNode which this break statement is breaking from. This will be
/// either a [Statement] (in the case of breaking out of a loop), a
/// [SwitchMember] (in the case of a labeled break statement whose label
/// matches a label on a switch case in an enclosing switch statement), or
/// `null` if the AST has not yet been resolved or if the target could not be
/// resolved. Note that if the source code has errors, the target might be
/// invalid (e.g. trying to break to a switch case).
@override
AstNode? target;
/// Initialize a newly created break statement. The [label] can be `null` if
/// there is no label associated with the statement.
BreakStatementImpl({
required this.breakKeyword,
required SimpleIdentifierImpl? label,
required this.semicolon,
}) : _label = label {
_becomeParentOf(_label);
}
@override
Token get beginToken => breakKeyword;
@override
Token get endToken => semicolon;
@override
SimpleIdentifierImpl? get label => _label;
set label(SimpleIdentifierImpl? identifier) {
_label = _becomeParentOf(identifier);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('breakKeyword', breakKeyword)
..addNode('label', label)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitBreakStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_label?.accept(visitor);
}
}
/// A sequence of cascaded expressions: expressions that share a common target.
///
/// There are three kinds of expressions that can be used in a cascade
/// expression: [IndexExpression], [MethodInvocation] and [PropertyAccess].
///
/// cascadeExpression ::=
/// [Expression] cascadeSection*
///
/// cascadeSection ::=
/// ('..' | '?..') (cascadeSelector arguments*)
/// (assignableSelector arguments*)*
/// (assignmentOperator expressionWithoutCascade)?
///
/// cascadeSelector ::=
/// '[ ' expression '] '
/// | identifier
abstract final class CascadeExpression
implements Expression, NullShortableExpression {
/// Return the cascade sections sharing the common target.
NodeList<Expression> get cascadeSections;
/// Whether this cascade is null aware (as opposed to non-null).
bool get isNullAware;
/// Return the target of the cascade sections.
Expression get target;
}
/// A sequence of cascaded expressions: expressions that share a common target.
/// There are three kinds of expressions that can be used in a cascade
/// expression: [IndexExpression], [MethodInvocation] and [PropertyAccess].
///
/// cascadeExpression ::=
/// [Expression] cascadeSection*
///
/// cascadeSection ::=
/// '..' (cascadeSelector arguments*) (assignableSelector arguments*)*
/// (assignmentOperator expressionWithoutCascade)?
///
/// cascadeSelector ::=
/// '[ ' expression '] '
/// | identifier
final class CascadeExpressionImpl extends ExpressionImpl
with NullShortableExpressionImpl
implements CascadeExpression {
/// The target of the cascade sections.
ExpressionImpl _target;
/// The cascade sections sharing the common target.
final NodeListImpl<ExpressionImpl> _cascadeSections = NodeListImpl._();
/// Initialize a newly created cascade expression. The list of
/// [cascadeSections] must contain at least one element.
CascadeExpressionImpl({
required ExpressionImpl target,
required List<ExpressionImpl> cascadeSections,
}) : _target = target {
_becomeParentOf(_target);
_cascadeSections._initialize(this, cascadeSections);
}
@override
Token get beginToken => _target.beginToken;
@override
NodeListImpl<ExpressionImpl> get cascadeSections => _cascadeSections;
@override
Token get endToken => _cascadeSections.endToken!;
@override
bool get isNullAware {
return target.endToken.next!.type == TokenType.QUESTION_PERIOD_PERIOD;
}
@override
Precedence get precedence => Precedence.cascade;
@override
ExpressionImpl get target => _target;
set target(ExpressionImpl target) {
_target = _becomeParentOf(target);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('target', target)
..addNodeList('cascadeSections', cascadeSections);
@override
AstNode? get _nullShortingExtensionCandidate => null;
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitCascadeExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitCascadeExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_target.accept(visitor);
_cascadeSections.accept(visitor);
}
@override
bool _extendsNullShorting(Expression descendant) {
return _cascadeSections.contains(descendant);
}
}
/// The `case` clause that can optionally appear in an `if` statement.
///
/// caseClause ::=
/// 'case' [GuardedPattern]
abstract final class CaseClause implements AstNode {
/// Return the token representing the 'case' keyword.
Token get caseKeyword;
/// Return the pattern controlling whether the statements will be executed.
GuardedPattern get guardedPattern;
}
/// The `case` clause that can optionally appear in an `if` statement.
///
/// caseClause ::=
/// 'case' [DartPattern] [WhenClause]?
final class CaseClauseImpl extends AstNodeImpl implements CaseClause {
@override
final Token caseKeyword;
@override
final GuardedPatternImpl guardedPattern;
CaseClauseImpl({
required this.caseKeyword,
required this.guardedPattern,
}) {
_becomeParentOf(guardedPattern);
}
@override
Token get beginToken => caseKeyword;
@override
Token get endToken => guardedPattern.endToken;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('caseKeyword', caseKeyword)
..addNode('guardedPattern', guardedPattern);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitCaseClause(this);
@override
void visitChildren(AstVisitor visitor) {
guardedPattern.accept(visitor);
}
}
/// A cast pattern.
///
/// castPattern ::=
/// [DartPattern] 'as' [TypeAnnotation]
abstract final class CastPattern implements DartPattern {
/// The `as` token.
Token get asToken;
/// The pattern whose matched value will be cast.
DartPattern get pattern;
/// The type that the value being matched is cast to.
TypeAnnotation get type;
}
/// A cast pattern.
///
/// castPattern ::=
/// [DartPattern] 'as' [TypeAnnotation]
final class CastPatternImpl extends DartPatternImpl implements CastPattern {
@override
final Token asToken;
@override
final DartPatternImpl pattern;
@override
final TypeAnnotationImpl type;
CastPatternImpl({
required this.pattern,
required this.asToken,
required this.type,
}) {
_becomeParentOf(pattern);
_becomeParentOf(type);
}
@override
Token get beginToken => pattern.beginToken;
@override
Token get endToken => type.endToken;
@override
PatternPrecedence get precedence => PatternPrecedence.postfix;
@override
VariablePatternImpl? get variablePattern => pattern.variablePattern;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('pattern', pattern)
..addToken('asToken', asToken)
..addNode('type', type);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitCastPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor.analyzeCastPatternSchema();
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
type.accept(resolverVisitor);
final requiredType = type.typeOrThrow;
resolverVisitor.analyzeCastPattern(
context: context,
pattern: this,
innerPattern: pattern,
requiredType: requiredType,
);
resolverVisitor.checkPatternNeverMatchesValueType(
context: context,
pattern: this,
requiredType: requiredType,
);
}
@override
void visitChildren(AstVisitor visitor) {
pattern.accept(visitor);
type.accept(visitor);
}
}
/// A catch clause within a try statement.
///
/// onPart ::=
/// catchPart [Block]
/// | 'on' type catchPart? [Block]
///
/// catchPart ::=
/// 'catch' '(' [CatchClauseParameter] (',' [CatchClauseParameter])? ')'
abstract final class CatchClause implements AstNode {
/// Return the body of the catch block.
Block get body;
/// Return the token representing the 'catch' keyword, or `null` if there is
/// no 'catch' keyword.
Token? get catchKeyword;
/// Return the comma separating the exception parameter from the stack trace
/// parameter, or `null` if there is no stack trace parameter.
Token? get comma;
/// Return the parameter whose value will be the exception that was thrown, or
/// `null` if there is no 'catch' keyword.
CatchClauseParameter? get exceptionParameter;
/// Return the type of exceptions caught by this catch clause, or `null` if
/// this catch clause catches every type of exception.
TypeAnnotation? get exceptionType;
/// Return the left parenthesis, or `null` if there is no 'catch' keyword.
Token? get leftParenthesis;
/// Return the token representing the 'on' keyword, or `null` if there is no
/// 'on' keyword.
Token? get onKeyword;
/// Return the right parenthesis, or `null` if there is no 'catch' keyword.
Token? get rightParenthesis;
/// Return the parameter whose value will be the stack trace associated with
/// the exception, or `null` if there is no stack trace parameter.
CatchClauseParameter? get stackTraceParameter;
}
/// A catch clause within a try statement.
///
/// onPart ::=
/// catchPart [Block]
/// | 'on' type catchPart? [Block]
///
/// catchPart ::=
/// 'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
final class CatchClauseImpl extends AstNodeImpl implements CatchClause {
/// The token representing the 'on' keyword, or `null` if there is no 'on'
/// keyword.
@override
final Token? onKeyword;
/// The type of exceptions caught by this catch clause, or `null` if this
/// catch clause catches every type of exception.
TypeAnnotationImpl? _exceptionType;
/// The token representing the 'catch' keyword, or `null` if there is no
/// 'catch' keyword.
@override
final Token? catchKeyword;
/// The left parenthesis, or `null` if there is no 'catch' keyword.
@override
final Token? leftParenthesis;
/// The parameter whose value will be the exception that was thrown, or `null`
/// if there is no 'catch' keyword.
CatchClauseParameterImpl? _exceptionParameter;
/// The comma separating the exception parameter from the stack trace
/// parameter, or `null` if there is no stack trace parameter.
@override
final Token? comma;
/// The parameter whose value will be the stack trace associated with the
/// exception, or `null` if there is no stack trace parameter.
CatchClauseParameterImpl? _stackTraceParameter;
/// The right parenthesis, or `null` if there is no 'catch' keyword.
@override
final Token? rightParenthesis;
/// The body of the catch block.
BlockImpl _body;
/// Initialize a newly created catch clause. The [onKeyword] and
/// [exceptionType] can be `null` if the clause will catch all exceptions. The
/// [comma] and [_stackTraceParameter] can be `null` if the stack trace
/// parameter is not defined.
CatchClauseImpl({
required this.onKeyword,
required TypeAnnotationImpl? exceptionType,
required this.catchKeyword,
required this.leftParenthesis,
required CatchClauseParameterImpl? exceptionParameter,
required this.comma,
required CatchClauseParameterImpl? stackTraceParameter,
required this.rightParenthesis,
required BlockImpl body,
}) : assert(onKeyword != null || catchKeyword != null),
_exceptionType = exceptionType,
_exceptionParameter = exceptionParameter,
_stackTraceParameter = stackTraceParameter,
_body = body {
_becomeParentOf(_exceptionType);
_becomeParentOf(_exceptionParameter);
_becomeParentOf(_stackTraceParameter);
_becomeParentOf(_body);
}
@override
Token get beginToken {
if (onKeyword case final onKeyword?) {
return onKeyword;
}
return catchKeyword!;
}
@override
BlockImpl get body => _body;
set body(BlockImpl block) {
_body = _becomeParentOf(block);
}
@override
Token get endToken => _body.endToken;
@override
CatchClauseParameterImpl? get exceptionParameter {
return _exceptionParameter;
}
set exceptionParameter(CatchClauseParameterImpl? parameter) {
_exceptionParameter = parameter;
_becomeParentOf(parameter);
}
@override
TypeAnnotationImpl? get exceptionType => _exceptionType;
set exceptionType(TypeAnnotationImpl? exceptionType) {
_exceptionType = _becomeParentOf(exceptionType);
}
@override
CatchClauseParameterImpl? get stackTraceParameter {
return _stackTraceParameter;
}
set stackTraceParameter(CatchClauseParameterImpl? parameter) {
_stackTraceParameter = parameter;
_becomeParentOf(parameter);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('onKeyword', onKeyword)
..addNode('exceptionType', exceptionType)
..addToken('catchKeyword', catchKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('exceptionParameter', exceptionParameter)
..addToken('comma', comma)
..addNode('stackTraceParameter', stackTraceParameter)
..addToken('rightParenthesis', rightParenthesis)
..addNode('body', body);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitCatchClause(this);
@override
void visitChildren(AstVisitor visitor) {
_exceptionType?.accept(visitor);
_exceptionParameter?.accept(visitor);
_stackTraceParameter?.accept(visitor);
_body.accept(visitor);
}
}
/// The 'exception' or 'stackTrace' parameter in [CatchClause].
abstract final class CatchClauseParameter extends AstNode {
/// The declared element, or `null` if the AST has not been resolved.
LocalVariableElement? get declaredElement;
/// The name of the parameter.
Token get name;
}
final class CatchClauseParameterImpl extends AstNodeImpl
implements CatchClauseParameter {
@override
final Token name;
@override
LocalVariableElementImpl? declaredElement;
CatchClauseParameterImpl({
required this.name,
});
@override
Token get beginToken => name;
@override
Token get endToken => name;
@override
ChildEntities get _childEntities =>
super._childEntities..addToken('name', name);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitCatchClauseParameter(this);
}
@override
void visitChildren(AstVisitor visitor) {}
}
/// Helper class to allow iteration of child entities of an AST node.
class ChildEntities {
/// The list of child entities to be iterated over.
final List<ChildEntity> entities = [];
List<SyntacticEntity> get syntacticEntities {
var result = <SyntacticEntity>[];
for (var entity in entities) {
var entityValue = entity.value;
if (entityValue is SyntacticEntity) {
result.add(entityValue);
} else if (entityValue is List<Object>) {
for (var element in entityValue) {
if (element is SyntacticEntity) {
result.add(element);
}
}
}
}
var needsSorting = false;
int? lastOffset;
for (var entity in result) {
if (lastOffset != null && lastOffset > entity.offset) {
needsSorting = true;
break;
}
lastOffset = entity.offset;
}
if (needsSorting) {
result.sort((a, b) => a.offset - b.offset);
}
return result;
}
void addAll(ChildEntities other) {
entities.addAll(other.entities);
}
void addNode(String name, AstNode? value) {
if (value != null) {
entities.add(
ChildEntity(name, value),
);
}
}
void addNodeList(String name, List<AstNode> value) {
entities.add(
ChildEntity(name, value),
);
}
void addToken(String name, Token? value) {
if (value != null) {
entities.add(
ChildEntity(name, value),
);
}
}
void addTokenList(String name, List<Token> value) {
entities.add(
ChildEntity(name, value),
);
}
}
/// A named child of an [AstNode], usually a token, node, or a list of nodes.
class ChildEntity {
final String name;
final Object value;
ChildEntity(this.name, this.value);
}
/// The declaration of a class.
///
/// classDeclaration ::=
/// classModifiers 'class' name [TypeParameterList]?
/// [ExtendsClause]? [WithClause]? [ImplementsClause]?
/// '{' [ClassMember]* '}'
///
/// classModifiers ::= 'sealed'
/// | 'abstract'? ('base' | 'interface' | 'final')?
/// | 'abstract'? 'base'? 'mixin'
abstract final class ClassDeclaration implements NamedCompilationUnitMember {
/// Return the 'abstract' keyword, or `null` if the keyword was absent.
///
/// In valid code only [ClassDeclaration] can specify it.
Token? get abstractKeyword;
/// Return the 'augment' keyword, or `null` if the keyword was absent.
@experimental
Token? get augmentKeyword;
/// Return the 'base' keyword, or `null` if the keyword was absent.
Token? get baseKeyword;
/// Returns the token representing the 'class' keyword.
Token get classKeyword;
@override
ClassElement? get declaredElement;
/// Returns the `extends` clause for this class, or `null` if the class
/// does not extend any other class.
ExtendsClause? get extendsClause;
/// Return the 'final' keyword, or `null` if the keyword was absent.
Token? get finalKeyword;
/// Returns the `implements` clause for the class, or `null` if the class
/// does not implement any interfaces.
ImplementsClause? get implementsClause;
/// Return the 'inline' keyword, or `null` if the keyword was absent.
@Deprecated('Replaced with extension types')
@experimental
Token? get inlineKeyword;
/// Return the 'interface' keyword, or `null` if the keyword was absent.
Token? get interfaceKeyword;
/// Returns the left curly bracket.
Token get leftBracket;
/// Return the 'macro' keyword, or `null` if the keyword was absent.
@experimental
Token? get macroKeyword;
/// Returns the members defined by the class.
NodeList<ClassMember> get members;
/// Return the 'mixin' keyword, or `null` if the keyword was absent.
Token? get mixinKeyword;
/// Return the native clause for this class, or `null` if the class does not
/// have a native clause.
NativeClause? get nativeClause;
/// Returns the right curly bracket.
Token get rightBracket;
/// Return the 'sealed' keyword, or `null` if the keyword was absent.
Token? get sealedKeyword;
/// Returns the type parameters for the class, or `null` if the class does
/// not have any type parameters.
TypeParameterList? get typeParameters;
/// Returns the `with` clause for the class, or `null` if the class does not
/// have a `with` clause.
WithClause? get withClause;
}
final class ClassDeclarationImpl extends NamedCompilationUnitMemberImpl
implements ClassDeclaration {
@override
final Token? augmentKeyword;
@override
final Token? abstractKeyword;
@override
final Token? macroKeyword;
@override
final Token? sealedKeyword;
@override
final Token? baseKeyword;
@override
final Token? interfaceKeyword;
@override
final Token? finalKeyword;
@override
final Token? mixinKeyword;
@override
final Token classKeyword;
@override
TypeParameterListImpl? typeParameters;
@override
ExtendsClauseImpl? extendsClause;
@override
WithClauseImpl? withClause;
@override
ImplementsClauseImpl? implementsClause;
@override
final NativeClauseImpl? nativeClause;
@override
final Token leftBracket;
@override
final NodeListImpl<ClassMemberImpl> members = NodeListImpl._();
@override
final Token rightBracket;
@override
ClassElementImpl? declaredElement;
ClassDeclarationImpl({
required super.comment,
required super.metadata,
required this.augmentKeyword,
required this.abstractKeyword,
required this.macroKeyword,
required this.sealedKeyword,
required this.baseKeyword,
required this.interfaceKeyword,
required this.finalKeyword,
required this.mixinKeyword,
required this.classKeyword,
required super.name,
required this.typeParameters,
required this.extendsClause,
required this.withClause,
required this.implementsClause,
required this.nativeClause,
required this.leftBracket,
required List<ClassMemberImpl> members,
required this.rightBracket,
}) {
_becomeParentOf(typeParameters);
_becomeParentOf(extendsClause);
_becomeParentOf(withClause);
_becomeParentOf(implementsClause);
_becomeParentOf(nativeClause);
this.members._initialize(this, members);
}
@override
Token get endToken => rightBracket;
@override
Token get firstTokenAfterCommentAndMetadata {
return abstractKeyword ??
macroKeyword ??
sealedKeyword ??
baseKeyword ??
interfaceKeyword ??
finalKeyword ??
augmentKeyword ??
mixinKeyword ??
classKeyword;
}
@Deprecated('Replaced with extension types')
@override
Token? get inlineKeyword {
return null;
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('abstractKeyword', abstractKeyword)
..addToken('macroKeyword', macroKeyword)
..addToken('sealedKeyword', sealedKeyword)
..addToken('baseKeyword', baseKeyword)
..addToken('interfaceKeyword', interfaceKeyword)
..addToken('finalKeyword', finalKeyword)
..addToken('augmentKeyword', augmentKeyword)
..addToken('mixinKeyword', mixinKeyword)
..addToken('classKeyword', classKeyword)
..addToken('name', name)
..addNode('typeParameters', typeParameters)
..addNode('extendsClause', extendsClause)
..addNode('withClause', withClause)
..addNode('implementsClause', implementsClause)
..addToken('leftBracket', leftBracket)
..addNodeList('members', members)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitClassDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
typeParameters?.accept(visitor);
extendsClause?.accept(visitor);
withClause?.accept(visitor);
implementsClause?.accept(visitor);
nativeClause?.accept(visitor);
members.accept(visitor);
}
}
/// A node that declares a name within the scope of a class declarations.
///
/// When the 'extension-methods' experiment is enabled, these nodes can also be
/// located inside extension declarations.
sealed class ClassMember implements Declaration {}
/// A node that declares a name within the scope of a class.
sealed class ClassMemberImpl extends DeclarationImpl implements ClassMember {
/// Initialize a newly created member of a class. Either or both of the
/// [comment] and [metadata] can be `null` if the member does not have the
/// corresponding attribute.
ClassMemberImpl({
required super.comment,
required super.metadata,
});
}
/// A class type alias.
///
/// classTypeAlias ::=
/// classModifiers 'class' [SimpleIdentifier] [TypeParameterList]? '=' mixinApplication
///
/// classModifiers ::= 'sealed'
/// | 'abstract'? ('base' | 'interface' | 'final')?
/// | 'abstract'? 'base'? 'mixin'
///
/// mixinApplication ::=
/// [NamedType] [WithClause] [ImplementsClause]? ';'
abstract final class ClassTypeAlias implements TypeAlias {
/// Return the token for the 'abstract' keyword, or `null` if this is not
/// defining an abstract class.
Token? get abstractKeyword;
/// Return the 'base' keyword, or `null` if the keyword was absent.
Token? get baseKeyword;
@override
ClassElement? get declaredElement;
/// Return the token for the '=' separating the name from the definition.
Token get equals;
/// Return the 'final' keyword, or `null` if the keyword was absent.
Token? get finalKeyword;
/// Return the implements clause for this class, or `null` if there is no
/// implements clause.
ImplementsClause? get implementsClause;
/// Return the 'interface' keyword, or `null` if the keyword was absent.
Token? get interfaceKeyword;
/// Return the 'mixin' keyword, or `null` if the keyword was absent.
Token? get mixinKeyword;
/// Return the 'sealed' keyword, or `null` if the keyword was absent.
Token? get sealedKeyword;
/// Return the name of the superclass of the class being declared.
NamedType get superclass;
/// Return the type parameters for the class, or `null` if the class does not
/// have any type parameters.
TypeParameterList? get typeParameters;
/// Return the with clause for this class.
WithClause get withClause;
}
/// A class type alias.
///
/// classTypeAlias ::=
/// classModifiers 'class' [SimpleIdentifier] [TypeParameterList]? '=' mixinApplication
///
/// classModifiers ::= 'sealed'
/// | 'abstract'? ('base' | 'interface' | 'final')?
/// | 'abstract'? 'base'? 'mixin'
///
/// mixinApplication ::=
/// [NamedType] [WithClause] [ImplementsClause]? ';'
final class ClassTypeAliasImpl extends TypeAliasImpl implements ClassTypeAlias {
/// The type parameters for the class, or `null` if the class does not have
/// any type parameters.
TypeParameterListImpl? _typeParameters;
/// The token for the '=' separating the name from the definition.
@override
final Token equals;
/// The token for the 'abstract' keyword, or `null` if this is not defining an
/// abstract class.
@override
final Token? abstractKeyword;
/// The token for the 'macro' keyword, or `null` if this is not defining a
/// macro class.
final Token? macroKeyword;
/// The token for the 'sealed' keyword, or `null` if this is not defining a
/// sealed class.
@override
final Token? sealedKeyword;
/// The token for the 'base' keyword, or `null` if this is not defining a base
/// class.
@override
final Token? baseKeyword;
/// The token for the 'interface' keyword, or `null` if this is not defining
/// an interface class.
@override
final Token? interfaceKeyword;
/// The token for the 'final' keyword, or `null` if this is not defining a
/// final class.
@override
final Token? finalKeyword;
/// The token for the 'augment' keyword, or `null` if this is not defining an
/// augmentation class.
final Token? augmentKeyword;
/// The token for the 'mixin' keyword, or `null` if this is not defining a
/// mixin class.
@override
final Token? mixinKeyword;
/// The name of the superclass of the class being declared.
NamedTypeImpl _superclass;
/// The with clause for this class.
WithClauseImpl _withClause;
/// The implements clause for this class, or `null` if there is no implements
/// clause.
ImplementsClauseImpl? _implementsClause;
@override
ClassElementImpl? declaredElement;
/// Initialize a newly created class type alias. Either or both of the
/// [comment] and [metadata] can be `null` if the class type alias does not
/// have the corresponding attribute. The [typeParameters] can be `null` if
/// the class does not have any type parameters. The [abstractKeyword] can be
/// `null` if the class is not abstract. The [implementsClause] can be `null`
/// if the class does not implement any interfaces.
ClassTypeAliasImpl({
required super.comment,
required super.metadata,
required super.typedefKeyword,
required super.name,
required TypeParameterListImpl? typeParameters,
required this.equals,
required this.abstractKeyword,
required this.macroKeyword,
required this.sealedKeyword,
required this.baseKeyword,
required this.interfaceKeyword,
required this.finalKeyword,
required this.augmentKeyword,
required this.mixinKeyword,
required NamedTypeImpl superclass,
required WithClauseImpl withClause,
required ImplementsClauseImpl? implementsClause,
required super.semicolon,
}) : _typeParameters = typeParameters,
_superclass = superclass,
_withClause = withClause,
_implementsClause = implementsClause {
_becomeParentOf(_typeParameters);
_becomeParentOf(_superclass);
_becomeParentOf(_withClause);
_becomeParentOf(_implementsClause);
}
@override
Token get firstTokenAfterCommentAndMetadata {
return abstractKeyword ??
macroKeyword ??
sealedKeyword ??
baseKeyword ??
interfaceKeyword ??
finalKeyword ??
augmentKeyword ??
mixinKeyword ??
typedefKeyword;
}
@override
ImplementsClauseImpl? get implementsClause => _implementsClause;
set implementsClause(ImplementsClauseImpl? implementsClause) {
_implementsClause = _becomeParentOf(implementsClause);
}
@override
NamedTypeImpl get superclass => _superclass;
set superclass(NamedTypeImpl superclass) {
_superclass = _becomeParentOf(superclass);
}
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
set typeParameters(TypeParameterListImpl? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters as TypeParameterListImpl);
}
@override
WithClauseImpl get withClause => _withClause;
set withClause(WithClauseImpl withClause) {
_withClause = _becomeParentOf(withClause);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('typedefKeyword', typedefKeyword)
..addToken('name', name)
..addNode('typeParameters', typeParameters)
..addToken('equals', equals)
..addToken('abstractKeyword', abstractKeyword)
..addToken('macroKeyword', macroKeyword)
..addToken('sealedKeyword', sealedKeyword)
..addToken('baseKeyword', baseKeyword)
..addToken('interfaceKeyword', interfaceKeyword)
..addToken('finalKeyword', finalKeyword)
..addToken('augmentKeyword', augmentKeyword)
..addToken('mixinKeyword', mixinKeyword)
..addNode('superclass', superclass)
..addNode('withClause', withClause)
..addNode('implementsClause', implementsClause)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitClassTypeAlias(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_typeParameters?.accept(visitor);
_superclass.accept(visitor);
_withClause.accept(visitor);
_implementsClause?.accept(visitor);
}
}
/// An element in a list, map or set literal.
///
/// collectionElement ::=
/// [Expression]
/// | [IfElement]
/// | [ForElement]
/// | [MapLiteralEntry]
/// | [SpreadElement]
sealed class CollectionElement implements AstNode {}
sealed class CollectionElementImpl extends AstNodeImpl
implements CollectionElement {
/// Dispatches this collection element to the [resolver], with the given
/// [context] information.
void resolveElement(
ResolverVisitor resolver, CollectionLiteralContext? context);
}
/// A combinator associated with an import or export directive.
///
/// combinator ::=
/// [HideCombinator]
/// | [ShowCombinator]
sealed class Combinator implements AstNode {
/// Return the 'hide' or 'show' keyword specifying what kind of processing is
/// to be done on the names.
Token get keyword;
}
/// A combinator associated with an import or export directive.
///
/// combinator ::=
/// [HideCombinator]
/// | [ShowCombinator]
sealed class CombinatorImpl extends AstNodeImpl implements Combinator {
/// The 'hide' or 'show' keyword specifying what kind of processing is to be
/// done on the names.
@override
final Token keyword;
/// Initialize a newly created combinator.
CombinatorImpl({
required this.keyword,
});
@override
Token get beginToken => keyword;
}
/// A comment within the source code.
///
/// comment ::=
/// endOfLineComment
/// | blockComment
/// | documentationComment
///
/// endOfLineComment ::=
/// '//' (CHARACTER - EOL)* EOL
///
/// blockComment ::=
/// '/ *' CHARACTER* '&#42;/'
///
/// documentationComment ::=
/// '/ **' (CHARACTER | [CommentReference])* '&#42;/'
/// | ('///' (CHARACTER - EOL)* EOL)+
abstract final class Comment implements AstNode {
/// The Markdown code blocks (both fenced and indented) parsed in this
/// comment.
@experimental
List<MdCodeBlock> get codeBlocks;
@experimental
List<DocDirective> get docDirectives;
@experimental
List<DocImport> get docImports;
/// Whether this comment has a line beginning with '@nodoc', indicating its
/// contents are not intended for publishing.
@experimental
bool get hasNodoc;
/// Return `true` if this is a block comment.
bool get isBlock;
/// Return `true` if this is a documentation comment.
bool get isDocumentation;
/// Return `true` if this is an end-of-line comment.
bool get isEndOfLine;
/// Return the references embedded within the documentation comment.
NodeList<CommentReference> get references;
/// Return the tokens representing the comment.
List<Token> get tokens;
}
/// A comment within the source code.
///
/// comment ::=
/// endOfLineComment
/// | blockComment
/// | documentationComment
///
/// endOfLineComment ::=
/// '//' (CHARACTER - EOL)* EOL
///
/// blockComment ::=
/// '/ *' CHARACTER* '&#42;/'
///
/// documentationComment ::=
/// '/ **' (CHARACTER | [CommentReference])* '&#42;/'
/// | ('///' (CHARACTER - EOL)* EOL)+
final class CommentImpl extends AstNodeImpl implements Comment {
/// The tokens representing the comment.
@override
final List<Token> tokens;
/// The type of the comment.
final CommentType _type;
/// The references embedded within the documentation comment. This list will
/// be empty unless this is a documentation comment that has references embedded
/// within it.
final NodeListImpl<CommentReferenceImpl> _references = NodeListImpl._();
@override
final List<MdCodeBlock> codeBlocks;
@override
final List<DocImport> docImports;
@override
final List<DocDirective> docDirectives;
@override
final bool hasNodoc;
/// Initialize a newly created comment. The list of [tokens] must contain at
/// least one token. The [_type] is the type of the comment. The list of
/// [references] can be empty if the comment does not contain any embedded
/// references.
CommentImpl({
required this.tokens,
required CommentType type,
required List<CommentReferenceImpl> references,
required this.codeBlocks,
required this.docImports,
required this.docDirectives,
required this.hasNodoc,
}) : _type = type {
_references._initialize(this, references);
}
@override
Token get beginToken => tokens[0];
@override
Token get endToken => tokens[tokens.length - 1];
@override
bool get isBlock => _type == CommentType.BLOCK;
@override
bool get isDocumentation => _type == CommentType.DOCUMENTATION;
@override
bool get isEndOfLine => _type == CommentType.END_OF_LINE;
@override
NodeListImpl<CommentReferenceImpl> get references => _references;
@override
ChildEntities get _childEntities => ChildEntities()
..addNodeList('references', references)
..addTokenList('tokens', tokens);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitComment(this);
@override
void visitChildren(AstVisitor visitor) {
_references.accept(visitor);
}
}
/// An interface for an [Expression] which can make up a [CommentReference].
///
/// commentReferableExpression ::=
/// [ConstructorReference]
/// | [FunctionReference]
/// | [PrefixedIdentifier]
/// | [PropertyAccess]
/// | [SimpleIdentifier]
/// | [TypeLiteral]
///
/// This interface should align closely with dartdoc's notion of
/// comment-referable expressions at:
/// https://github.com/dart-lang/dartdoc/blob/master/lib/src/comment_references/parser.dart
abstract final class CommentReferableExpression implements Expression {}
sealed class CommentReferableExpressionImpl extends ExpressionImpl
implements CommentReferableExpression {}
/// A reference to a Dart element that is found within a documentation comment.
///
/// commentReference ::=
/// '[' 'new'? [CommentReferableExpression] ']'
abstract final class CommentReference implements AstNode {
/// The comment-referable expression being referenced.
CommentReferableExpression get expression;
/// Return the token representing the 'new' keyword, or `null` if there was no
/// 'new' keyword.
Token? get newKeyword;
}
/// A reference to a Dart element that is found within a documentation comment.
///
/// commentReference ::=
/// '[' 'new'? [Identifier] ']'
final class CommentReferenceImpl extends AstNodeImpl
implements CommentReference {
/// The token representing the 'new' keyword, or `null` if there was no 'new'
/// keyword.
@override
final Token? newKeyword;
/// The expression being referenced.
CommentReferableExpressionImpl _expression;
/// Initialize a newly created reference to a Dart element. The [newKeyword]
/// can be `null` if the reference is not to a constructor.
CommentReferenceImpl({
required this.newKeyword,
required CommentReferableExpressionImpl expression,
}) : _expression = expression {
_becomeParentOf(_expression);
}
@override
Token get beginToken => newKeyword ?? _expression.beginToken;
@override
Token get endToken => _expression.endToken;
@override
CommentReferableExpressionImpl get expression => _expression;
set expression(CommentReferableExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('newKeyword', newKeyword)
..addNode('expression', expression);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitCommentReference(this);
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
}
}
/// The possible types of comments that are recognized by the parser.
class CommentType {
/// A block comment.
static const CommentType BLOCK = CommentType('BLOCK');
/// A documentation comment.
static const CommentType DOCUMENTATION = CommentType('DOCUMENTATION');
/// An end-of-line comment.
static const CommentType END_OF_LINE = CommentType('END_OF_LINE');
/// The name of the comment type.
final String name;
/// Initialize a newly created comment type to have the given [name].
const CommentType(this.name);
@override
String toString() => name;
}
/// A compilation unit.
///
/// While the grammar restricts the order of the directives and declarations
/// within a compilation unit, this class does not enforce those restrictions.
/// In particular, the children of a compilation unit will be visited in lexical
/// order even if lexical order does not conform to the restrictions of the
/// grammar.
///
/// compilationUnit ::=
/// directives declarations
///
/// directives ::=
/// [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
/// | [PartOfDirective]
///
/// namespaceDirective ::=
/// [ImportDirective]
/// | [ExportDirective]
///
/// declarations ::=
/// [CompilationUnitMember]*
abstract final class CompilationUnit implements AstNode {
/// Return the declarations contained in this compilation unit.
NodeList<CompilationUnitMember> get declarations;
/// Return the element associated with this compilation unit, or `null` if the
/// AST structure has not been resolved.
CompilationUnitElement? get declaredElement;
/// Return the directives contained in this compilation unit.
NodeList<Directive> get directives;
/// The set of features available to this compilation unit.
///
/// Determined by some combination of the .packages file, the enclosing
/// package's SDK version constraint, and/or the presence of a `@dart`
/// directive in a comment at the top of the file.
FeatureSet get featureSet;
/// The language version override specified for this compilation unit using a
/// token like '// @dart = 2.7', or `null` if no override is specified.
LanguageVersionToken? get languageVersionToken;
/// Return the line information for this compilation unit.
LineInfo get lineInfo;
/// Return the script tag at the beginning of the compilation unit, or `null`
/// if there is no script tag in this compilation unit.
ScriptTag? get scriptTag;
/// Return a list containing all of the directives and declarations in this
/// compilation unit, sorted in lexical order.
List<AstNode> get sortedDirectivesAndDeclarations;
}
/// A compilation unit.
///
/// While the grammar restricts the order of the directives and declarations
/// within a compilation unit, this class does not enforce those restrictions.
/// In particular, the children of a compilation unit will be visited in lexical
/// order even if lexical order does not conform to the restrictions of the
/// grammar.
///
/// compilationUnit ::=
/// directives declarations
///
/// directives ::=
/// [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
/// | [PartOfDirective]
///
/// namespaceDirective ::=
/// [ImportDirective]
/// | [ExportDirective]
///
/// declarations ::=
/// [CompilationUnitMember]*
final class CompilationUnitImpl extends AstNodeImpl implements CompilationUnit {
/// The first token in the token stream that was parsed to form this
/// compilation unit.
@override
Token beginToken;
/// The script tag at the beginning of the compilation unit, or `null` if
/// there is no script tag in this compilation unit.
ScriptTagImpl? _scriptTag;
/// The directives contained in this compilation unit.
final NodeListImpl<DirectiveImpl> _directives = NodeListImpl._();
/// The declarations contained in this compilation unit.
final NodeListImpl<CompilationUnitMemberImpl> _declarations =
NodeListImpl._();
/// The last token in the token stream that was parsed to form this
/// compilation unit. This token should always have a type of [TokenType.EOF].
@override
final Token endToken;
/// The element associated with this compilation unit, or `null` if the AST
/// structure has not been resolved.
@override
CompilationUnitElementImpl? declaredElement;
/// The line information for this compilation unit.
@override
final LineInfo lineInfo;
/// The language version information.
LibraryLanguageVersion? languageVersion;
@override
final FeatureSet featureSet;
/// Nodes that were parsed, but happened at locations where they are not
/// allowed. So, instead of dropping them, we remember them here. Quick
/// fixes could look here to determine which source range to remove.
final List<AstNodeImpl> invalidNodes;
/// Initialize a newly created compilation unit to have the given directives
/// and declarations. The [scriptTag] can be `null` if there is no script tag
/// in the compilation unit. The list of [directives] can be `null` if there
/// are no directives in the compilation unit. The list of [declarations] can
/// be `null` if there are no declarations in the compilation unit.
CompilationUnitImpl({
required this.beginToken,
required ScriptTagImpl? scriptTag,
required List<DirectiveImpl>? directives,
required List<CompilationUnitMemberImpl>? declarations,
required this.endToken,
required this.featureSet,
required this.lineInfo,
required this.invalidNodes,
}) : _scriptTag = scriptTag {
_becomeParentOf(_scriptTag);
_directives._initialize(this, directives);
_declarations._initialize(this, declarations);
}
@override
NodeListImpl<CompilationUnitMemberImpl> get declarations => _declarations;
@override
NodeListImpl<DirectiveImpl> get directives => _directives;
@override
LanguageVersionToken? get languageVersionToken {
Token? targetToken = beginToken;
if (targetToken.type == TokenType.SCRIPT_TAG) {
targetToken = targetToken.next;
}
Token? comment = targetToken?.precedingComments;
while (comment != null) {
if (comment is LanguageVersionToken) {
return comment;
}
comment = comment.next;
}
return null;
}
@override
int get length {
final endToken = this.endToken;
return endToken.offset + endToken.length;
}
@override
int get offset => 0;
@override
ScriptTagImpl? get scriptTag => _scriptTag;
set scriptTag(ScriptTagImpl? scriptTag) {
_scriptTag = _becomeParentOf(scriptTag);
}
@override
List<AstNode> get sortedDirectivesAndDeclarations {
return <AstNode>[
..._directives,
..._declarations,
]..sort(AstNode.LEXICAL_ORDER);
}
@override
ChildEntities get _childEntities {
return ChildEntities()
..addNode('scriptTag', scriptTag)
..addNodeList('directives', directives)
..addNodeList('declarations', declarations);
}
/// Return `true` if all of the directives are lexically before any
/// declarations.
bool get _directivesAreBeforeDeclarations {
if (_directives.isEmpty || _declarations.isEmpty) {
return true;
}
Directive lastDirective = _directives[_directives.length - 1];
CompilationUnitMember firstDeclaration = _declarations[0];
return lastDirective.offset < firstDeclaration.offset;
}
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitCompilationUnit(this);
@override
void visitChildren(AstVisitor visitor) {
_scriptTag?.accept(visitor);
if (_directivesAreBeforeDeclarations) {
_directives.accept(visitor);
_declarations.accept(visitor);
} else {
List<AstNode> sortedMembers = sortedDirectivesAndDeclarations;
int length = sortedMembers.length;
for (int i = 0; i < length; i++) {
AstNode child = sortedMembers[i];
child.accept(visitor);
}
}
}
}
/// A node that declares one or more names within the scope of a compilation
/// unit.
///
/// compilationUnitMember ::=
/// [ClassDeclaration]
/// | [MixinDeclaration]
/// | [ExtensionDeclaration]
/// | [EnumDeclaration]
/// | [TypeAlias]
/// | [FunctionDeclaration]
/// | [TopLevelVariableDeclaration]
abstract final class CompilationUnitMember implements Declaration {}
/// A node that declares one or more names within the scope of a compilation
/// unit.
///
/// compilationUnitMember ::=
/// [ClassDeclaration]
/// | [MixinDeclaration]
/// | [ExtensionDeclaration]
/// | [EnumDeclaration]
/// | [TypeAlias]
/// | [FunctionDeclaration]
/// | [TopLevelVariableDeclaration]
sealed class CompilationUnitMemberImpl extends DeclarationImpl
implements CompilationUnitMember {
/// Initialize a newly created generic compilation unit member. Either or both
/// of the [comment] and [metadata] can be `null` if the member does not have
/// the corresponding attribute.
CompilationUnitMemberImpl({
required super.comment,
required super.metadata,
});
}
/// A potentially compound assignment.
///
/// A compound assignment is any node in which a single expression is used to
/// specify both where to access a value to be operated on (the "read") and to
/// specify where to store the result of the operation (the "write"). This
/// happens in an [AssignmentExpression] when the assignment operator is a
/// compound assignment operator, and in a [PrefixExpression] or
/// [PostfixExpression] when the operator is an increment operator.
abstract final class CompoundAssignmentExpression implements Expression {
/// The element that is used to read the value.
///
/// If this node is not a compound assignment, this element is `null`.
///
/// In valid code this element can be a [LocalVariableElement], a
/// [ParameterElement], or a [PropertyAccessorElement] getter.
///
/// In invalid code this element is `null`, for example `int += 2`. For
/// recovery [writeElement] is filled, and can be used for navigation.
///
/// This element is `null` if the AST structure has not been resolved, or
/// if the target could not be resolved.
Element? get readElement;
/// The type of the value read with the [readElement].
///
/// If this node is not a compound assignment, this type is `null`.
///
/// In invalid code, e.g. `int += 2`, this type is `dynamic`.
///
/// This type is `null` if the AST structure has not been resolved.
///
/// If the target could not be resolved, this type is `dynamic`.
DartType? get readType;
/// The element that is used to write the result.
///
/// In valid code this is a [LocalVariableElement], [ParameterElement], or a
/// [PropertyAccessorElement] setter.
///
/// In invalid code, for recovery, we might use other elements, for example a
/// [PropertyAccessorElement] getter `myGetter = 0` even though the getter
/// cannot be used to write a value. We do this to help the user to navigate
/// to the getter, and maybe add the corresponding setter.
///
/// If this node is a compound assignment, e. g. `x += 2`, both [readElement]
/// and [writeElement] could be not `null`.
///
/// This element is `null` if the AST structure has not been resolved, or
/// if the target could not be resolved.
Element? get writeElement;
/// The types of assigned values must be subtypes of this type.
///
/// If the target could not be resolved, this type is `dynamic`.
DartType? get writeType;
}
base mixin CompoundAssignmentExpressionImpl
implements CompoundAssignmentExpression {
@override
Element? readElement;
@override
Element? writeElement;
@override
DartType? readType;
@override
DartType? writeType;
}
/// A conditional expression.
///
/// conditionalExpression ::=
/// [Expression] '?' [Expression] ':' [Expression]
abstract final class ConditionalExpression implements Expression {
/// Return the token used to separate the then expression from the else
/// expression.
Token get colon;
/// Return the condition used to determine which of the expressions is
/// executed next.
Expression get condition;
/// Return the expression that is executed if the condition evaluates to
/// `false`.
Expression get elseExpression;
/// Return the token used to separate the condition from the then expression.
Token get question;
/// Return the expression that is executed if the condition evaluates to
/// `true`.
Expression get thenExpression;
}
/// A conditional expression.
///
/// conditionalExpression ::=
/// [Expression] '?' [Expression] ':' [Expression]
final class ConditionalExpressionImpl extends ExpressionImpl
implements ConditionalExpression {
/// The condition used to determine which of the expressions is executed next.
ExpressionImpl _condition;
/// The token used to separate the condition from the then expression.
@override
final Token question;
/// The expression that is executed if the condition evaluates to `true`.
ExpressionImpl _thenExpression;
/// The token used to separate the then expression from the else expression.
@override
final Token colon;
/// The expression that is executed if the condition evaluates to `false`.
ExpressionImpl _elseExpression;
/// Initialize a newly created conditional expression.
ConditionalExpressionImpl({
required ExpressionImpl condition,
required this.question,
required ExpressionImpl thenExpression,
required this.colon,
required ExpressionImpl elseExpression,
}) : _condition = condition,
_thenExpression = thenExpression,
_elseExpression = elseExpression {
_becomeParentOf(_condition);
_becomeParentOf(_thenExpression);
_becomeParentOf(_elseExpression);
}
@override
Token get beginToken => _condition.beginToken;
@override
ExpressionImpl get condition => _condition;
set condition(ExpressionImpl expression) {
_condition = _becomeParentOf(expression);
}
@override
ExpressionImpl get elseExpression => _elseExpression;
set elseExpression(ExpressionImpl expression) {
_elseExpression = _becomeParentOf(expression);
}
@override
Token get endToken => _elseExpression.endToken;
@override
Precedence get precedence => Precedence.conditional;
@override
ExpressionImpl get thenExpression => _thenExpression;
set thenExpression(ExpressionImpl expression) {
_thenExpression = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('condition', condition)
..addToken('question', question)
..addNode('thenExpression', thenExpression)
..addToken('colon', colon)
..addNode('elseExpression', elseExpression);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitConditionalExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitConditionalExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_condition.accept(visitor);
_thenExpression.accept(visitor);
_elseExpression.accept(visitor);
}
}
/// A configuration in either an import or export directive.
///
/// configuration ::=
/// 'if' '(' test ')' uri
///
/// test ::=
/// dottedName ('==' stringLiteral)?
///
/// dottedName ::=
/// identifier ('.' identifier)*
abstract final class Configuration implements AstNode {
/// Return the token for the equal operator, or `null` if the condition does
/// not include an equality test.
Token? get equalToken;
/// Return the token for the 'if' keyword.
Token get ifKeyword;
/// Return the token for the left parenthesis.
Token get leftParenthesis;
/// Return the name of the declared variable whose value is being used in the
/// condition.
DottedName get name;
/// The result of resolving [uri].
DirectiveUri? get resolvedUri;
/// Return the token for the right parenthesis.
Token get rightParenthesis;
/// Return the URI of the implementation library to be used if the condition
/// is true.
StringLiteral get uri;
/// Return the value to which the value of the declared variable will be
/// compared, or `null` if the condition does not include an equality test.
StringLiteral? get value;
}
/// A configuration in either an import or export directive.
///
/// configuration ::=
/// 'if' '(' test ')' uri
///
/// test ::=
/// dottedName ('==' stringLiteral)?
///
/// dottedName ::=
/// identifier ('.' identifier)*
final class ConfigurationImpl extends AstNodeImpl implements Configuration {
@override
final Token ifKeyword;
@override
final Token leftParenthesis;
DottedNameImpl _name;
@override
final Token? equalToken;
StringLiteralImpl? _value;
@override
final Token rightParenthesis;
StringLiteralImpl _uri;
@override
DirectiveUri? resolvedUri;
ConfigurationImpl({
required this.ifKeyword,
required this.leftParenthesis,
required DottedNameImpl name,
required this.equalToken,
required StringLiteralImpl? value,
required this.rightParenthesis,
required StringLiteralImpl uri,
}) : _name = name,
_value = value,
_uri = uri {
_becomeParentOf(_name);
_becomeParentOf(_value);
_becomeParentOf(_uri);
}
@override
Token get beginToken => ifKeyword;
@override
Token get endToken => _uri.endToken;
@override
DottedNameImpl get name => _name;
set name(DottedNameImpl name) {
_name = _becomeParentOf(name);
}
@override
StringLiteralImpl get uri => _uri;
set uri(StringLiteralImpl uri) {
_uri = _becomeParentOf(uri);
}
@override
StringLiteralImpl? get value => _value;
set value(StringLiteralImpl? value) {
_value = _becomeParentOf(value as StringLiteralImpl);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('ifKeyword', ifKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('name', name)
..addToken('equalToken', equalToken)
..addNode('value', value)
..addToken('rightParenthesis', rightParenthesis)
..addNode('uri', uri);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitConfiguration(this);
@override
void visitChildren(AstVisitor visitor) {
_name.accept(visitor);
_value?.accept(visitor);
_uri.accept(visitor);
}
}
/// This class is used as a marker of constant context for initializers
/// of constant fields and top-level variables read from summaries.
final class ConstantContextForExpressionImpl extends AstNodeImpl {
final Element variable;
final ExpressionImpl expression;
ConstantContextForExpressionImpl(this.variable, this.expression) {
_becomeParentOf(expression);
}
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
/// A constant expression being used as a pattern.
///
/// The only expressions that can be validly used as a pattern are
/// - `bool` literals
/// - `double` literals
/// - `int` literals
/// - `null` literals
/// - `String` literals
/// - references to constant variables
/// - constant constructor invocations
/// - constant list literals
/// - constant set or map literals
/// - constant expressions wrapped in parentheses and preceded by the `const`
/// keyword
///
/// This node is also used to recover from cases where a different kind of
/// expression is used as a pattern, so clients need to handle the case where
/// the expression is not one of the valid alternatives.
///
/// constantPattern ::=
/// 'const'? [Expression]
abstract final class ConstantPattern implements DartPattern {
/// Return the `const` keyword, or `null` if the expression is not preceded by
/// the keyword `const`.
Token? get constKeyword;
/// Return the constant expression being used as a pattern.
Expression get expression;
}
/// An expression being used as a pattern.
///
/// The only expressions that can be validly used as a pattern are `bool`,
/// `double`, `int`, `null`, and `String` literals and references to constant
/// variables.
///
/// This node is also used to recover from cases where a different kind of
/// expression is used as a pattern, so clients need to handle the case where
/// the expression is not one of the valid alternatives.
///
/// constantPattern ::=
/// 'const'? [Expression]
final class ConstantPatternImpl extends DartPatternImpl
implements ConstantPattern {
@override
final Token? constKeyword;
ExpressionImpl _expression;
ConstantPatternImpl({
required this.constKeyword,
required ExpressionImpl expression,
}) : _expression = expression {
_becomeParentOf(expression);
}
@override
Token get beginToken => constKeyword ?? expression.beginToken;
@override
Token get endToken => expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
PatternPrecedence get precedence => PatternPrecedence.primary;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('const', constKeyword)
..addNode('expression', expression);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitConstantPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor.analyzeConstantPatternSchema();
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
resolverVisitor.analyzeConstantPattern(context, this, expression);
expression = resolverVisitor.popRewrite()!;
}
@override
void visitChildren(AstVisitor visitor) {
expression.accept(visitor);
}
}
/// A constructor declaration.
///
/// constructorDeclaration ::=
/// constructorSignature [FunctionBody]?
/// | constructorName formalParameterList ':' 'this' ('.' [SimpleIdentifier])? arguments
///
/// constructorSignature ::=
/// 'external'? constructorName formalParameterList initializerList?
/// | 'external'? 'factory' factoryName formalParameterList initializerList?
/// | 'external'? 'const' constructorName formalParameterList initializerList?
///
/// constructorName ::=
/// [SimpleIdentifier] ('.' name)?
///
/// factoryName ::=
/// [Identifier] ('.' [SimpleIdentifier])?
///
/// initializerList ::=
/// ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
abstract final class ConstructorDeclaration implements ClassMember {
/// Return the 'augment' keyword, or `null` if the keyword was absent.
Token? get augmentKeyword;
/// Return the body of the constructor.
FunctionBody get body;
/// Return the token for the 'const' keyword, or `null` if the constructor is
/// not a const constructor.
Token? get constKeyword;
@override
ConstructorElement? get declaredElement;
/// Return the token for the 'external' keyword to the given [token].
Token? get externalKeyword;
/// Return the token for the 'factory' keyword, or `null` if the constructor
/// is not a factory constructor.
Token? get factoryKeyword;
/// Return the initializers associated with the constructor.
NodeList<ConstructorInitializer> get initializers;
/// Return the name of the constructor, or `null` if the constructor being
/// declared is unnamed.
Token? get name;
/// Return the parameters associated with the constructor.
FormalParameterList get parameters;
/// Return the token for the period before the constructor name, or `null` if
/// the constructor being declared is unnamed.
Token? get period;
/// Return the name of the constructor to which this constructor will be
/// redirected, or `null` if this is not a redirecting factory constructor.
ConstructorName? get redirectedConstructor;
/// Return the type of object being created.
///
/// This can be different than the type in which the constructor is being
/// declared if the constructor is the implementation of a factory
/// constructor.
Identifier get returnType;
/// Return the token for the separator (colon or equals) before the
/// initializer list or redirection, or `null` if there are no initializers.
Token? get separator;
}
/// A constructor declaration.
///
/// constructorDeclaration ::=
/// constructorSignature [FunctionBody]?
/// | constructorName formalParameterList ':' 'this'
/// ('.' [SimpleIdentifier])? arguments
///
/// constructorSignature ::=
/// 'external'? constructorName formalParameterList initializerList?
/// | 'external'? 'factory' factoryName formalParameterList
/// initializerList?
/// | 'external'? 'const' constructorName formalParameterList
/// initializerList?
///
/// constructorName ::=
/// [SimpleIdentifier] ('.' [SimpleIdentifier])?
///
/// factoryName ::=
/// [Identifier] ('.' [SimpleIdentifier])?
///
/// initializerList ::=
/// ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
final class ConstructorDeclarationImpl extends ClassMemberImpl
implements ConstructorDeclaration {
@override
final Token? augmentKeyword;
/// The token for the 'external' keyword, or `null` if the constructor is not
/// external.
@override
final Token? externalKeyword;
/// The token for the 'const' keyword, or `null` if the constructor is not a
/// const constructor.
@override
Token? constKeyword;
/// The token for the 'factory' keyword, or `null` if the constructor is not a
/// factory constructor.
@override
final Token? factoryKeyword;
/// The type of object being created. This can be different than the type in
/// which the constructor is being declared if the constructor is the
/// implementation of a factory constructor.
IdentifierImpl _returnType;
/// The token for the period before the constructor name, or `null` if the
/// constructor being declared is unnamed.
@override
final Token? period;
/// The name of the constructor, or `null` if the constructor being declared
/// is unnamed.
@override
final Token? name;
/// The parameters associated with the constructor.
FormalParameterListImpl _parameters;
/// The token for the separator (colon or equals) before the initializer list
/// or redirection, or `null` if there are no initializers.
@override
Token? separator;
/// The initializers associated with the constructor.
final NodeListImpl<ConstructorInitializerImpl> _initializers =
NodeListImpl._();
/// The name of the constructor to which this constructor will be redirected,
/// or `null` if this is not a redirecting factory constructor.
ConstructorNameImpl? _redirectedConstructor;
/// The body of the constructor.
FunctionBodyImpl _body;
/// The element associated with this constructor, or `null` if the AST
/// structure has not been resolved or if this constructor could not be
/// resolved.
@override
ConstructorElementImpl? declaredElement;
/// Initialize a newly created constructor declaration. The [externalKeyword]
/// can be `null` if the constructor is not external. Either or both of the
/// [comment] and [metadata] can be `null` if the constructor does not have
/// the corresponding attribute. The [constKeyword] can be `null` if the
/// constructor cannot be used to create a constant. The [factoryKeyword] can
/// be `null` if the constructor is not a factory. The [period] and [name] can
/// both be `null` if the constructor is not a named constructor. The
/// [separator] can be `null` if the constructor does not have any
/// initializers and does not redirect to a different constructor. The list of
/// [initializers] can be `null` if the constructor does not have any
/// initializers. The [redirectedConstructor] can be `null` if the constructor
/// does not redirect to a different constructor. The [body] can be `null` if
/// the constructor does not have a body.
ConstructorDeclarationImpl({
required super.comment,
required super.metadata,
required this.augmentKeyword,
required this.externalKeyword,
required this.constKeyword,
required this.factoryKeyword,
required IdentifierImpl returnType,
required this.period,
required this.name,
required FormalParameterListImpl parameters,
required this.separator,
required List<ConstructorInitializerImpl>? initializers,
required ConstructorNameImpl? redirectedConstructor,
required FunctionBodyImpl body,
}) : _returnType = returnType,
_parameters = parameters,
_redirectedConstructor = redirectedConstructor,
_body = body {
_becomeParentOf(_returnType);
_becomeParentOf(_parameters);
_initializers._initialize(this, initializers);
_becomeParentOf(_redirectedConstructor);
_becomeParentOf(_body);
}
@override
FunctionBodyImpl get body => _body;
set body(FunctionBodyImpl functionBody) {
_body = _becomeParentOf(functionBody);
}
@override
Token get endToken {
return _body.endToken;
}
@override
Token get firstTokenAfterCommentAndMetadata {
return Token.lexicallyFirst(
externalKeyword, constKeyword, factoryKeyword) ??
_returnType.beginToken;
}
@override
NodeListImpl<ConstructorInitializerImpl> get initializers => _initializers;
// A trivial constructor is a generative constructor that is not a
// redirecting constructor, declares no parameters, has no
// initializer list, has no body, and is not external.
bool get isTrivial =>
redirectedConstructor == null &&
parameters.parameters.isEmpty &&
initializers.isEmpty &&
body is EmptyFunctionBody &&
externalKeyword == null;
@override
FormalParameterListImpl get parameters => _parameters;
set parameters(FormalParameterListImpl parameters) {
_parameters = _becomeParentOf(parameters);
}
@override
ConstructorNameImpl? get redirectedConstructor => _redirectedConstructor;
set redirectedConstructor(ConstructorNameImpl? redirectedConstructor) {
_redirectedConstructor =
_becomeParentOf(redirectedConstructor as ConstructorNameImpl);
}
@override
IdentifierImpl get returnType => _returnType;
set returnType(IdentifierImpl typeName) {
_returnType = _becomeParentOf(typeName);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('augmentKeyword', augmentKeyword)
..addToken('externalKeyword', externalKeyword)
..addToken('constKeyword', constKeyword)
..addToken('factoryKeyword', factoryKeyword)
..addNode('returnType', returnType)
..addToken('period', period)
..addToken('name', name)
..addNode('parameters', parameters)
..addToken('separator', separator)
..addNodeList('initializers', initializers)
..addNode('redirectedConstructor', redirectedConstructor)
..addNode('body', body);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitConstructorDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_returnType.accept(visitor);
_parameters.accept(visitor);
_initializers.accept(visitor);
_redirectedConstructor?.accept(visitor);
_body.accept(visitor);
}
}
/// The initialization of a field within a constructor's initialization list.
///
/// fieldInitializer ::=
/// ('this' '.')? [SimpleIdentifier] '=' [Expression]
abstract final class ConstructorFieldInitializer
implements ConstructorInitializer {
/// Return the token for the equal sign between the field name and the
/// expression.
Token get equals;
/// Return the expression computing the value to which the field will be
/// initialized.
Expression get expression;
/// Return the name of the field being initialized.
SimpleIdentifier get fieldName;
/// Return the token for the period after the 'this' keyword, or `null` if
/// there is no 'this' keyword.
Token? get period;
/// Return the token for the 'this' keyword, or `null` if there is no 'this'
/// keyword.
Token? get thisKeyword;
}
/// The initialization of a field within a constructor's initialization list.
///
/// fieldInitializer ::=
/// ('this' '.')? [SimpleIdentifier] '=' [Expression]
final class ConstructorFieldInitializerImpl extends ConstructorInitializerImpl
implements ConstructorFieldInitializer {
/// The token for the 'this' keyword, or `null` if there is no 'this' keyword.
@override
final Token? thisKeyword;
/// The token for the period after the 'this' keyword, or `null` if there is
/// no 'this' keyword.
@override
final Token? period;
/// The name of the field being initialized.
SimpleIdentifierImpl _fieldName;
/// The token for the equal sign between the field name and the expression.
@override
final Token equals;
/// The expression computing the value to which the field will be initialized.
ExpressionImpl _expression;
/// Initialize a newly created field initializer to initialize the field with
/// the given name to the value of the given expression. The [thisKeyword] and
/// [period] can be `null` if the 'this' keyword was not specified.
ConstructorFieldInitializerImpl({
required this.thisKeyword,
required this.period,
required SimpleIdentifierImpl fieldName,
required this.equals,
required ExpressionImpl expression,
}) : _fieldName = fieldName,
_expression = expression {
_becomeParentOf(_fieldName);
_becomeParentOf(_expression);
}
@override
Token get beginToken {
if (thisKeyword case final thisKeyword?) {
return thisKeyword;
}
return _fieldName.beginToken;
}
@override
Token get endToken => _expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
SimpleIdentifierImpl get fieldName => _fieldName;
set fieldName(SimpleIdentifierImpl identifier) {
_fieldName = _becomeParentOf(identifier);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('thisKeyword', thisKeyword)
..addToken('period', period)
..addNode('fieldName', fieldName)
..addToken('equals', equals)
..addNode('expression', expression);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitConstructorFieldInitializer(this);
@override
void visitChildren(AstVisitor visitor) {
_fieldName.accept(visitor);
_expression.accept(visitor);
}
}
/// A node that can occur in the initializer list of a constructor declaration.
///
/// constructorInitializer ::=
/// [SuperConstructorInvocation]
/// | [ConstructorFieldInitializer]
/// | [RedirectingConstructorInvocation]
sealed class ConstructorInitializer implements AstNode {}
/// A node that can occur in the initializer list of a constructor declaration.
///
/// constructorInitializer ::=
/// [SuperConstructorInvocation]
/// | [ConstructorFieldInitializer]
/// | [RedirectingConstructorInvocation]
sealed class ConstructorInitializerImpl extends AstNodeImpl
implements ConstructorInitializer {}
/// The name of a constructor.
///
/// constructorName ::=
/// type ('.' identifier)?
abstract final class ConstructorName
implements AstNode, ConstructorReferenceNode {
/// Return the name of the constructor, or `null` if the specified constructor
/// is the unnamed constructor.
SimpleIdentifier? get name;
/// Return the token for the period before the constructor name, or `null` if
/// the specified constructor is the unnamed constructor.
Token? get period;
/// Return the name of the type defining the constructor.
NamedType get type;
}
/// The name of the constructor.
///
/// constructorName ::=
/// type ('.' identifier)?
final class ConstructorNameImpl extends AstNodeImpl implements ConstructorName {
/// The name of the type defining the constructor.
NamedTypeImpl _type;
/// The token for the period before the constructor name, or `null` if the
/// specified constructor is the unnamed constructor.
@override
Token? period;
/// The name of the constructor, or `null` if the specified constructor is the
/// unnamed constructor.
SimpleIdentifierImpl? _name;
/// The element associated with this constructor name based on static type
/// information, or `null` if the AST structure has not been resolved or if
/// this constructor name could not be resolved.
@override
ConstructorElement? staticElement;
/// Initialize a newly created constructor name. The [period] and [name] can
/// be`null` if the constructor being named is the unnamed constructor.
ConstructorNameImpl({
required NamedTypeImpl type,
required this.period,
required SimpleIdentifierImpl? name,
}) : _type = type,
_name = name {
_becomeParentOf(_type);
_becomeParentOf(_name);
}
@override
Token get beginToken => _type.beginToken;
@override
Token get endToken {
if (name case final name?) {
return name.endToken;
}
return _type.endToken;
}
@override
SimpleIdentifierImpl? get name => _name;
set name(SimpleIdentifierImpl? name) {
_name = _becomeParentOf(name);
}
@override
NamedTypeImpl get type => _type;
set type(NamedTypeImpl type) {
_type = _becomeParentOf(type);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('type', type)
..addToken('period', period)
..addNode('name', name);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitConstructorName(this);
@override
void visitChildren(AstVisitor visitor) {
_type.accept(visitor);
_name?.accept(visitor);
}
}
/// An expression representing a reference to a constructor, e.g. the expression
/// `List.filled` in `var x = List.filled;`.
///
/// Objects of this type are not produced directly by the parser (because the
/// parser cannot tell whether an identifier refers to a type); they are
/// produced at resolution time.
abstract final class ConstructorReference
implements Expression, CommentReferableExpression {
/// The constructor being referenced.
ConstructorName get constructorName;
}
/// An expression representing a reference to a constructor, e.g. the expression
/// `List.filled` in `var x = List.filled;`.
///
/// Objects of this type are not produced directly by the parser (because the
/// parser cannot tell whether an identifier refers to a type); they are
/// produced at resolution time.
final class ConstructorReferenceImpl extends CommentReferableExpressionImpl
implements ConstructorReference {
ConstructorNameImpl _constructorName;
ConstructorReferenceImpl({
required ConstructorNameImpl constructorName,
}) : _constructorName = constructorName {
_becomeParentOf(_constructorName);
}
@override
Token get beginToken => constructorName.beginToken;
@override
ConstructorNameImpl get constructorName => _constructorName;
set constructorName(ConstructorNameImpl value) {
_constructorName = _becomeParentOf(value);
}
@override
Token get endToken => constructorName.endToken;
@override
Precedence get precedence => Precedence.postfix;
@override
ChildEntities get _childEntities =>
ChildEntities()..addNode('constructorName', constructorName);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitConstructorReference(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitConstructorReference(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
constructorName.accept(visitor);
}
}
/// An AST node that makes reference to a constructor.
abstract final class ConstructorReferenceNode implements AstNode {
/// Return the element associated with the referenced constructor based on
/// static type information, or `null` if the AST structure has not been
/// resolved or if the constructor could not be resolved.
ConstructorElement? get staticElement;
}
/// The name of a constructor being invoked.
///
/// constructorSelector ::=
/// '.' identifier
abstract final class ConstructorSelector implements AstNode {
/// Return the constructor name.
SimpleIdentifier get name;
/// Return the period before the constructor name.
Token get period;
}
final 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
Token get endToken => name.token;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('period', period)
..addNode('name', name);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitConstructorSelector(this);
}
@override
void visitChildren(AstVisitor visitor) {}
}
/// A continue statement.
///
/// continueStatement ::=
/// 'continue' [SimpleIdentifier]? ';'
abstract final class ContinueStatement implements Statement {
/// Return the token representing the 'continue' keyword.
Token get continueKeyword;
/// Return the label associated with the statement, or `null` if there is no
/// label.
SimpleIdentifier? get label;
/// Return the semicolon terminating the statement.
Token get semicolon;
/// Return the node to which this continue statement is continuing.
///
/// This will be either a [Statement] (in the case of continuing a loop), a
/// [SwitchMember] (in the case of continuing from one switch case to
/// another), or `null` if the AST has not yet been resolved or if the target
/// could not be resolved. Note that if the source code has errors, the
/// target might be invalid (e.g. the target may be in an enclosing
/// function).
AstNode? get target;
}
/// A continue statement.
///
/// continueStatement ::=
/// 'continue' [SimpleIdentifier]? ';'
final class ContinueStatementImpl extends StatementImpl
implements ContinueStatement {
/// The token representing the 'continue' keyword.
@override
final Token continueKeyword;
/// The label associated with the statement, or `null` if there is no label.
SimpleIdentifierImpl? _label;
/// The semicolon terminating the statement.
@override
final Token semicolon;
/// The AstNode which this continue statement is continuing to. This will be
/// either a Statement (in the case of continuing a loop) or a SwitchMember
/// (in the case of continuing from one switch case to another). Null if the
/// AST has not yet been resolved or if the target could not be resolved.
/// Note that if the source code has errors, the target may be invalid (e.g.
/// the target may be in an enclosing function).
@override
AstNode? target;
/// Initialize a newly created continue statement. The [label] can be `null`
/// if there is no label associated with the statement.
ContinueStatementImpl({
required this.continueKeyword,
required SimpleIdentifierImpl? label,
required this.semicolon,
}) : _label = label {
_becomeParentOf(_label);
}
@override
Token get beginToken => continueKeyword;
@override
Token get endToken => semicolon;
@override
SimpleIdentifierImpl? get label => _label;
set label(SimpleIdentifierImpl? identifier) {
_label = _becomeParentOf(identifier);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('continueKeyword', continueKeyword)
..addNode('label', label)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitContinueStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_label?.accept(visitor);
}
}
/// A pattern.
///
/// pattern ::=
/// [AssignedVariablePattern]
/// | [DeclaredVariablePattern]
/// | [CastPattern]
/// | [ConstantPattern]
/// | [ListPattern]
/// | [LogicalAndPattern]
/// | [LogicalOrPattern]
/// | [MapPattern]
/// | [NullAssertPattern]
/// | [NullCheckPattern]
/// | [ObjectPattern]
/// | [ParenthesizedPattern]
/// | [RecordPattern]
/// | [RelationalPattern]
sealed class DartPattern implements AstNode, ListPatternElement {
/// The matched value type, or `null` if the node is not resolved yet.
DartType? get matchedValueType;
/// Return the precedence of this pattern.
///
/// The precedence is a positive integer value that defines how the source
/// code is parsed into an AST. For example `a | b & c` is parsed as `a | (b
/// & c)` because the precedence of `&` is greater than the precedence of `|`.
PatternPrecedence get precedence;
/// If this pattern is a parenthesized pattern, return the result of
/// unwrapping the pattern inside the parentheses. Otherwise, return this
/// pattern.
DartPattern get unParenthesized;
}
/// A pattern.
///
/// pattern ::=
/// [AssignedVariablePattern]
/// | [DeclaredVariablePattern]
/// | [CastPattern]
/// | [ConstantPattern]
/// | [ListPattern]
/// | [LogicalAndPattern]
/// | [LogicalOrPattern]
/// | [MapPattern]
/// | [NullAssertPattern]
/// | [NullCheckPattern]
/// | [ObjectPattern]
/// | [ParenthesizedPattern]
/// | [RecordPattern]
/// | [RelationalPattern]
sealed class DartPatternImpl extends AstNodeImpl
implements DartPattern, ListPatternElementImpl {
@override
DartType? matchedValueType;
/// Returns the context for this pattern.
/// * Declaration context:
/// [ForEachPartsWithPatternImpl]
/// [PatternVariableDeclarationImpl]
/// * Assignment context: [PatternAssignmentImpl]
/// * Matching context: [GuardedPatternImpl]
AstNodeImpl? get patternContext {
for (DartPatternImpl current = this;;) {
var parent = current.parent;
if (parent is MapPatternEntry) {
parent = parent.parent;
} else if (parent is PatternFieldImpl) {
parent = parent.parent;
} else if (parent is RestPatternElementImpl) {
parent = parent.parent;
}
if (parent is ForEachPartsWithPatternImpl) {
return parent;
} else if (parent is PatternVariableDeclarationImpl) {
return parent;
} else if (parent is PatternAssignmentImpl) {
return parent;
} else if (parent is GuardedPatternImpl) {
return parent;
} else if (parent is DartPatternImpl) {
current = parent;
} else {
return null;
}
}
}
@override
DartPattern get unParenthesized => this;
/// The variable pattern, itself, or wrapped in a unary pattern.
VariablePatternImpl? get variablePattern => null;
DartType computePatternSchema(ResolverVisitor resolverVisitor);
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
);
}
/// A node that represents the declaration of one or more names.
///
/// Each declared name is visible within a name scope.
abstract final class Declaration implements AnnotatedNode {
/// Return the element associated with this declaration, or `null` if either
/// this node corresponds to a list of declarations or if the AST structure
/// has not been resolved.
Element? get declaredElement;
}
/// A node that represents the declaration of one or more names. Each declared
/// name is visible within a name scope.
sealed class DeclarationImpl extends AnnotatedNodeImpl implements Declaration {
/// Initialize a newly created declaration. Either or both of the [comment]
/// and [metadata] can be `null` if the declaration does not have the
/// corresponding attribute.
DeclarationImpl({
required super.comment,
required super.metadata,
});
}
/// The declaration of a single identifier.
///
/// declaredIdentifier ::=
/// [Annotation] finalConstVarOrType [SimpleIdentifier]
abstract final class DeclaredIdentifier implements Declaration {
@override
LocalVariableElement? get declaredElement;
/// Return `true` if this variable was declared with the 'const' modifier.
bool get isConst;
/// Return `true` if this variable was declared with the 'final' modifier.
/// Variables that are declared with the 'const' modifier will return `false`
/// even though they are implicitly final.
bool get isFinal;
/// Return the token representing either the 'final', 'const' or 'var'
/// keyword, or `null` if no keyword was used.
Token? get keyword;
/// Return the name of the variable being declared.
Token get name;
/// Return the name of the declared type of the parameter, or `null` if the
/// parameter does not have a declared type.
TypeAnnotation? get type;
}
/// The declaration of a single identifier.
///
/// declaredIdentifier ::=
/// [Annotation] finalConstVarOrType [SimpleIdentifier]
final class DeclaredIdentifierImpl extends DeclarationImpl
implements DeclaredIdentifier {
/// The token representing either the 'final', 'const' or 'var' keyword, or
/// `null` if no keyword was used.
@override
final Token? keyword;
/// The name of the declared type of the parameter, or `null` if the parameter
/// does not have a declared type.
TypeAnnotationImpl? _type;
@override
final Token name;
@override
LocalVariableElementImpl? declaredElement;
/// Initialize a newly created formal parameter. Either or both of the
/// [comment] and [metadata] can be `null` if the declaration does not have
/// the corresponding attribute. The [keyword] can be `null` if a type name is
/// given. The [type] must be `null` if the keyword is 'var'.
DeclaredIdentifierImpl({
required super.comment,
required super.metadata,
required this.keyword,
required TypeAnnotationImpl? type,
required this.name,
}) : _type = type {
_becomeParentOf(_type);
}
@override
Token get endToken => name;
@override
Token get firstTokenAfterCommentAndMetadata {
return keyword ?? _type?.beginToken ?? name;
}
@override
bool get isConst => keyword?.keyword == Keyword.CONST;
@override
bool get isFinal => keyword?.keyword == Keyword.FINAL;
@override
TypeAnnotationImpl? get type => _type;
set type(TypeAnnotationImpl? type) {
_type = _becomeParentOf(type);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('keyword', keyword)
..addNode('type', type)
..addToken('name', name);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitDeclaredIdentifier(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_type?.accept(visitor);
}
}
/// A variable pattern that declares a variable.
///
/// variablePattern ::=
/// ( 'var' | 'final' | 'final'? [TypeAnnotation])? [Identifier]
sealed class DeclaredVariablePattern implements VariablePattern {
/// Return the element associated with this declaration, or `null` if the AST
/// structure has not been resolved.
BindPatternVariableElement? get declaredElement;
/// The 'var' or 'final' keyword.
Token? get keyword;
/// The type that the variable is required to match, or `null` if any type is
/// matched.
TypeAnnotation? get type;
}
/// A variable pattern.
///
/// variablePattern ::=
/// ( 'var' | 'final' | 'final'? [TypeAnnotation])? [Identifier]
final class DeclaredVariablePatternImpl extends VariablePatternImpl
implements DeclaredVariablePattern {
@override
BindPatternVariableElementImpl? declaredElement;
@override
final Token? keyword;
@override
final TypeAnnotationImpl? type;
DeclaredVariablePatternImpl({
required this.keyword,
required this.type,
required super.name,
}) {
_becomeParentOf(type);
}
@override
Token get beginToken => keyword ?? type?.beginToken ?? name;
@override
Token get endToken => name;
/// If [keyword] is `final`, returns it.
Token? get finalKeyword {
final keyword = this.keyword;
if (keyword != null && keyword.keyword == Keyword.FINAL) {
return keyword;
}
return null;
}
@override
PatternPrecedence get precedence => PatternPrecedence.primary;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('keyword', keyword)
..addNode('type', type)
..addToken('name', name);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitDeclaredVariablePattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor
.analyzeDeclaredVariablePatternSchema(type?.typeOrThrow);
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
final result = resolverVisitor.analyzeDeclaredVariablePattern(context, this,
declaredElement!, declaredElement!.name, type?.typeOrThrow);
declaredElement!.type = result.staticType;
resolverVisitor.checkPatternNeverMatchesValueType(
context: context,
pattern: this,
requiredType: result.staticType,
);
}
@override
void visitChildren(AstVisitor visitor) {
type?.accept(visitor);
}
}
/// A formal parameter with a default value.
///
/// There are two kinds of parameters that are both represented by this class:
/// named formal parameters and positional formal parameters.
///
/// defaultFormalParameter ::=
/// [NormalFormalParameter] ('=' [Expression])?
///
/// defaultNamedParameter ::=
/// [NormalFormalParameter] (':' [Expression])?
abstract final class DefaultFormalParameter implements FormalParameter {
/// Return the expression computing the default value for the parameter, or
/// `null` if there is no default value.
Expression? get defaultValue;
/// Return the formal parameter with which the default value is associated.
NormalFormalParameter get parameter;
/// Return the token separating the parameter from the default value, or
/// `null` if there is no default value.
Token? get separator;
}
/// A formal parameter with a default value. There are two kinds of parameters
/// that are both represented by this class: named formal parameters and
/// positional formal parameters.
///
/// defaultFormalParameter ::=
/// [NormalFormalParameter] ('=' [Expression])?
///
/// defaultNamedParameter ::=
/// [NormalFormalParameter] (':' [Expression])?
final class DefaultFormalParameterImpl extends FormalParameterImpl
implements DefaultFormalParameter {
/// The formal parameter with which the default value is associated.
NormalFormalParameterImpl _parameter;
/// The kind of this parameter.
@override
ParameterKind kind;
/// The token separating the parameter from the default value, or `null` if
/// there is no default value.
@override
final Token? separator;
/// The expression computing the default value for the parameter, or `null` if
/// there is no default value.
ExpressionImpl? _defaultValue;
/// Initialize a newly created default formal parameter. The [separator] and
/// [defaultValue] can be `null` if there is no default value.
DefaultFormalParameterImpl({
required NormalFormalParameterImpl parameter,
required this.kind,
required this.separator,
required ExpressionImpl? defaultValue,
}) : _parameter = parameter,
_defaultValue = defaultValue {
_becomeParentOf(_parameter);
_becomeParentOf(_defaultValue);
}
@override
Token get beginToken => _parameter.beginToken;
@override
Token? get covariantKeyword => null;
@override
ParameterElementImpl? get declaredElement => _parameter.declaredElement;
@override
ExpressionImpl? get defaultValue => _defaultValue;
set defaultValue(ExpressionImpl? expression) {
_defaultValue = _becomeParentOf(expression);
}
@override
Token get endToken {
if (defaultValue case final defaultValue?) {
return defaultValue.endToken;
}
return _parameter.endToken;
}
@override
bool get isConst => _parameter.isConst;
@override
bool get isExplicitlyTyped => _parameter.isExplicitlyTyped;
@override
bool get isFinal => _parameter.isFinal;
@override
NodeListImpl<AnnotationImpl> get metadata => _parameter.metadata;
@override
Token? get name => _parameter.name;
@override
NormalFormalParameterImpl get parameter => _parameter;
set parameter(NormalFormalParameterImpl formalParameter) {
_parameter = _becomeParentOf(formalParameter);
}
@override
Token? get requiredKeyword => null;
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('parameter', parameter)
..addToken('separator', separator)
..addNode('defaultValue', defaultValue);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitDefaultFormalParameter(this);
@override
void visitChildren(AstVisitor visitor) {
_parameter.accept(visitor);
_defaultValue?.accept(visitor);
}
}
/// A node that represents a directive.
///
/// directive ::=
/// [ExportDirective]
/// | [ImportDirective]
/// | [LibraryDirective]
/// | [PartDirective]
/// | [PartOfDirective]
sealed class Directive implements AnnotatedNode {
/// Return the element associated with this directive, or `null` if the AST
/// structure has not been resolved.
Element? get element;
}
/// A node that represents a directive.
///
/// directive ::=
/// [AugmentationImportDirective]
/// | [ExportDirective]
/// | [ImportDirective]
/// | [LibraryDirective]
/// | [PartDirective]
/// | [PartOfDirective]
sealed class DirectiveImpl extends AnnotatedNodeImpl implements Directive {
/// The element associated with this directive, or `null` if the AST structure
/// has not been resolved or if this directive could not be resolved.
Element? _element;
/// Initialize a newly create directive. Either or both of the [comment] and
/// [metadata] can be `null` if the directive does not have the corresponding
/// attribute.
DirectiveImpl({
required super.comment,
required super.metadata,
});
@override
Element? get element => _element;
/// Set the element associated with this directive to be the given [element].
set element(Element? element) {
_element = element;
}
}
/// A do statement.
///
/// doStatement ::=
/// 'do' [Statement] 'while' '(' [Expression] ')' ';'
abstract final class DoStatement implements Statement {
/// Return the body of the loop.
Statement get body;
/// Return the condition that determines when the loop will terminate.
Expression get condition;
/// Return the token representing the 'do' keyword.
Token get doKeyword;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right parenthesis.
Token get rightParenthesis;
/// Return the semicolon terminating the statement.
Token get semicolon;
/// Return the token representing the 'while' keyword.
Token get whileKeyword;
}
/// A do statement.
///
/// doStatement ::=
/// 'do' [Statement] 'while' '(' [Expression] ')' ';'
final class DoStatementImpl extends StatementImpl implements DoStatement {
/// The token representing the 'do' keyword.
@override
final Token doKeyword;
/// The body of the loop.
StatementImpl _body;
/// The token representing the 'while' keyword.
@override
final Token whileKeyword;
/// The left parenthesis.
@override
final Token leftParenthesis;
/// The condition that determines when the loop will terminate.
ExpressionImpl _condition;
/// The right parenthesis.
@override
final Token rightParenthesis;
/// The semicolon terminating the statement.
@override
final Token semicolon;
/// Initialize a newly created do loop.
DoStatementImpl({
required this.doKeyword,
required StatementImpl body,
required this.whileKeyword,
required this.leftParenthesis,
required ExpressionImpl condition,
required this.rightParenthesis,
required this.semicolon,
}) : _body = body,
_condition = condition {
_becomeParentOf(_body);
_becomeParentOf(_condition);
}
@override
Token get beginToken => doKeyword;
@override
StatementImpl get body => _body;
set body(StatementImpl statement) {
_body = _becomeParentOf(statement);
}
@override
ExpressionImpl get condition => _condition;
set condition(ExpressionImpl expression) {
_condition = _becomeParentOf(expression);
}
@override
Token get endToken => semicolon;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('doKeyword', doKeyword)
..addNode('body', body)
..addToken('whileKeyword', whileKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('condition', condition)
..addToken('rightParenthesis', rightParenthesis)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitDoStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_body.accept(visitor);
_condition.accept(visitor);
}
}
/// A dotted name, used in a configuration within an import or export directive.
///
/// dottedName ::=
/// [SimpleIdentifier] ('.' [SimpleIdentifier])*
abstract final class DottedName implements AstNode {
/// Return the components of the identifier.
NodeList<SimpleIdentifier> get components;
}
/// A dotted name, used in a configuration within an import or export directive.
///
/// dottedName ::=
/// [SimpleIdentifier] ('.' [SimpleIdentifier])*
final class DottedNameImpl extends AstNodeImpl implements DottedName {
/// The components of the identifier.
final NodeListImpl<SimpleIdentifierImpl> _components = NodeListImpl._();
/// Initialize a newly created dotted name.
DottedNameImpl({
required List<SimpleIdentifierImpl> components,
}) {
_components._initialize(this, components);
}
@override
Token get beginToken => _components.beginToken!;
@override
NodeListImpl<SimpleIdentifierImpl> get components => _components;
@override
Token get endToken => _components.endToken!;
@override
// TODO(paulberry): add "." tokens.
ChildEntities get _childEntities =>
ChildEntities()..addNodeList('components', components);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitDottedName(this);
@override
void visitChildren(AstVisitor visitor) {
_components.accept(visitor);
}
}
/// A floating point literal expression.
///
/// doubleLiteral ::=
/// decimalDigit+ ('.' decimalDigit*)? exponent?
/// | '.' decimalDigit+ exponent?
///
/// exponent ::=
/// ('e' | 'E') ('+' | '-')? decimalDigit+
abstract final class DoubleLiteral implements Literal {
/// Return the token representing the literal.
Token get literal;
/// Return the value of the literal.
double get value;
}
/// A floating point literal expression.
///
/// doubleLiteral ::=
/// decimalDigit+ ('.' decimalDigit*)? exponent?
/// | '.' decimalDigit+ exponent?
///
/// exponent ::=
/// ('e' | 'E') ('+' | '-')? decimalDigit+
final class DoubleLiteralImpl extends LiteralImpl implements DoubleLiteral {
/// The token representing the literal.
@override
final Token literal;
/// The value of the literal.
@override
double value;
/// Initialize a newly created floating point literal.
DoubleLiteralImpl({
required this.literal,
required this.value,
});
@override
Token get beginToken => literal;
@override
Token get endToken => literal;
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('literal', literal);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitDoubleLiteral(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitDoubleLiteral(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
}
/// An empty function body, which can only appear in constructors or abstract
/// methods.
///
/// emptyFunctionBody ::=
/// ';'
abstract final class EmptyFunctionBody implements FunctionBody {
/// Return the token representing the semicolon that marks the end of the
/// function body.
Token get semicolon;
}
/// An empty function body, which can only appear in constructors or abstract
/// methods.
///
/// emptyFunctionBody ::=
/// ';'
final class EmptyFunctionBodyImpl extends FunctionBodyImpl
implements EmptyFunctionBody {
/// The token representing the semicolon that marks the end of the function
/// body.
@override
final Token semicolon;
/// Initialize a newly created function body.
EmptyFunctionBodyImpl({
required this.semicolon,
});
@override
Token get beginToken => semicolon;
@override
Token get endToken => semicolon;
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitEmptyFunctionBody(this);
@override
DartType resolve(ResolverVisitor resolver, DartType? imposedType) =>
resolver.visitEmptyFunctionBody(this, imposedType: imposedType);
@override
void visitChildren(AstVisitor visitor) {
// Empty function bodies have no children.
}
}
/// An empty statement.
///
/// emptyStatement ::=
/// ';'
abstract final class EmptyStatement implements Statement {
/// Return the semicolon terminating the statement.
Token get semicolon;
}
/// An empty statement.
///
/// emptyStatement ::=
/// ';'
final class EmptyStatementImpl extends StatementImpl implements EmptyStatement {
/// The semicolon terminating the statement.
@override
final Token semicolon;
/// Initialize a newly created empty statement.
EmptyStatementImpl({
required this.semicolon,
});
@override
Token get beginToken => semicolon;
@override
Token get endToken => semicolon;
@override
bool get isSynthetic => semicolon.isSynthetic;
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitEmptyStatement(this);
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
}
/// The arguments part of an enum constant.
///
/// enumConstantArguments ::=
/// [TypeArgumentList]? [ConstructorSelector]? [ArgumentList]
abstract final 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;
}
final 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
Token get endToken => argumentList.endToken;
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('typeArguments', typeArguments)
..addNode('constructorSelector', constructorSelector)
..addNode('argumentList', argumentList);
@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.
abstract final 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;
@override
FieldElement? get declaredElement;
/// Return the name of the constant.
Token get name;
}
/// The declaration of an enum constant.
final class EnumConstantDeclarationImpl extends DeclarationImpl
implements EnumConstantDeclaration {
@override
final Token name;
@override
FieldElementImpl? declaredElement;
@override
final EnumConstantArgumentsImpl? arguments;
@override
ConstructorElement? constructorElement;
/// Initialize a newly created enum constant declaration. Either or both of
/// the [documentationComment] and [metadata] can be `null` if the constant
/// does not have the corresponding attribute.
EnumConstantDeclarationImpl({
required super.comment,
required super.metadata,
required this.name,
required this.arguments,
}) {
_becomeParentOf(arguments);
}
@override
Token get endToken => arguments?.endToken ?? name;
@override
Token get firstTokenAfterCommentAndMetadata => name;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('name', name)
..addNode('arguments', arguments);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitEnumConstantDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
arguments?.accept(visitor);
}
}
/// The declaration of an enumeration.
///
/// enumType ::=
/// metadata 'enum' name [TypeParameterList]?
/// [WithClause]? [ImplementsClause]? '{' [SimpleIdentifier]
/// (',' [SimpleIdentifier])* (';' [ClassMember]+)? '}'
abstract final class EnumDeclaration implements NamedCompilationUnitMember {
/// Return the enumeration constants being declared.
NodeList<EnumConstantDeclaration> get constants;
@override
EnumElement? get declaredElement;
/// 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;
/// Return the members declared by the enumeration.
NodeList<ClassMember> get members;
/// Return the right curly bracket.
Token get rightBracket;
/// Return the optional semicolon after the last constant.
Token? get semicolon;
/// 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;
}
/// The declaration of an enumeration.
///
/// enumType ::=
/// metadata 'enum' [SimpleIdentifier] [TypeParameterList]?
/// [WithClause]? [ImplementsClause]? '{' [SimpleIdentifier]
/// (',' [SimpleIdentifier])* (';' [ClassMember]+)? '}'
final class EnumDeclarationImpl extends NamedCompilationUnitMemberImpl
implements EnumDeclaration {
/// The 'enum' keyword.
@override
final 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
final Token leftBracket;
/// The enumeration constants being declared.
final NodeListImpl<EnumConstantDeclarationImpl> _constants = NodeListImpl._();
@override
final Token? semicolon;
/// The members defined by the enum.
final NodeListImpl<ClassMemberImpl> _members = NodeListImpl._();
/// The right curly bracket.
@override
final Token rightBracket;
@override
EnumElementImpl? declaredElement;
/// Initialize 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.
EnumDeclarationImpl({
required super.comment,
required super.metadata,
required this.enumKeyword,
required super.name,
required TypeParameterListImpl? typeParameters,
required WithClauseImpl? withClause,
required ImplementsClauseImpl? implementsClause,
required this.leftBracket,
required List<EnumConstantDeclarationImpl> constants,
required this.semicolon,
required List<ClassMemberImpl> members,
required this.rightBracket,
}) : _typeParameters = typeParameters,
_withClause = withClause,
_implementsClause = implementsClause {
_becomeParentOf(_typeParameters);
_becomeParentOf(_withClause);
_becomeParentOf(_implementsClause);
_constants._initialize(this, constants);
_members._initialize(this, members);
}
@override
NodeListImpl<EnumConstantDeclarationImpl> get constants => _constants;
@override
Token get endToken => rightBracket;
@override
Token get firstTokenAfterCommentAndMetadata => enumKeyword;
@override
ImplementsClauseImpl? get implementsClause => _implementsClause;
set implementsClause(ImplementsClauseImpl? implementsClause) {
_implementsClause = _becomeParentOf(implementsClause);
}
@override
NodeListImpl<ClassMemberImpl> get members => _members;
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
set typeParameters(TypeParameterListImpl? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters);
}
@override
WithClauseImpl? get withClause => _withClause;
set withClause(WithClauseImpl? withClause) {
_withClause = _becomeParentOf(withClause);
}
@override
// TODO(brianwilkerson): Add commas?
ChildEntities get _childEntities => super._childEntities
..addToken('enumKeyword', enumKeyword)
..addToken('name', name)
..addNode('typeParameters', typeParameters)
..addNode('withClause', withClause)
..addNode('implementsClause', implementsClause)
..addToken('leftBracket', leftBracket)
..addNodeList('constants', constants)
..addToken('semicolon', semicolon)
..addNodeList('members', members)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitEnumDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_typeParameters?.accept(visitor);
_withClause?.accept(visitor);
_implementsClause?.accept(visitor);
_constants.accept(visitor);
_members.accept(visitor);
}
}
/// An export directive.
///
/// exportDirective ::=
/// [Annotation] 'export' [StringLiteral] [Combinator]* ';'
abstract final class ExportDirective implements NamespaceDirective {
/// Return the element associated with this directive, or `null` if the AST
/// structure has not been resolved.
@override
LibraryExportElement? get element;
/// The token representing the 'export' keyword.
Token get exportKeyword;
}
/// An export directive.
///
/// exportDirective ::=
/// [Annotation] 'export' [StringLiteral] [Combinator]* ';'
final class ExportDirectiveImpl extends NamespaceDirectiveImpl
implements ExportDirective {
@override
final Token exportKeyword;
/// Initialize 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
/// are no combinators.
ExportDirectiveImpl({
required super.comment,
required super.metadata,
required this.exportKeyword,
required super.uri,
required super.configurations,
required super.combinators,
required super.semicolon,
});
@override
LibraryExportElementImpl? get element {
return super.element as LibraryExportElementImpl?;
}
@override
Token get firstTokenAfterCommentAndMetadata => exportKeyword;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('exportKeyword', exportKeyword)
..addNode('uri', uri)
..addNodeList('combinators', combinators)
..addNodeList('configurations', configurations)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitExportDirective(this);
@override
void visitChildren(AstVisitor visitor) {
configurations.accept(visitor);
super.visitChildren(visitor);
combinators.accept(visitor);
}
}
/// A node that represents an expression.
///
/// expression ::=
/// [AssignmentExpression]
/// | [ConditionalExpression] cascadeSection*
/// | [ThrowExpression]
abstract final class Expression implements CollectionElement {
/// An expression _e_ is said to _occur in a constant context_,
/// * if _e_ is an element of a constant list literal, or a key or value of an
/// entry of a constant map literal.
/// * if _e_ is an actual argument of a constant object expression or of a
/// metadata annotation.
/// * if _e_ is the initializing expression of a constant variable
/// declaration.
/// * if _e_ is a switch case expression.
/// * if _e_ is an immediate subexpression of an expression _e1_ which occurs
/// in a constant context, unless _e1_ is a `throw` expression or a function
/// literal.
///
/// This roughly means that everything which is inside a syntactically
/// constant expression is in a constant context. A `throw` expression is
/// currently not allowed in a constant expression, but extensions affecting
/// that status may be considered. A similar situation arises for function
/// literals.
///
/// Note that the default value of an optional formal parameter is _not_ a
/// constant context. This choice reserves some freedom to modify the
/// semantics of default values.
bool get inConstantContext;
/// Return `true` if this expression is syntactically valid for the LHS of an
/// [AssignmentExpression].
bool get isAssignable;
/// Return the precedence of this expression.
///
/// The precedence is a positive integer value that defines how the source
/// code is parsed into an AST. For example `a * b + c` is parsed as `(a * b)
/// + c` because the precedence of `*` is greater than the precedence of `+`.
Precedence get precedence;
/// If this expression is an argument to an invocation, and the AST structure
/// has been resolved, and the function being invoked is known based on static
/// type information, and this expression corresponds to one of the parameters
/// of the function being invoked, then return the parameter element
/// representing the parameter to which the value of this expression will be
/// bound. Otherwise, return `null`.
ParameterElement? get staticParameterElement;
/// Return the static type of this expression, or `null` if the AST structure
/// has not been resolved.
DartType? get staticType;
/// If this expression is a parenthesized expression, return the result of
/// unwrapping the expression inside the parentheses. Otherwise, return this
/// expression.
Expression get unParenthesized;
}
/// A function body consisting of a single expression.
///
/// expressionFunctionBody ::=
/// 'async'? '=>' [Expression] ';'
abstract final class ExpressionFunctionBody implements FunctionBody {
/// Return the expression representing the body of the function.
Expression get expression;
/// Return the token introducing the expression that represents the body of the
/// function.
Token get functionDefinition;
/// Return the semicolon terminating the statement.
Token? get semicolon;
}
/// A function body consisting of a single expression.
///
/// expressionFunctionBody ::=
/// 'async'? '=>' [Expression] ';'
final class ExpressionFunctionBodyImpl extends FunctionBodyImpl
implements ExpressionFunctionBody {
/// The token representing the 'async' keyword, or `null` if there is no such
/// keyword.
@override
final Token? keyword;
/// The star optionally following the 'async' or 'sync' keyword, or `null` if
/// there is wither no such keyword or no star.
///
/// It is an error for an expression function body to feature the star, but
/// the parser will accept it.
@override
final Token? star;
/// The token introducing the expression that represents the body of the
/// function.
@override
final Token functionDefinition;
/// The expression representing the body of the function.
ExpressionImpl _expression;
/// The semicolon terminating the statement.
@override
final Token? semicolon;
/// Initialize a newly created function body consisting of a block of
/// statements. The [keyword] can be `null` if the function body is not an
/// async function body.
ExpressionFunctionBodyImpl({
required this.keyword,
required this.star,
required this.functionDefinition,
required ExpressionImpl expression,
required this.semicolon,
}) : _expression = expression {
_becomeParentOf(_expression);
}
@override
Token get beginToken {
if (keyword case final keyword?) {
return keyword;
}
return functionDefinition;
}
@override
Token get endToken {
if (semicolon case final semicolon?) {
return semicolon;
}
return _expression.endToken;
}
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
bool get isAsynchronous => keyword?.lexeme == Keyword.ASYNC.lexeme;
@override
bool get isGenerator => star != null;
@override
bool get isSynchronous => keyword?.lexeme != Keyword.ASYNC.lexeme;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('keyword', keyword)
..addToken('star', star)
..addToken('functionDefinition', functionDefinition)
..addNode('expression', expression)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitExpressionFunctionBody(this);
@override
DartType resolve(ResolverVisitor resolver, DartType? imposedType) =>
resolver.visitExpressionFunctionBody(this, imposedType: imposedType);
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
}
}
/// A node that represents an expression.
///
/// expression ::=
/// [AssignmentExpression]
/// | [ConditionalExpression] cascadeSection*
/// | [ThrowExpression]
sealed class ExpressionImpl extends AstNodeImpl
implements CollectionElementImpl, Expression {
/// The static type of this expression, or `null` if the AST structure has not
/// been resolved.
@override
DartType? staticType;
@override
bool get inConstantContext {
AstNode child = this;
while (child is Expression ||
child is ArgumentList ||
child is MapLiteralEntry ||
child is SpreadElement ||
child is IfElement ||
child is ForElement) {
var parent = child.parent;
if (parent is ConstantContextForExpressionImpl) {
return true;
} else if (parent is ConstantPatternImpl) {
return parent.constKeyword != null;
} else if (parent is EnumConstantArguments) {
return true;
} else if (parent is TypedLiteralImpl && parent.constKeyword != null) {
// Inside an explicitly `const` list or map literal.
return true;
} else if (parent is InstanceCreationExpression &&
parent.keyword?.keyword == Keyword.CONST) {
// Inside an explicitly `const` instance creation expression.
return true;
} else if (parent is Annotation) {
// Inside an annotation.
return true;
} else if (parent is RecordLiteral && parent.constKeyword != null) {
return true;
} else if (parent is VariableDeclaration) {
var grandParent = parent.parent;
// Inside the initializer for a `const` variable declaration.
return grandParent is VariableDeclarationList &&
grandParent.keyword?.keyword == Keyword.CONST;
} else if (parent is SwitchCase) {
// Inside a switch case.
return true;
} else if (parent == null) {
break;
}
child = parent;
}
return false;
}
@override
bool get isAssignable => false;
@override
ParameterElement? get staticParameterElement {
final parent = this.parent;
if (parent is ArgumentListImpl) {
return parent._getStaticParameterElementFor(this);
} else if (parent is IndexExpressionImpl) {
if (identical(parent.index, this)) {
return parent._staticParameterElementForIndex;
}
} else if (parent is BinaryExpressionImpl) {
// TODO(scheglov): https://github.com/dart-lang/sdk/issues/49102
if (identical(parent.rightOperand, this)) {
var parameters = parent.staticInvokeType?.parameters;
if (parameters != null && parameters.isNotEmpty) {
return parameters[0];
}
return null;
}
} else if (parent is AssignmentExpressionImpl) {
if (identical(parent.rightHandSide, this)) {
return parent._staticParameterElementForRightHandSide;
}
} else if (parent is PrefixExpressionImpl) {
// TODO(scheglov): This does not look right, there is no element for
// the operand, for `a++` we invoke `a = a + 1`, so the parameter
// is for `1`, not for `a`.
return parent._staticParameterElementForOperand;
} else if (parent is PostfixExpressionImpl) {
// TODO(scheglov): The same as above.
return parent._staticParameterElementForOperand;
}
return null;
}
@override
ExpressionImpl get unParenthesized => this;
@override
void resolveElement(
ResolverVisitor resolver, CollectionLiteralContext? context) {
resolver.analyzeExpression(this, context?.elementType);
}
/// Dispatches this expression to the [resolver], with the given [contextType]
/// information.
///
/// Note: most code shouldn't call this method directly, but should instead
/// call [ResolverVisitor.analyzeExpression], which has some special logic for
/// handling dynamic contexts.
void resolveExpression(ResolverVisitor resolver, DartType contextType);
}
/// An expression used as a statement.
///
/// expressionStatement ::=
/// [Expression]? ';'
abstract final class ExpressionStatement implements Statement {
/// Return the expression that comprises the statement.
Expression get expression;
/// Return the semicolon terminating the statement, or `null` if the
/// expression is a function expression and therefore isn't followed by a
/// semicolon.
Token? get semicolon;
}
/// An expression used as a statement.
///
/// expressionStatement ::=
/// [Expression]? ';'
final class ExpressionStatementImpl extends StatementImpl
implements ExpressionStatement {
/// The expression that comprises the statement.
ExpressionImpl _expression;
/// The semicolon terminating the statement, or `null` if the expression is a
/// function expression and therefore isn't followed by a semicolon.
@override
final Token? semicolon;
/// Initialize a newly created expression statement.
ExpressionStatementImpl({
required ExpressionImpl expression,
required this.semicolon,
}) : _expression = expression {
_becomeParentOf(_expression);
}
@override
Token get beginToken => _expression.beginToken;
@override
Token get endToken {
if (semicolon case final semicolon?) {
return semicolon;
}
return _expression.endToken;
}
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
bool get isSynthetic =>
_expression.isSynthetic && (semicolon == null || semicolon!.isSynthetic);
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('expression', expression)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitExpressionStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
}
}
/// The "extends" clause in a class declaration.
///
/// extendsClause ::=
/// 'extends' [NamedType]
abstract final class ExtendsClause implements AstNode {
/// Return the token representing the 'extends' keyword.
Token get extendsKeyword;
/// Return the name of the class that is being extended.
NamedType get superclass;
}
/// The "extends" clause in a class declaration.
///
/// extendsClause ::=
/// 'extends' [NamedType]
final class ExtendsClauseImpl extends AstNodeImpl implements ExtendsClause {
/// The token representing the 'extends' keyword.
@override
final Token extendsKeyword;
/// The name of the class that is being extended.
NamedTypeImpl _superclass;
/// Initialize a newly created extends clause.
ExtendsClauseImpl({
required this.extendsKeyword,
required NamedTypeImpl superclass,
}) : _superclass = superclass {
_becomeParentOf(_superclass);
}
@override
Token get beginToken => extendsKeyword;
@override
Token get endToken => _superclass.endToken;
@override
NamedTypeImpl get superclass => _superclass;
set superclass(NamedTypeImpl name) {
_superclass = _becomeParentOf(name);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('extendsKeyword', extendsKeyword)
..addNode('superclass', superclass);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitExtendsClause(this);
@override
void visitChildren(AstVisitor visitor) {
_superclass.accept(visitor);
}
}
/// The declaration of an extension of a type.
///
/// extension ::=
/// 'extension' [SimpleIdentifier]? [TypeParameterList]?
/// 'on' [TypeAnnotation] [ShowClause]? [HideClause]?
/// '{' [ClassMember]* '}'
abstract final class ExtensionDeclaration implements CompilationUnitMember {
@override
ExtensionElement? get declaredElement;
/// Return the type that is being extended.
TypeAnnotation get extendedType;
/// Return the token representing the 'extension' keyword.
Token get extensionKeyword;
/// Return the left curly bracket.
Token get leftBracket;
/// Return the members being added to the extended class.
NodeList<ClassMember> get members;
/// Return the name of the extension, or `null` if the extension does not have
/// a name.
Token? get name;
/// Return the token representing the 'on' keyword.
Token get onKeyword;
/// Return the right curly bracket.
Token get rightBracket;
/// Return the token representing the 'type' keyword.
Token? get typeKeyword;
/// Return the type parameters for the extension, or `null` if the extension
/// does not have any type parameters.
TypeParameterList? get typeParameters;
}
/// The declaration of an extension of a type.
///
/// extension ::=
/// 'extension' [SimpleIdentifier] [TypeParameterList]?
/// 'on' [TypeAnnotation] '{' [ClassMember]* '}'
final class ExtensionDeclarationImpl extends CompilationUnitMemberImpl
implements ExtensionDeclaration {
@override
final Token extensionKeyword;
@override
final Token? typeKeyword;
@override
final Token? name;
/// The type parameters for the extension, or `null` if the extension does not
/// have any type parameters.
TypeParameterListImpl? _typeParameters;
@override
final Token onKeyword;
/// The type that is being extended.
TypeAnnotationImpl _extendedType;
@override
final Token leftBracket;
/// The members being added to the extended class.
final NodeListImpl<ClassMemberImpl> _members = NodeListImpl._();
@override
final Token rightBracket;
@override
ExtensionElementImpl? declaredElement;
ExtensionDeclarationImpl({
required super.comment,
required super.metadata,
required this.extensionKeyword,
required this.typeKeyword,
required this.name,
required TypeParameterListImpl? typeParameters,
required this.onKeyword,
required TypeAnnotationImpl extendedType,
required this.leftBracket,
required List<ClassMemberImpl> members,
required this.rightBracket,
}) : _typeParameters = typeParameters,
_extendedType = extendedType {
_becomeParentOf(_typeParameters);
_becomeParentOf(_extendedType);
_members._initialize(this, members);
}
@override
Token get endToken => rightBracket;
@override
TypeAnnotationImpl get extendedType => _extendedType;
set extendedType(TypeAnnotationImpl extendedClass) {
_extendedType = _becomeParentOf(extendedClass);
}
@override
Token get firstTokenAfterCommentAndMetadata => extensionKeyword;
@override
NodeListImpl<ClassMemberImpl> get members => _members;
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
set typeParameters(TypeParameterListImpl? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('extensionKeyword', extensionKeyword)
..addToken('name', name)
..addNode('typeParameters', typeParameters)
..addToken('onKeyword', onKeyword)
..addNode('extendedType', extendedType)
..addToken('leftBracket', leftBracket)
..addNodeList('members', members)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitExtensionDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_typeParameters?.accept(visitor);
_extendedType.accept(visitor);
_members.accept(visitor);
}
}
/// An override to force resolution to choose a member from a specific
/// extension.
///
/// extensionOverride ::=
/// [Identifier] [TypeArgumentList]? [ArgumentList]
abstract final class ExtensionOverride implements Expression {
/// Return the list of arguments to the override. In valid code this will
/// contain a single argument, which evaluates to the object being extended.
ArgumentList get argumentList;
/// The forced extension element.
ExtensionElement get element;
/// Return the actual type extended by this override, produced by applying
/// [typeArgumentTypes] to the generic type extended by the extension.
///
/// Return `null` if the AST structure has not been resolved.
DartType? get extendedType;
/// The optional import prefix before [name].
ImportPrefixReference? get importPrefix;
/// Whether this override is null aware (as opposed to non-null).
bool get isNullAware;
/// The name of the extension being selected.
Token get name;
/// Return the type arguments to be applied to the extension, or `null` if no
/// type arguments were provided.
TypeArgumentList? get typeArguments;
/// Return the actual type arguments to be applied to the extension, either
/// explicitly specified in [typeArguments], or inferred.
///
/// If the AST has been resolved, never returns `null`, returns an empty list
/// if the extension does not have type parameters.
///
/// Return `null` if the AST structure has not been resolved.
List<DartType>? get typeArgumentTypes;
}
/// An override to force resolution to choose a member from a specific
/// extension.
///
/// extensionOverride ::=
/// [Identifier] [TypeArgumentList]? [ArgumentList]
final class ExtensionOverrideImpl extends ExpressionImpl
implements ExtensionOverride {
@override
final ImportPrefixReferenceImpl? importPrefix;
@override
final Token name;
@override
final ExtensionElement element;
/// The type arguments to be applied to the extension, or `null` if no type
/// arguments were provided.
TypeArgumentListImpl? _typeArguments;
/// The list of arguments to the override. In valid code this will contain a
/// single argument, which evaluates to the object being extended.
ArgumentListImpl _argumentList;
@override
List<DartType>? typeArgumentTypes;
@override
DartType? extendedType;
ExtensionOverrideImpl({
required this.importPrefix,
required this.name,
required TypeArgumentListImpl? typeArguments,
required ArgumentListImpl argumentList,
required this.element,
}) : _typeArguments = typeArguments,
_argumentList = argumentList {
_becomeParentOf(importPrefix);
_becomeParentOf(_typeArguments);
_becomeParentOf(_argumentList);
}
@override
ArgumentListImpl get argumentList => _argumentList;
set argumentList(ArgumentListImpl argumentList) {
_argumentList = _becomeParentOf(argumentList);
}
@override
Token get beginToken => importPrefix?.name ?? name;
@override
Token get endToken => _argumentList.endToken;
@override
bool get isNullAware {
var nextType = argumentList.endToken.next!.type;
return nextType == TokenType.QUESTION_PERIOD ||
nextType == TokenType.QUESTION;
}
@override
Precedence get precedence => Precedence.postfix;
@override
TypeArgumentListImpl? get typeArguments => _typeArguments;
set typeArguments(TypeArgumentListImpl? typeArguments) {
_typeArguments = _becomeParentOf(typeArguments);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('importPrefix', importPrefix)
..addToken('name', name)
..addNode('typeArguments', typeArguments)
..addNode('argumentList', argumentList);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitExtensionOverride(this);
}
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitExtensionOverride(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
importPrefix?.accept(visitor);
_typeArguments?.accept(visitor);
_argumentList.accept(visitor);
}
}
/// The declaration of an extension type.
///
/// <extensionTypeDeclaration> ::=
/// 'extension' 'type' 'const'? <typeIdentifier> <typeParameters>?
/// <representationDeclaration> <interfaces>?
/// '{'
/// (<metadata> <extensionTypeMemberDeclaration>)*
/// '}'
@experimental
abstract final class ExtensionTypeDeclaration
implements NamedCompilationUnitMember {
/// The 'const' keyword.
Token? get constKeyword;
@override
ExtensionTypeElement? get declaredElement;
/// The 'extension' keyword.
Token get extensionKeyword;
/// The 'implements' clause.
ImplementsClause? get implementsClause;
/// The left curly bracket.
Token get leftBracket;
/// The members.
NodeList<ClassMember> get members;
/// The representation declaration.
RepresentationDeclaration get representation;
/// The right curly bracket.
Token get rightBracket;
/// The 'type' keyword.
Token get typeKeyword;
/// The type parameters.
TypeParameterList? get typeParameters;
}
final class ExtensionTypeDeclarationImpl extends NamedCompilationUnitMemberImpl
implements ExtensionTypeDeclaration {
@override
final Token extensionKeyword;
@override
final Token typeKeyword;
@override
final Token? constKeyword;
@override
final TypeParameterListImpl? typeParameters;
@override
final RepresentationDeclarationImpl representation;
@override
final ImplementsClauseImpl? implementsClause;
@override
final Token leftBracket;
@override
final NodeListImpl<ClassMemberImpl> members = NodeListImpl._();
@override
final Token rightBracket;
@override
ExtensionTypeElementImpl? declaredElement;
ExtensionTypeDeclarationImpl({
required super.comment,
required super.metadata,
required this.extensionKeyword,
required this.typeKeyword,
required this.constKeyword,
required super.name,
required this.typeParameters,
required this.representation,
required this.implementsClause,
required this.leftBracket,
required List<ClassMemberImpl> members,
required this.rightBracket,
}) {
_becomeParentOf(typeParameters);
_becomeParentOf(representation);
_becomeParentOf(implementsClause);
this.members._initialize(this, members);
}
@override
Token get endToken => rightBracket;
@override
Token get firstTokenAfterCommentAndMetadata => extensionKeyword;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('extensionKeyword', extensionKeyword)
..addToken('typeKeyword', typeKeyword)
..addToken('constKeyword', constKeyword)
..addToken('name', name)
..addNode('typeParameters', typeParameters)
..addNode('representation', representation)
..addNode('implementsClause', implementsClause)
..addToken('leftBracket', leftBracket)
..addNodeList('members', members)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitExtensionTypeDeclaration(this);
}
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
typeParameters?.accept(visitor);
representation.accept(visitor);
implementsClause?.accept(visitor);
members.accept(visitor);
}
}
/// The declaration of one or more fields of the same type.
///
/// fieldDeclaration ::=
/// 'static' 'const' <type>? <staticFinalDeclarationList>
/// | 'static' 'final' <type>? <staticFinalDeclarationList>
/// | 'static' 'late' 'final' <type>? <initializedIdentifierList>
/// | 'static' 'late'? <varOrType> <initializedIdentifierList>
/// | 'covariant' 'late'? <varOrType> <initializedIdentifierList>
/// | 'late'? 'final' <type>? <initializedIdentifierList>
/// | 'late'? <varOrType> <initializedIdentifierList>
/// | 'external' ('static'? <finalVarOrType> | 'covariant' <varOrType>)
/// <identifierList>
/// | 'abstract' (<finalVarOrType> | 'covariant' <varOrType>)
/// <identifierList>
///
/// (Note: there is no `<fieldDeclaration>` production in the grammar; this is a
/// subset of the grammar production `<declaration>`, which encompasses
/// everything that can appear inside a class declaration except methods).
abstract final class FieldDeclaration implements ClassMember {
/// The `abstract` keyword, or `null` if the keyword was not used.
Token? get abstractKeyword;
/// The 'covariant' keyword, or `null` if the keyword was not used.
Token? get covariantKeyword;
/// The `external` keyword, or `null` if the keyword was not used.
Token? get externalKeyword;
/// Return the fields being declared.
VariableDeclarationList get fields;
/// Return `true` if the fields are declared to be static.
bool get isStatic;
/// Return the semicolon terminating the declaration.
Token get semicolon;
/// Return the token representing the 'static' keyword, or `null` if the
/// fields are not static.
Token? get staticKeyword;
}
/// The declaration of one or more fields of the same type.
///
/// fieldDeclaration ::=
/// 'static'? [VariableDeclarationList] ';'
final class FieldDeclarationImpl extends ClassMemberImpl
implements FieldDeclaration {
@override
final Token? abstractKeyword;
/// The 'augment' keyword, or `null` if the keyword was not used.
final Token? augmentKeyword;
/// The 'covariant' keyword, or `null` if the keyword was not used.
@override
final Token? covariantKeyword;
@override
final Token? externalKeyword;
/// The token representing the 'static' keyword, or `null` if the fields are
/// not static.
@override
final Token? staticKeyword;
/// The fields being declared.
VariableDeclarationListImpl _fieldList;
/// The semicolon terminating the declaration.
@override
final Token semicolon;
/// Initialize a newly created field declaration. Either or both of the
/// [comment] and [metadata] can be `null` if the declaration does not have
/// the corresponding attribute. The [staticKeyword] can be `null` if the
/// field is not a static field.
FieldDeclarationImpl({
required super.comment,
required super.metadata,
required this.abstractKeyword,
required this.augmentKeyword,
required this.covariantKeyword,
required this.externalKeyword,
required this.staticKeyword,
required VariableDeclarationListImpl fieldList,
required this.semicolon,
}) : _fieldList = fieldList {
_becomeParentOf(_fieldList);
}
@override
Element? get declaredElement => null;
@override
Token get endToken => semicolon;
@override
VariableDeclarationListImpl get fields => _fieldList;
set fields(VariableDeclarationListImpl fields) {
_fieldList = _becomeParentOf(fields);
}
@override
Token get firstTokenAfterCommentAndMetadata {
return Token.lexicallyFirst(abstractKeyword, augmentKeyword,
externalKeyword, covariantKeyword, staticKeyword) ??
_fieldList.beginToken;
}
@override
bool get isStatic => staticKeyword != null;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('staticKeyword', staticKeyword)
..addNode('fields', fields)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitFieldDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_fieldList.accept(visitor);
}
}
/// A field formal parameter.
///
/// fieldFormalParameter ::=
/// ('final' [TypeAnnotation] | 'const' [TypeAnnotation] | 'var' | [TypeAnnotation])?
/// 'this' '.' name ([TypeParameterList]? [FormalParameterList])?
abstract final class FieldFormalParameter implements NormalFormalParameter {
/// Return the token representing either the 'final', 'const' or 'var'
/// keyword, or `null` if no keyword was used.
Token? get keyword;
@override
Token get name;
/// Return the parameters of the function-typed parameter, or `null` if this
/// is not a function-typed field formal parameter.
FormalParameterList? get parameters;
/// Return the token representing the period.
Token get period;
/// If the parameter is function-typed, and has the question mark, then its
/// function type is nullable. Having a nullable function type means that the
/// parameter can be null.
Token? get question;
/// Return the token representing the 'this' keyword.
Token get thisKeyword;
/// Return the declared type of the parameter, or `null` if the parameter does
/// not have a declared type.
///
/// Note that if this is a function-typed field formal parameter this is the
/// return type of the function.
TypeAnnotation? get type;
/// Return the type parameters associated with this method, or `null` if this
/// method is not a generic method.
TypeParameterList? get typeParameters;
}
/// A field formal parameter.
///
/// fieldFormalParameter ::=
/// ('final' [NamedType] | 'const' [NamedType] | 'var' | [NamedType])?
/// 'this' '.' [SimpleIdentifier]
/// ([TypeParameterList]? [FormalParameterList])?
final class FieldFormalParameterImpl extends NormalFormalParameterImpl
implements FieldFormalParameter {
/// The token representing either the 'final', 'const' or 'var' keyword, or
/// `null` if no keyword was used.
@override
final Token? keyword;
/// The name of the declared type of the parameter, or `null` if the parameter
/// does not have a declared type.
TypeAnnotationImpl? _type;
/// The token representing the 'this' keyword.
@override
final Token thisKeyword;
/// The token representing the period.
@override
final Token period;
/// The type parameters associated with the method, or `null` if the method is
/// not a generic method.
TypeParameterListImpl? _typeParameters;
/// The parameters of the function-typed parameter, or `null` if this is not a
/// function-typed field formal parameter.
FormalParameterListImpl? _parameters;
@override
final Token? question;
/// Initialize a newly created formal parameter. Either or both of the
/// [comment] and [metadata] can be `null` if the parameter does not have the
/// corresponding attribute. The [keyword] can be `null` if there is a type.
/// The [type] must be `null` if the keyword is 'var'. The [thisKeyword] and
/// [period] can be `null` if the keyword 'this' was not provided. The
/// [parameters] can be `null` if this is not a function-typed field formal
/// parameter.
FieldFormalParameterImpl({
required super.comment,
required super.metadata,
required super.covariantKeyword,
required super.requiredKeyword,
required this.keyword,
required TypeAnnotationImpl? type,
required this.thisKeyword,
required this.period,
required super.name,
required TypeParameterListImpl? typeParameters,
required FormalParameterListImpl? parameters,
required this.question,
}) : _type = type,
_typeParameters = typeParameters,
_parameters = parameters {
_becomeParentOf(_type);
_becomeParentOf(_typeParameters);
_becomeParentOf(_parameters);
}
@override
Token get beginToken {
final metadata = this.metadata;
if (metadata.isNotEmpty) {
return metadata.beginToken!;
} else if (requiredKeyword case final requiredKeyword?) {
return requiredKeyword;
} else if (covariantKeyword case final covariantKeyword?) {
return covariantKeyword;
} else if (keyword case final keyword?) {
return keyword;
} else if (type case final type?) {
return type.beginToken;
}
return thisKeyword;
}
@override
Token get endToken {
return question ?? _parameters?.endToken ?? name;
}
@override
bool get isConst => keyword?.keyword == Keyword.CONST;
@override
bool get isExplicitlyTyped => _parameters != null || _type != null;
@override
bool get isFinal => keyword?.keyword == Keyword.FINAL;
@override
Token get name => super.name!;
@override
FormalParameterListImpl? get parameters => _parameters;
set parameters(FormalParameterListImpl? parameters) {
_parameters = _becomeParentOf(parameters);
}
@override
TypeAnnotationImpl? get type => _type;
set type(TypeAnnotationImpl? type) {
_type = _becomeParentOf(type as TypeAnnotationImpl);
}
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
set typeParameters(TypeParameterListImpl? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('keyword', keyword)
..addNode('type', type)
..addToken('thisKeyword', thisKeyword)
..addToken('period', period)
..addToken('name', name)
..addNode('typeParameters', typeParameters)
..addNode('parameters', parameters);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitFieldFormalParameter(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_type?.accept(visitor);
_typeParameters?.accept(visitor);
_parameters?.accept(visitor);
}
}
/// The parts of a for-each loop that control the iteration.
sealed class ForEachParts implements ForLoopParts {
/// Return the token representing the 'in' keyword.
Token get inKeyword;
/// Return the expression evaluated to produce the iterator.
Expression get iterable;
}
sealed class ForEachPartsImpl extends ForLoopPartsImpl implements ForEachParts {
@override
final Token inKeyword;
/// The expression evaluated to produce the iterator.
ExpressionImpl _iterable;
/// Initialize a newly created for-each statement whose loop control variable
/// is declared internally (in the for-loop part). The [awaitKeyword] can be
/// `null` if this is not an asynchronous for loop.
ForEachPartsImpl({
required this.inKeyword,
required ExpressionImpl iterable,
}) : _iterable = iterable {
_becomeParentOf(_iterable);
}
@override
Token get beginToken => inKeyword;
@override
Token get endToken => _iterable.endToken;
@override
ExpressionImpl get iterable => _iterable;
set iterable(ExpressionImpl expression) {
_iterable = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('inKeyword', inKeyword)
..addNode('iterable', iterable);
@override
void visitChildren(AstVisitor visitor) {
_iterable.accept(visitor);
}
}
/// The parts of a for-each loop that control the iteration when the loop
/// variable is declared as part of the for loop.
///
/// forLoopParts ::=
/// [DeclaredIdentifier] 'in' [Expression]
abstract final class ForEachPartsWithDeclaration implements ForEachParts {
/// Return the declaration of the loop variable.
DeclaredIdentifier get loopVariable;
}
final class ForEachPartsWithDeclarationImpl extends ForEachPartsImpl
implements ForEachPartsWithDeclaration {
/// The declaration of the loop variable.
DeclaredIdentifierImpl _loopVariable;
/// Initialize a newly created for-each statement whose loop control variable
/// is declared internally (inside the for-loop part).
ForEachPartsWithDeclarationImpl({
required DeclaredIdentifierImpl loopVariable,
required super.inKeyword,
required super.iterable,
}) : _loopVariable = loopVariable {
_becomeParentOf(_loopVariable);
}
@override
Token get beginToken => _loopVariable.beginToken;
@override
DeclaredIdentifierImpl get loopVariable => _loopVariable;
set loopVariable(DeclaredIdentifierImpl variable) {
_loopVariable = _becomeParentOf(variable);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('loopVariable', loopVariable)
..addAll(super._childEntities);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitForEachPartsWithDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
_loopVariable.accept(visitor);
super.visitChildren(visitor);
}
}
/// The parts of a for-each loop that control the iteration when the loop
/// variable is declared outside of the for loop.
///
/// forLoopParts ::=
/// [SimpleIdentifier] 'in' [Expression]
abstract final class ForEachPartsWithIdentifier implements ForEachParts {
/// Return the loop variable.
SimpleIdentifier get identifier;
}
final class ForEachPartsWithIdentifierImpl extends ForEachPartsImpl
implements ForEachPartsWithIdentifier {
/// The loop variable.
SimpleIdentifierImpl _identifier;
/// Initialize a newly created for-each statement whose loop control variable
/// is declared externally (outside the for-loop part).
ForEachPartsWithIdentifierImpl({
required SimpleIdentifierImpl identifier,
required super.inKeyword,
required super.iterable,
}) : _identifier = identifier {
_becomeParentOf(_identifier);
}
@override
Token get beginToken => _identifier.beginToken;
@override
SimpleIdentifierImpl get identifier => _identifier;
set identifier(SimpleIdentifierImpl identifier) {
_identifier = _becomeParentOf(identifier);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('identifier', identifier)
..addAll(super._childEntities);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitForEachPartsWithIdentifier(this);
@override
void visitChildren(AstVisitor visitor) {
_identifier.accept(visitor);
_iterable.accept(visitor);
}
}
/// A for-loop part with a pattern.
///
/// forEachPartsWithPattern ::=
/// ( 'final' | 'var' ) [DartPattern] 'in' [Expression]
abstract final class ForEachPartsWithPattern implements ForEachParts {
/// Return the `var` or `final` keyword introducing the pattern.
Token get keyword;
/// Returns the annotations associated with this node.
NodeList<Annotation> get metadata;
/// The pattern that will match the expression.
DartPattern get pattern;
}
/// A for-loop part with a pattern.
///
/// forEachPartsWithPattern ::=
/// ( 'final' | 'var' ) [DartPattern] 'in' [Expression]
final class ForEachPartsWithPatternImpl extends ForEachPartsImpl
implements ForEachPartsWithPattern {
/// The annotations associated with this node.
final NodeListImpl<AnnotationImpl> _metadata = NodeListImpl._();
@override
final Token keyword;
@override
final DartPatternImpl pattern;
/// Variables declared in [pattern].
late final List<BindPatternVariableElementImpl> variables;
ForEachPartsWithPatternImpl({
required List<AnnotationImpl>? metadata,
required this.keyword,
required this.pattern,
required super.inKeyword,
required super.iterable,
}) {
_metadata._initialize(this, metadata);
_becomeParentOf(pattern);
}
@override
Token get beginToken {
if (_metadata.isEmpty) {
return keyword;
} else {
return _metadata.beginToken!;
}
}
/// If [keyword] is `final`, returns it.
Token? get finalKeyword {
if (keyword.keyword == Keyword.FINAL) {
return keyword;
}
return null;
}
@override
NodeListImpl<AnnotationImpl> get metadata => _metadata;
@override
ChildEntities get _childEntities => ChildEntities()
..addNodeList('metadata', metadata)
..addToken('keyword', keyword)
..addNode('pattern', pattern)
..addAll(super._childEntities);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitForEachPartsWithPattern(this);
@override
void visitChildren(AstVisitor visitor) {
_metadata.accept(visitor);
pattern.accept(visitor);
super.visitChildren(visitor);
}
}
/// The basic structure of a for element.
abstract final class ForElement implements CollectionElement {
/// Return the token representing the 'await' keyword, or `null` if there was
/// no 'await' keyword.
Token? get awaitKeyword;
/// Return the body of the loop.
CollectionElement get body;
/// Return the token representing the 'for' keyword.
Token get forKeyword;
/// Return the parts of the for element that control the iteration.
ForLoopParts get forLoopParts;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right parenthesis.
Token get rightParenthesis;
}
final class ForElementImpl extends CollectionElementImpl implements ForElement {
@override
final Token? awaitKeyword;
@override
final Token forKeyword;
@override
final Token leftParenthesis;
ForLoopPartsImpl _forLoopParts;
@override
final Token rightParenthesis;
/// The body of the loop.
CollectionElementImpl _body;
/// Initialize a newly created for element.
ForElementImpl({
required this.awaitKeyword,
required this.forKeyword,
required this.leftParenthesis,
required ForLoopPartsImpl forLoopParts,
required this.rightParenthesis,
required CollectionElementImpl body,
}) : _forLoopParts = forLoopParts,
_body = body {
_becomeParentOf(_forLoopParts);
_becomeParentOf(_body);
}
@override
Token get beginToken => awaitKeyword ?? forKeyword;
@override
CollectionElementImpl get body => _body;
set body(CollectionElementImpl statement) {
_body = _becomeParentOf(statement);
}
@override
Token get endToken => _body.endToken;
@override
ForLoopPartsImpl get forLoopParts => _forLoopParts;
set forLoopParts(ForLoopPartsImpl forLoopParts) {
_forLoopParts = _becomeParentOf(forLoopParts);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('awaitKeyword', awaitKeyword)
..addToken('forKeyword', forKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('forLoopParts', forLoopParts)
..addToken('rightParenthesis', rightParenthesis)
..addNode('body', body);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitForElement(this);
@override
void resolveElement(
ResolverVisitor resolver, CollectionLiteralContext? context) {
resolver.visitForElement(this, context: context);
resolver.pushRewrite(null);
}
@override
void visitChildren(AstVisitor visitor) {
_forLoopParts.accept(visitor);
_body.accept(visitor);
}
}
/// The parts of a for or for-each loop that control the iteration.
///
/// forLoopParts ::=
/// [VariableDeclaration] ';' [Expression]? ';' expressionList?
/// | [Expression]? ';' [Expression]? ';' expressionList?
/// | [DeclaredIdentifier] 'in' [Expression]
/// | [SimpleIdentifier] 'in' [Expression]
///
/// expressionList ::=
/// [Expression] (',' [Expression])*
sealed class ForLoopParts implements AstNode {}
sealed class ForLoopPartsImpl extends AstNodeImpl implements ForLoopParts {}
/// A node representing a parameter to a function.
///
/// formalParameter ::=
/// [NormalFormalParameter]
/// | [DefaultFormalParameter]
sealed class FormalParameter implements AstNode {
/// The 'covariant' keyword, or `null` if the keyword was not used.
Token? get covariantKeyword;
/// Return the element representing this parameter, or `null` if this
/// parameter has not been resolved.
ParameterElement? get declaredElement;
/// Return `true` if this parameter was declared with the 'const' modifier.
bool get isConst;
/// Indicates whether the parameter has an explicit type.
bool get isExplicitlyTyped;
/// Return `true` if this parameter was declared with the 'final' modifier.
///
/// Parameters that are declared with the 'const' modifier will return
/// `false` even though they are implicitly final.
bool get isFinal;
/// Return `true` if this parameter is a named parameter.
///
/// Named parameters can either be required or optional.
bool get isNamed;
/// Return `true` if this parameter is an optional parameter.
///
/// Optional parameters can either be positional or named.
bool get isOptional;
/// Return `true` if this parameter is both an optional and named parameter.
bool get isOptionalNamed;
/// Return `true` if this parameter is both an optional and positional
/// parameter.
bool get isOptionalPositional;
/// Return `true` if this parameter is a positional parameter.
///
/// Positional parameters can either be required or optional.
bool get isPositional;
/// Return `true` if this parameter is a required parameter.
///
/// Required parameters can either be positional or named.
///
/// Note: this will return `false` for a named parameter that is annotated
/// with the `@required` annotation.
bool get isRequired;
/// Return `true` if this parameter is both a required and named parameter.
///
/// Note: this will return `false` for a named parameter that is annotated
/// with the `@required` annotation.
bool get isRequiredNamed;
/// Return `true` if this parameter is both a required and positional
/// parameter.
bool get isRequiredPositional;
/// Return the annotations associated with this parameter.
NodeList<Annotation> get metadata;
/// Return the name of the parameter being declared, or `null` if the
/// parameter doesn't have a name, such as when it's part of a generic
/// function type.
Token? get name;
/// The 'required' keyword, or `null` if the keyword was not used.
Token? get requiredKeyword;
}
/// A node representing a parameter to a function.
///
/// formalParameter ::=
/// [NormalFormalParameter]
/// | [DefaultFormalParameter]
sealed class FormalParameterImpl extends AstNodeImpl
implements FormalParameter {
@override
ParameterElementImpl? declaredElement;
@override
bool get isNamed => kind.isNamed;
@override
bool get isOptional => kind.isOptional;
@override
bool get isOptionalNamed => kind.isOptionalNamed;
@override
bool get isOptionalPositional => kind.isOptionalPositional;
@override
bool get isPositional => kind.isPositional;
@override
bool get isRequired => kind.isRequired;
@override
bool get isRequiredNamed => kind.isRequiredNamed;
@override
bool get isRequiredPositional => kind.isRequiredPositional;
/// Return the kind of this parameter.
ParameterKind get kind;
}
/// The formal parameter list of a method declaration, function declaration, or
/// function type alias.
///
/// While the grammar requires all optional formal parameters to follow all of
/// the normal formal parameters and at most one grouping of optional formal
/// parameters, this class does not enforce those constraints. All parameters
/// are flattened into a single list, which can have any or all kinds of
/// parameters (normal, named, and positional) in any order.
///
/// formalParameterList ::=
/// '(' ')'
/// | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
/// | '(' optionalFormalParameters ')'
///
/// normalFormalParameters ::=
/// [NormalFormalParameter] (',' [NormalFormalParameter])*
///
/// optionalFormalParameters ::=
/// optionalPositionalFormalParameters
/// | namedFormalParameters
///
/// optionalPositionalFormalParameters ::=
/// '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
///
/// namedFormalParameters ::=
/// '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
abstract final class FormalParameterList implements AstNode {
/// Return the left square bracket ('[') or left curly brace ('{') introducing
/// the optional parameters, or `null` if there are no optional parameters.
Token? get leftDelimiter;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return a list containing the elements representing the parameters in this
/// list.
///
/// The list will contain `null`s if the parameters in this list have not
/// been resolved.
List<ParameterElement?> get parameterElements;
/// Return the parameters associated with the method.
NodeList<FormalParameter> get parameters;
/// Return the right square bracket (']') or right curly brace ('}')
/// terminating the optional parameters, or `null` if there are no optional
/// parameters.
Token? get rightDelimiter;
/// Return the right parenthesis.
Token get rightParenthesis;
}
/// The formal parameter list of a method declaration, function declaration, or
/// function type alias.
///
/// While the grammar requires all optional formal parameters to follow all of
/// the normal formal parameters and at most one grouping of optional formal
/// parameters, this class does not enforce those constraints. All parameters
/// are flattened into a single list, which can have any or all kinds of
/// parameters (normal, named, and positional) in any order.
///
/// formalParameterList ::=
/// '(' ')'
/// | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
/// | '(' optionalFormalParameters ')'
///
/// normalFormalParameters ::=
/// [NormalFormalParameter] (',' [NormalFormalParameter])*
///
/// optionalFormalParameters ::=
/// optionalPositionalFormalParameters
/// | namedFormalParameters
///
/// optionalPositionalFormalParameters ::=
/// '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
///
/// namedFormalParameters ::=
/// '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
final class FormalParameterListImpl extends AstNodeImpl
implements FormalParameterList {
/// The left parenthesis.
@override
final Token leftParenthesis;
/// The parameters associated with the method.
final NodeListImpl<FormalParameterImpl> _parameters = NodeListImpl._();
/// The left square bracket ('[') or left curly brace ('{') introducing the
/// optional parameters, or `null` if there are no optional parameters.
@override
final Token? leftDelimiter;
/// The right square bracket (']') or right curly brace ('}') terminating the
/// optional parameters, or `null` if there are no optional parameters.
@override
final Token? rightDelimiter;
/// The right parenthesis.
@override
final Token rightParenthesis;
/// Initialize a newly created parameter list. The list of [parameters] can be
/// `null` if there are no parameters. The [leftDelimiter] and
/// [rightDelimiter] can be `null` if there are no optional parameters.
FormalParameterListImpl({
required this.leftParenthesis,
required List<FormalParameterImpl> parameters,
required this.leftDelimiter,
required this.rightDelimiter,
required this.rightParenthesis,
}) {
_parameters._initialize(this, parameters);
}
@override
Token get beginToken => leftParenthesis;
@override
Token get endToken => rightParenthesis;
@override
List<ParameterElement?> get parameterElements {
int count = _parameters.length;
var types = <ParameterElement?>[];
for (int i = 0; i < count; i++) {
types.add(_parameters[i].declaredElement);
}
return types;
}
@override
NodeListImpl<FormalParameterImpl> get parameters => _parameters;
@override
ChildEntities get _childEntities {
// TODO(paulberry): include commas.
var result = ChildEntities()..addToken('leftParenthesis', leftParenthesis);
bool leftDelimiterNeeded = leftDelimiter != null;
int length = _parameters.length;
for (int i = 0; i < length; i++) {
FormalParameter parameter = _parameters[i];
if (leftDelimiterNeeded && leftDelimiter!.offset < parameter.offset) {
result.addToken('leftDelimiter', leftDelimiter);
leftDelimiterNeeded = false;
}
result.addNode('parameter', parameter);
}
return result
..addToken('rightDelimiter', rightDelimiter)
..addToken('rightParenthesis', rightParenthesis);
}
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitFormalParameterList(this);
@override
void visitChildren(AstVisitor visitor) {
_parameters.accept(visitor);
}
}
/// The parts of a for loop that control the iteration.
///
/// forLoopParts ::=
/// [VariableDeclaration] ';' [Expression]? ';' expressionList?
/// | [Expression]? ';' [Expression]? ';' expressionList?
sealed class ForParts implements ForLoopParts {
/// Return the condition used to determine when to terminate the loop, or
/// `null` if there is no condition.
Expression? get condition;
/// Return the semicolon separating the initializer and the condition.
Token get leftSeparator;
/// Return the semicolon separating the condition and the updater.
Token get rightSeparator;
/// Return the list of expressions run after each execution of the loop body.
NodeList<Expression> get updaters;
}
sealed class ForPartsImpl extends ForLoopPartsImpl implements ForParts {
@override
final Token leftSeparator;
/// The condition used to determine when to terminate the loop, or `null` if
/// there is no condition.
ExpressionImpl? _condition;
@override
final Token rightSeparator;
/// The list of expressions run after each execution of the loop body.
final NodeListImpl<ExpressionImpl> _updaters = NodeListImpl._();
/// Initialize a newly created for statement. Either the [variableList] or the
/// [initialization] must be `null`. Either the [condition] and the list of
/// [updaters] can be `null` if the loop does not have the corresponding
/// attribute.
ForPartsImpl({
required this.leftSeparator,
required ExpressionImpl? condition,
required this.rightSeparator,
required List<ExpressionImpl>? updaters,
}) : _condition = condition {
_becomeParentOf(_condition);
_updaters._initialize(this, updaters);
}
@override
Token get beginToken => leftSeparator;
@override
ExpressionImpl? get condition => _condition;
set condition(ExpressionImpl? expression) {
_condition = _becomeParentOf(expression);
}
@override
Token get endToken => _updaters.endToken ?? rightSeparator;
@override
NodeListImpl<ExpressionImpl> get updaters => _updaters;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('leftSeparator', leftSeparator)
..addNode('condition', condition)
..addToken('rightSeparator', rightSeparator)
..addNodeList('updaters', updaters);
@override
void visitChildren(AstVisitor visitor) {
_condition?.accept(visitor);
_updaters.accept(visitor);
}
}
/// The parts of a for loop that control the iteration when there are one or
/// more variable declarations as part of the for loop.
///
/// forLoopParts ::=
/// [VariableDeclarationList] ';' [Expression]? ';' expressionList?
abstract final class ForPartsWithDeclarations implements ForParts {
/// Return the declaration of the loop variables.
VariableDeclarationList get variables;
}
final class ForPartsWithDeclarationsImpl extends ForPartsImpl
implements ForPartsWithDeclarations {
/// The declaration of the loop variables, or `null` if there are no
/// variables. Note that a for statement cannot have both a variable list and
/// an initialization expression, but can validly have neither.
VariableDeclarationListImpl _variableList;
/// Initialize a newly created for statement. Both the [condition] and the
/// list of [updaters] can be `null` if the loop does not have the
/// corresponding attribute.
ForPartsWithDeclarationsImpl({
required VariableDeclarationListImpl variableList,
required super.leftSeparator,
required super.condition,
required super.rightSeparator,
required super.updaters,
}) : _variableList = variableList {
_becomeParentOf(_variableList);
}
@override
Token get beginToken => _variableList.beginToken;
@override
VariableDeclarationListImpl get variables => _variableList;
set variables(VariableDeclarationListImpl? variableList) {
_variableList =
_becomeParentOf(variableList as VariableDeclarationListImpl);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('variables', variables)
..addAll(super._childEntities);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitForPartsWithDeclarations(this);
@override
void visitChildren(AstVisitor visitor) {
_variableList.accept(visitor);
super.visitChildren(visitor);
}
}
/// The parts of a for loop that control the iteration when there are no
/// variable declarations as part of the for loop.
///
/// forLoopParts ::=
/// [Expression]? ';' [Expression]? ';' expressionList?
abstract final class ForPartsWithExpression implements ForParts {
/// Return the initialization expression, or `null` if there is no
/// initialization expression.
Expression? get initialization;
}
final class ForPartsWithExpressionImpl extends ForPartsImpl
implements ForPartsWithExpression {
/// The initialization expression, or `null` if there is no initialization
/// expression. Note that a for statement cannot have both a variable list and
/// an initialization expression, but can validly have neither.
ExpressionImpl? _initialization;
/// Initialize a newly created for statement. Both the [condition] and the
/// list of [updaters] can be `null` if the loop does not have the
/// corresponding attribute.
ForPartsWithExpressionImpl({
required ExpressionImpl? initialization,
required super.leftSeparator,
required super.condition,
required super.rightSeparator,
required super.updaters,
}) : _initialization = initialization {
_becomeParentOf(_initialization);
}
@override
Token get beginToken => initialization?.beginToken ?? super.beginToken;
@override
ExpressionImpl? get initialization => _initialization;
set initialization(ExpressionImpl? initialization) {
_initialization = _becomeParentOf(initialization);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('initialization', initialization)
..addAll(super._childEntities);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitForPartsWithExpression(this);
@override
void visitChildren(AstVisitor visitor) {
_initialization?.accept(visitor);
super.visitChildren(visitor);
}
}
/// The parts of a for loop that control the iteration when there is a pattern
/// declaration as part of the for loop.
///
/// forLoopParts ::=
/// [PatternVariableDeclaration] ';' [Expression]? ';' expressionList?
abstract final class ForPartsWithPattern implements ForParts {
/// Return the declaration of the loop variables.
PatternVariableDeclaration get variables;
}
/// The parts of a for loop that control the iteration when there is a pattern
/// declaration as part of the for loop.
///
/// forLoopParts ::=
/// [PatternVariableDeclaration] ';' [Expression]? ';' expressionList?
final class ForPartsWithPatternImpl extends ForPartsImpl
implements ForPartsWithPattern {
@override
final PatternVariableDeclarationImpl variables;
ForPartsWithPatternImpl({
required this.variables,
required super.leftSeparator,
required super.condition,
required super.rightSeparator,
required super.updaters,
}) {
_becomeParentOf(variables);
}
@override
Token get beginToken => variables.beginToken;
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('variables', variables)
..addAll(super._childEntities);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitForPartsWithPattern(this);
@override
void visitChildren(AstVisitor visitor) {
variables.accept(visitor);
super.visitChildren(visitor);
}
}
/// A for or for-each statement.
///
/// forStatement ::=
/// 'for' '(' forLoopParts ')' [Statement]
///
/// forLoopParts ::=
/// [VariableDeclaration] ';' [Expression]? ';' expressionList?
/// | [Expression]? ';' [Expression]? ';' expressionList?
/// | [DeclaredIdentifier] 'in' [Expression]
/// | [SimpleIdentifier] 'in' [Expression]
///
/// This is the class that is used to represent a for loop when either the
/// 'control-flow-collections' or 'spread-collections' experiments are enabled.
/// If neither of those experiments are enabled, then either `ForStatement` or
/// `ForEachStatement` will be used.
abstract final class ForStatement implements Statement {
/// Return the token representing the 'await' keyword, or `null` if there is
/// no 'await' keyword.
Token? get awaitKeyword;
/// Return the body of the loop.
Statement get body;
/// Return the token representing the 'for' keyword.
Token get forKeyword;
/// Return the parts of the for element that control the iteration.
ForLoopParts get forLoopParts;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right parenthesis.
Token get rightParenthesis;
}
final class ForStatementImpl extends StatementImpl implements ForStatement {
@override
final Token? awaitKeyword;
@override
final Token forKeyword;
@override
final Token leftParenthesis;
ForLoopPartsImpl _forLoopParts;
@override
final Token rightParenthesis;
/// The body of the loop.
StatementImpl _body;
/// Initialize a newly created for statement.
ForStatementImpl({
required this.awaitKeyword,
required this.forKeyword,
required this.leftParenthesis,
required ForLoopPartsImpl forLoopParts,
required this.rightParenthesis,
required StatementImpl body,
}) : _forLoopParts = forLoopParts,
_body = body {
_becomeParentOf(_forLoopParts);
_becomeParentOf(_body);
}
@override
Token get beginToken => awaitKeyword ?? forKeyword;
@override
StatementImpl get body => _body;
set body(StatementImpl statement) {
_body = _becomeParentOf(statement);
}
@override
Token get endToken => _body.endToken;
@override
ForLoopPartsImpl get forLoopParts => _forLoopParts;
set forLoopParts(ForLoopPartsImpl forLoopParts) {
_forLoopParts = _becomeParentOf(forLoopParts);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('awaitKeyword', awaitKeyword)
..addToken('forKeyword', forKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('forLoopParts', forLoopParts)
..addToken('rightParenthesis', rightParenthesis)
..addNode('body', body);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitForStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_forLoopParts.accept(visitor);
_body.accept(visitor);
}
}
/// A node representing the body of a function or method.
///
/// functionBody ::=
/// [BlockFunctionBody]
/// | [EmptyFunctionBody]
/// | [ExpressionFunctionBody]
/// | [NativeFunctionBody]
sealed class FunctionBody implements AstNode {
/// Return `true` if this function body is asynchronous.
bool get isAsynchronous;
/// Return `true` if this function body is a generator.
bool get isGenerator;
/// Return `true` if this function body is synchronous.
bool get isSynchronous;
/// Return the token representing the 'async' or 'sync' keyword, or `null` if
/// there is no such keyword.
Token? get keyword;
/// Return the star following the 'async' or 'sync' keyword, or `null` if
/// there is no star.
Token? get star;
/// If [variable] is a local variable or parameter declared anywhere within
/// the top level function or method containing this [FunctionBody], return a
/// boolean indicating whether [variable] is potentially mutated within the
/// scope of its declaration.
///
/// If [variable] is not a local variable or parameter declared within the top
/// level function or method containing this [FunctionBody], return `false`.
///
/// Throws an exception if resolution has not yet been performed.
bool isPotentiallyMutatedInScope(VariableElement variable);
}
/// A node representing the body of a function or method.
///
/// functionBody ::=
/// [BlockFunctionBody]
/// | [EmptyFunctionBody]
/// | [ExpressionFunctionBody]
sealed class FunctionBodyImpl extends AstNodeImpl implements FunctionBody {
/// Additional information about local variables and parameters that are
/// declared within this function body or any enclosing function body. `null`
/// if resolution has not yet been performed.
LocalVariableInfo? localVariableInfo;
/// Return `true` if this function body is asynchronous.
@override
bool get isAsynchronous => false;
/// Return `true` if this function body is a generator.
@override
bool get isGenerator => false;
/// Return `true` if this function body is synchronous.
@override
bool get isSynchronous => true;
/// Return the token representing the 'async' or 'sync' keyword, or `null` if
/// there is no such keyword.
@override
Token? get keyword => null;
/// Return the star following the 'async' or 'sync' keyword, or `null` if
/// there is no star.
@override
Token? get star => null;
@override
bool isPotentiallyMutatedInScope(VariableElement variable) {
if (localVariableInfo == null) {
throw StateError('Resolution has not yet been performed');
}
return localVariableInfo!.potentiallyMutatedInScope.contains(variable);
}
/// Dispatch this function body to the resolver, imposing [imposedType] as the
/// return type context for `return` statements.
///
/// Return value is the actual return type of the method.
DartType resolve(ResolverVisitor resolver, DartType? imposedType);
}
/// A function declaration.
///
/// Wrapped in a [FunctionDeclarationStatement] to represent a local function
/// declaration, otherwise a top-level function declaration.
///
/// functionDeclaration ::=
/// 'external' functionSignature
/// | functionSignature [FunctionBody]
///
/// functionSignature ::=
/// [Type]? ('get' | 'set')? name [FormalParameterList]
abstract final class FunctionDeclaration implements NamedCompilationUnitMember {
@override
ExecutableElement? get declaredElement;
/// Return the token representing the 'external' keyword, or `null` if this is
/// not an external function.
Token? get externalKeyword;
/// Return the function expression being wrapped.
FunctionExpression get functionExpression;
/// Return `true` if this function declares a getter.
bool get isGetter;
/// Return `true` if this function declares a setter.
bool get isSetter;
/// Return the token representing the 'get' or 'set' keyword, or `null` if
/// this is a function declaration rather than a property declaration.
Token? get propertyKeyword;
/// Return the return type of the function, or `null` if no return type was
/// declared.
TypeAnnotation? get returnType;
}
/// A function declaration.
///
/// Wrapped in a [FunctionDeclarationStatementImpl] to represent a local
/// function declaration, otherwise a top-level function declaration.
///
/// functionDeclaration ::=
/// 'external' functionSignature
/// | functionSignature [FunctionBody]
///
/// functionSignature ::=
/// [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
final class FunctionDeclarationImpl extends NamedCompilationUnitMemberImpl
implements FunctionDeclaration {
/// The token representing the 'augment' keyword, or `null` if this is not an
/// function augmentation.
final Token? augmentKeyword;
/// The token representing the 'external' keyword, or `null` if this is not an
/// external function.
@override
final Token? externalKeyword;
/// The return type of the function, or `null` if no return type was declared.
TypeAnnotationImpl? _returnType;
/// The token representing the 'get' or 'set' keyword, or `null` if this is a
/// function declaration rather than a property declaration.
@override
final Token? propertyKeyword;
/// The function expression being wrapped.
FunctionExpressionImpl _functionExpression;
@override
ExecutableElementImpl? declaredElement;
/// Initialize a newly created function declaration. Either or both of the
/// [comment] and [metadata] can be `null` if the function does not have the
/// corresponding attribute. The [externalKeyword] can be `null` if the
/// function is not an external function. The [returnType] can be `null` if no
/// return type was specified. The [propertyKeyword] can be `null` if the
/// function is neither a getter or a setter.
FunctionDeclarationImpl({
required super.comment,
required super.metadata,
required this.augmentKeyword,
required this.externalKeyword,
required TypeAnnotationImpl? returnType,
required this.propertyKeyword,
required super.name,
required FunctionExpressionImpl functionExpression,
}) : _returnType = returnType,
_functionExpression = functionExpression {
_becomeParentOf(_returnType);
_becomeParentOf(_functionExpression);
}
@override
Token get endToken => _functionExpression.endToken;
@override
Token get firstTokenAfterCommentAndMetadata {
return augmentKeyword ??
externalKeyword ??
_returnType?.beginToken ??
propertyKeyword ??
name;
}
@override
FunctionExpressionImpl get functionExpression => _functionExpression;
set functionExpression(FunctionExpressionImpl functionExpression) {
_functionExpression = _becomeParentOf(functionExpression);
}
@override
bool get isGetter => propertyKeyword?.keyword == Keyword.GET;
@override
bool get isSetter => propertyKeyword?.keyword == Keyword.SET;
@override
TypeAnnotationImpl? get returnType => _returnType;
set returnType(TypeAnnotationImpl? type) {
_returnType = _becomeParentOf(type as TypeAnnotationImpl);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('augmentKeyword', augmentKeyword)
..addToken('externalKeyword', externalKeyword)
..addNode('returnType', returnType)
..addToken('propertyKeyword', propertyKeyword)
..addToken('name', name)
..addNode('functionExpression', functionExpression);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitFunctionDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_returnType?.accept(visitor);
_functionExpression.accept(visitor);
}
}
/// A [FunctionDeclaration] used as a statement.
abstract final class FunctionDeclarationStatement implements Statement {
/// Return the function declaration being wrapped.
FunctionDeclaration get functionDeclaration;
}
/// A [FunctionDeclaration] used as a statement.
final class FunctionDeclarationStatementImpl extends StatementImpl
implements FunctionDeclarationStatement {
/// The function declaration being wrapped.
FunctionDeclarationImpl _functionDeclaration;
/// Initialize a newly created function declaration statement.
FunctionDeclarationStatementImpl({
required FunctionDeclarationImpl functionDeclaration,
}) : _functionDeclaration = functionDeclaration {
_becomeParentOf(_functionDeclaration);
}
@override
Token get beginToken => _functionDeclaration.beginToken;
@override
Token get endToken => _functionDeclaration.endToken;
@override
FunctionDeclarationImpl get functionDeclaration => _functionDeclaration;
set functionDeclaration(FunctionDeclarationImpl functionDeclaration) {
_functionDeclaration = _becomeParentOf(functionDeclaration);
}
@override
ChildEntities get _childEntities =>
ChildEntities()..addNode('functionDeclaration', functionDeclaration);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitFunctionDeclarationStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_functionDeclaration.accept(visitor);
}
}
/// A function expression.
///
/// functionExpression ::=
/// [TypeParameterList]? [FormalParameterList] [FunctionBody]
abstract final class FunctionExpression implements Expression {
/// Return the body of the function.
FunctionBody get body;
/// Return the element associated with the function, or `null` if the AST
/// structure has not been resolved.
ExecutableElement? get declaredElement;
/// Return the parameters associated with the function, or `null` if the
/// function is part of a top-level getter.
FormalParameterList? get parameters;
/// Return the type parameters associated with this method, or `null` if this
/// method is not a generic method.
TypeParameterList? get typeParameters;
}
/// A function expression.
///
/// functionExpression ::=
/// [TypeParameterList]? [FormalParameterList] [FunctionBody]
final class FunctionExpressionImpl extends ExpressionImpl
implements FunctionExpression {
/// The type parameters associated with the method, or `null` if the method is
/// not a generic method.
TypeParameterListImpl? _typeParameters;
/// The parameters associated with the function, or `null` if the function is
/// part of a top-level getter.
FormalParameterListImpl? _parameters;
/// The body of the function.
FunctionBodyImpl _body;
/// If resolution has been performed, this boolean indicates whether a
/// function type was supplied via context for this function expression.
/// `false` if resolution hasn't been performed yet.
bool wasFunctionTypeSupplied = false;
@override
ExecutableElementImpl? declaredElement;
/// Initialize a newly created function declaration.
FunctionExpressionImpl({
required TypeParameterListImpl? typeParameters,
required FormalParameterListImpl? parameters,
required FunctionBodyImpl body,
}) : _typeParameters = typeParameters,
_parameters = parameters,
_body = body {
_becomeParentOf(_typeParameters);
_becomeParentOf(_parameters);
_becomeParentOf(_body);
}
@override
Token get beginToken {
if (typeParameters case final typeParameters?) {
return typeParameters.beginToken;
} else if (parameters case final parameters?) {
return parameters.beginToken;
}
return _body.beginToken;
}
@override
FunctionBodyImpl get body => _body;
set body(FunctionBodyImpl functionBody) {
_body = _becomeParentOf(functionBody);
}
@override
Token get endToken {
return _body.endToken;
}
@override
FormalParameterListImpl? get parameters => _parameters;
set parameters(FormalParameterListImpl? parameters) {
_parameters = _becomeParentOf(parameters);
}
@override
Precedence get precedence => Precedence.primary;
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
set typeParameters(TypeParameterListImpl? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('typeParameters', typeParameters)
..addNode('parameters', parameters)
..addNode('body', body);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitFunctionExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitFunctionExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_typeParameters?.accept(visitor);
_parameters?.accept(visitor);
_body.accept(visitor);
}
}
/// The invocation of a function resulting from evaluating an expression.
///
/// Invocations of methods and other forms of functions are represented by
/// [MethodInvocation] nodes. Invocations of getters and setters are represented
/// by either [PrefixedIdentifier] or [PropertyAccess] nodes.
///
/// functionExpressionInvocation ::=
/// [Expression] [TypeArgumentList]? [ArgumentList]
abstract final class FunctionExpressionInvocation
implements NullShortableExpression, InvocationExpression {
/// Return the expression producing the function being invoked.
@override
Expression get function;
/// Return the element associated with the function being invoked based on
/// static type information, or `null` if the AST structure has not been
/// resolved or the function could not be resolved.
ExecutableElement? get staticElement;
}
/// The invocation of a function resulting from evaluating an expression.
/// Invocations of methods and other forms of functions are represented by
/// [MethodInvocation] nodes. Invocations of getters and setters are represented
/// by either [PrefixedIdentifier] or [PropertyAccess] nodes.
///
/// functionExpressionInvocation ::=
/// [Expression] [TypeArgumentList]? [ArgumentList]
final class FunctionExpressionInvocationImpl extends InvocationExpressionImpl
with NullShortableExpressionImpl
implements FunctionExpressionInvocation {
/// The expression producing the function being invoked.
ExpressionImpl _function;
/// The element associated with the function being invoked based on static
/// type information, or `null` if the AST structure has not been resolved or
/// the function could not be resolved.
@override
ExecutableElement? staticElement;
/// Initialize a newly created function expression invocation.
FunctionExpressionInvocationImpl({
required ExpressionImpl function,
required super.typeArguments,
required super.argumentList,
}) : _function = function {
_becomeParentOf(_function);
}
@override
Token get beginToken => _function.beginToken;
@override
Token get endToken => _argumentList.endToken;
@override
ExpressionImpl get function => _function;
set function(ExpressionImpl expression) {
_function = _becomeParentOf(expression);
}
@override
Precedence get precedence => Precedence.postfix;
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('function', function)
..addNode('typeArguments', typeArguments)
..addNode('argumentList', argumentList);
@override
AstNode? get _nullShortingExtensionCandidate => parent;
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitFunctionExpressionInvocation(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitFunctionExpressionInvocation(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_function.accept(visitor);
_typeArguments?.accept(visitor);
_argumentList.accept(visitor);
}
@override
bool _extendsNullShorting(Expression descendant) =>
identical(descendant, _function);
}
/// An expression representing a reference to a function, possibly with type
/// arguments applied to it, e.g. the expression `print` in `var x = print;`.
abstract final class FunctionReference
implements Expression, CommentReferableExpression {
/// The function being referenced.
///
/// In error-free code, this will be either a SimpleIdentifier (indicating a
/// function that is in scope), a PrefixedIdentifier (indicating a either
/// function imported via prefix or a static method in a class), or a
/// PropertyAccess (indicating a static method in a class imported via
/// prefix). In code with errors, this could be other kinds of expressions
/// (e.g. `(...)<int>` parses as a FunctionReference whose referent is a
/// ParenthesizedExpression.
Expression get function;
/// The type arguments being applied to the function, or `null` if there are
/// no type arguments.
TypeArgumentList? get typeArguments;
/// The actual type arguments being applied to the function, either explicitly
/// specified in [typeArguments], or inferred.
///
/// If the AST has been resolved, never returns `null`, returns an empty list
/// if the function does not have type parameters.
///
/// Returns `null` if the AST structure has not been resolved.
List<DartType>? get typeArgumentTypes;
}
/// An expression representing a reference to a function, possibly with type
/// arguments applied to it, e.g. the expression `print` in `var x = print;`.
final class FunctionReferenceImpl extends CommentReferableExpressionImpl
implements FunctionReference {
ExpressionImpl _function;
TypeArgumentListImpl? _typeArguments;
@override
List<DartType>? typeArgumentTypes;
FunctionReferenceImpl({
required ExpressionImpl function,
required TypeArgumentListImpl? typeArguments,
}) : _function = function,
_typeArguments = typeArguments {
_becomeParentOf(_function);
_becomeParentOf(_typeArguments);
}
@override
Token get beginToken => function.beginToken;
@override
Token get endToken => typeArguments?.endToken ?? function.endToken;
@override
ExpressionImpl get function => _function;
set function(ExpressionImpl value) {
_function = _becomeParentOf(value);
}
@override
Precedence get precedence =>
typeArguments == null ? function.precedence : Precedence.postfix;
@override
TypeArgumentListImpl? get typeArguments => _typeArguments;
set typeArguments(TypeArgumentListImpl? value) {
_typeArguments = _becomeParentOf(value);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('function', function)
..addNode('typeArguments', typeArguments);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitFunctionReference(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitFunctionReference(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
function.accept(visitor);
typeArguments?.accept(visitor);
}
}
/// A function type alias.
///
/// functionTypeAlias ::=
/// 'typedef' functionPrefix [TypeParameterList]? [FormalParameterList] ';'
///
/// functionPrefix ::=
/// [TypeAnnotation]? [SimpleIdentifier]
abstract final class FunctionTypeAlias implements TypeAlias {
@override
TypeAliasElement? get declaredElement;
/// Return the parameters associated with the function type.
FormalParameterList get parameters;
/// Return the return type of the function type being defined, or `null` if no
/// return type was given.
TypeAnnotation? get returnType;
/// Return the type parameters for the function type, or `null` if the
/// function type does not have any type parameters.
TypeParameterList? get typeParameters;
}
/// A function type alias.
///
/// functionTypeAlias ::=
/// 'typedef' functionPrefix [TypeParameterList]? [FormalParameterList] ';'
///
/// functionPrefix ::=
/// [TypeAnnotation]? [SimpleIdentifier]
final class FunctionTypeAliasImpl extends TypeAliasImpl
implements FunctionTypeAlias {
/// The name of the return type of the function type being defined, or `null`
/// if no return type was given.
TypeAnnotationImpl? _returnType;
/// The type parameters for the function type, or `null` if the function type
/// does not have any type parameters.
TypeParameterListImpl? _typeParameters;
/// The parameters associated with the function type.
FormalParameterListImpl _parameters;
@override
TypeAliasElementImpl? declaredElement;
/// Initialize a newly created function type alias. Either or both of the
/// [comment] and [metadata] can be `null` if the function does not have the
/// corresponding attribute. The [returnType] can be `null` if no return type
/// was specified. The [typeParameters] can be `null` if the function has no
/// type parameters.
FunctionTypeAliasImpl({
required super.comment,
required super.metadata,
required super.typedefKeyword,
required TypeAnnotationImpl? returnType,
required super.name,
required TypeParameterListImpl? typeParameters,
required FormalParameterListImpl parameters,
required super.semicolon,
}) : _returnType = returnType,
_typeParameters = typeParameters,
_parameters = parameters {
_becomeParentOf(_returnType);
_becomeParentOf(_typeParameters);
_becomeParentOf(_parameters);
}
@override
FormalParameterListImpl get parameters => _parameters;
set parameters(FormalParameterListImpl parameters) {
_parameters = _becomeParentOf(parameters);
}
@override
TypeAnnotationImpl? get returnType => _returnType;
set returnType(TypeAnnotationImpl? type) {
_returnType = _becomeParentOf(type);
}
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
set typeParameters(TypeParameterListImpl? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('typedefKeyword', typedefKeyword)
..addNode('returnType', returnType)
..addToken('name', name)
..addNode('typeParameters', typeParameters)
..addNode('parameters', parameters)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitFunctionTypeAlias(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_returnType?.accept(visitor);
_typeParameters?.accept(visitor);
_parameters.accept(visitor);
}
}
/// A function-typed formal parameter.
///
/// functionSignature ::=
/// [TypeAnnotation]? name [TypeParameterList]?
/// [FormalParameterList] '?'?
abstract final class FunctionTypedFormalParameter
implements NormalFormalParameter {
@override
Token get name;
/// Return the parameters of the function-typed parameter.
FormalParameterList get parameters;
/// Return the question mark indicating that the function type is nullable, or
/// `null` if there is no question mark. Having a nullable function type means
/// that the parameter can be null.
Token? get question;
/// Return the return type of the function, or `null` if the function does not
/// have a return type.
TypeAnnotation? get returnType;
/// Return the type parameters associated with this function, or `null` if
/// this function is not a generic function.
TypeParameterList? get typeParameters;
}
/// A function-typed formal parameter.
///
/// functionSignature ::=
/// [NamedType]? [SimpleIdentifier] [TypeParameterList]?
/// [FormalParameterList] '?'?
final class FunctionTypedFormalParameterImpl extends NormalFormalParameterImpl
implements FunctionTypedFormalParameter {
/// The return type of the function, or `null` if the function does not have a
/// return type.
TypeAnnotationImpl? _returnType;
/// The type parameters associated with the function, or `null` if the
/// function is not a generic function.
TypeParameterListImpl? _typeParameters;
/// The parameters of the function-typed parameter.
FormalParameterListImpl _parameters;
@override
final Token? question;
/// Initialize a newly created formal parameter. Either or both of the
/// [comment] and [metadata] can be `null` if the parameter does not have the
/// corresponding attribute. The [returnType] can be `null` if no return type
/// was specified.
FunctionTypedFormalParameterImpl({
required super.comment,
required super.metadata,
required super.covariantKeyword,
required super.requiredKeyword,
required TypeAnnotationImpl? returnType,
required super.name,
required TypeParameterListImpl? typeParameters,
required FormalParameterListImpl parameters,
required this.question,
}) : _returnType = returnType,
_typeParameters = typeParameters,
_parameters = parameters {
_becomeParentOf(_returnType);
_becomeParentOf(_typeParameters);
_becomeParentOf(_parameters);
}
@override
Token get beginToken {
final metadata = this.metadata;
if (metadata.isNotEmpty) {
return metadata.beginToken!;
} else if (requiredKeyword case final requiredKeyword?) {
return requiredKeyword;
} else if (covariantKeyword case final covariantKeyword?) {
return covariantKeyword;
} else if (returnType case final returnType?) {
return returnType.beginToken;
}
return name;
}
@override
Token get endToken => question ?? _parameters.endToken;
@override
bool get isConst => false;
@override
bool get isExplicitlyTyped => true;
@override
bool get isFinal => false;
@override
Token get name => super.name!;
@override
FormalParameterListImpl get parameters => _parameters;
set parameters(FormalParameterListImpl parameters) {
_parameters = _becomeParentOf(parameters);
}
@override
TypeAnnotationImpl? get returnType => _returnType;
set returnType(TypeAnnotationImpl? type) {
_returnType = _becomeParentOf(type);
}
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
set typeParameters(TypeParameterListImpl? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters);
}
@override
ChildEntities get _childEntities => super._childEntities
..addNode('returnType', returnType)
..addToken('name', name)
..addNode('parameters', parameters);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitFunctionTypedFormalParameter(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_returnType?.accept(visitor);
_typeParameters?.accept(visitor);
_parameters.accept(visitor);
}
}
/// An anonymous function type.
///
/// functionType ::=
/// [TypeAnnotation]? 'Function' [TypeParameterList]?
/// [FormalParameterList] '?'?
///
/// where the FormalParameterList is being used to represent the following
/// grammar, despite the fact that FormalParameterList can represent a much
/// larger grammar than the one below. This is done in order to simplify the
/// implementation.
///
/// parameterTypeList ::=
/// () |
/// ( normalParameterTypes ,? ) |
/// ( normalParameterTypes , optionalParameterTypes ) |
/// ( optionalParameterTypes )
/// namedParameterTypes ::=
/// { namedParameterType (, namedParameterType)* ,? }
/// namedParameterType ::=
/// [TypeAnnotation]? [SimpleIdentifier]
/// normalParameterTypes ::=
/// normalParameterType (, normalParameterType)*
/// normalParameterType ::=
/// [TypeAnnotation] [SimpleIdentifier]?
/// optionalParameterTypes ::=
/// optionalPositionalParameterTypes | namedParameterTypes
/// optionalPositionalParameterTypes ::=
/// [ normalParameterTypes ,? ]
abstract final class GenericFunctionType implements TypeAnnotation {
/// Return the keyword 'Function'.
Token get functionKeyword;
/// Return the parameters associated with the function type.
FormalParameterList get parameters;
/// Return the return type of the function type being defined, or `null` if
/// no return type was given.
TypeAnnotation? get returnType;
/// Return the type parameters for the function type, or `null` if the
/// function type does not have any type parameters.
TypeParameterList? get typeParameters;
}
/// An anonymous function type.
///
/// functionType ::=
/// [TypeAnnotation]? 'Function' [TypeParameterList]?
/// [FormalParameterList]
///
/// where the FormalParameterList is being used to represent the following
/// grammar, despite the fact that FormalParameterList can represent a much
/// larger grammar than the one below. This is done in order to simplify the
/// implementation.
///
/// parameterTypeList ::=
/// () |
/// ( normalParameterTypes ,? ) |
/// ( normalParameterTypes , optionalParameterTypes ) |
/// ( optionalParameterTypes )
/// namedParameterTypes ::=
/// { namedParameterType (, namedParameterType)* ,? }
/// namedParameterType ::=
/// [TypeAnnotation]? [SimpleIdentifier]
/// normalParameterTypes ::=
/// normalParameterType (, normalParameterType)*
/// normalParameterType ::=
/// [TypeAnnotation] [SimpleIdentifier]?
/// optionalParameterTypes ::=
/// optionalPositionalParameterTypes | namedParameterTypes
/// optionalPositionalParameterTypes ::=
/// [ normalParameterTypes ,? ]
final class GenericFunctionTypeImpl extends TypeAnnotationImpl
implements GenericFunctionType {
/// The name of the return type of the function type being defined, or
/// `null` if no return type was given.
TypeAnnotationImpl? _returnType;
@override
final Token functionKeyword;
/// The type parameters for the function type, or `null` if the function type
/// does not have any type parameters.
TypeParameterListImpl? _typeParameters;
/// The parameters associated with the function type.
FormalParameterListImpl _parameters;
@override
final Token? question;
@override
DartType? type;
/// Return the element associated with the function type, or `null` if the
/// AST structure has not been resolved.
GenericFunctionTypeElementImpl? declaredElement;
/// Initialize a newly created generic function type.
GenericFunctionTypeImpl({
required TypeAnnotationImpl? returnType,
required this.functionKeyword,
required TypeParameterListImpl? typeParameters,
required FormalParameterListImpl parameters,
required this.question,
}) : _returnType = returnType,
_typeParameters = typeParameters,
_parameters = parameters {
_becomeParentOf(_returnType);
_becomeParentOf(_typeParameters);
_becomeParentOf(_parameters);
}
@override
Token get beginToken => _returnType?.beginToken ?? functionKeyword;
@override
Token get endToken => question ?? _parameters.endToken;
@override
FormalParameterListImpl get parameters => _parameters;
set parameters(FormalParameterListImpl parameters) {
_parameters = _becomeParentOf(parameters);
}
@override
TypeAnnotationImpl? get returnType => _returnType;
set returnType(TypeAnnotationImpl? type) {
_returnType = _becomeParentOf(type);
}
/// Return the type parameters for the function type, or `null` if the
/// function type does not have any type parameters.
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
/// Set the type parameters for the function type to the given list of
/// [typeParameters].
set typeParameters(TypeParameterListImpl? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('returnType', returnType)
..addToken('functionKeyword', functionKeyword)
..addNode('typeParameters', typeParameters)
..addNode('parameters', parameters)
..addToken('question', question);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitGenericFunctionType(this);
}
@override
void visitChildren(AstVisitor visitor) {
_returnType?.accept(visitor);
_typeParameters?.accept(visitor);
_parameters.accept(visitor);
}
}
/// A generic type alias.
///
/// functionTypeAlias ::=
/// 'typedef' [SimpleIdentifier] [TypeParameterList]? = [FunctionType] ';'
abstract final class GenericTypeAlias implements TypeAlias {
/// Return the equal sign separating the name being defined from the function
/// type.
Token get equals;
/// Return the type of function being defined by the alias.
///
/// When the non-function type aliases feature is enabled and the denoted
/// type is not a [GenericFunctionType], return `null`.
GenericFunctionType? get functionType;
/// Return the type being defined by the alias.
TypeAnnotation get type;
/// Return the type parameters for the function type, or `null` if the
/// function type does not have any type parameters.
TypeParameterList? get typeParameters;
}
/// A generic type alias.
///
/// functionTypeAlias ::=
/// 'typedef' [SimpleIdentifier] [TypeParameterList]? = [FunctionType] ';'
final class GenericTypeAliasImpl extends TypeAliasImpl
implements GenericTypeAlias {
/// The type being defined by the alias.
TypeAnnotationImpl _type;
/// The type parameters for the function type, or `null` if the function
/// type does not have any type parameters.
TypeParameterListImpl? _typeParameters;
@override
final Token equals;
@override
ElementImpl? declaredElement;
/// Returns a newly created generic type alias. Either or both of the
/// [comment] and [metadata] can be `null` if the variable list does not have
/// the corresponding attribute. The [typeParameters] can be `null` if there
/// are no type parameters.
GenericTypeAliasImpl({
required super.comment,
required super.metadata,
required super.typedefKeyword,
required super.name,
required TypeParameterListImpl? typeParameters,
required this.equals,
required TypeAnnotationImpl type,
required super.semicolon,
}) : _typeParameters = typeParameters,
_type = type {
_becomeParentOf(_typeParameters);
_becomeParentOf(_type);
}
/// The type of function being defined by the alias.
///
/// If the non-function type aliases feature is enabled, a type alias may have
/// a [_type] which is not a [GenericFunctionTypeImpl]. In that case `null`
/// is returned.
@override
GenericFunctionType? get functionType {
var type = _type;
return type is GenericFunctionTypeImpl ? type : null;
}
set functionType(GenericFunctionType? functionType) {
_type = _becomeParentOf(functionType as GenericFunctionTypeImpl?)!;
}
@override
TypeAnnotationImpl get type => _type;
/// Set the type being defined by the alias to the given [TypeAnnotation].
set type(TypeAnnotationImpl typeAnnotation) {
_type = _becomeParentOf(typeAnnotation);
}
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
set typeParameters(TypeParameterListImpl? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNodeList('metadata', metadata)
..addToken('typedefKeyword', typedefKeyword)
..addToken('name', name)
..addNode('typeParameters', typeParameters)
..addToken('equals', equals)
..addNode('type', type);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitGenericTypeAlias(this);
}
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_typeParameters?.accept(visitor);
_type.accept(visitor);
}
}
/// The pattern with an optional [WhenClause].
///
/// guardedPattern ::=
/// [DartPattern] [WhenClause]?
abstract final class GuardedPattern implements AstNode {
/// Return the pattern controlling whether the statements will be executed.
DartPattern get pattern;
/// Return the clause controlling whether the statements will be executed.
WhenClause? get whenClause;
}
/// The `case` clause that can optionally appear in an `if` statement.
///
/// caseClause ::=
/// 'case' [DartPattern] [WhenClause]?
final class GuardedPatternImpl extends AstNodeImpl implements GuardedPattern {
@override
final DartPatternImpl pattern;
/// Variables declared in [pattern], available in [whenClause] guard, and
/// to the `ifTrue` node.
late Map<String, PatternVariableElementImpl> variables;
@override
final WhenClauseImpl? whenClause;
GuardedPatternImpl({
required this.pattern,
required this.whenClause,
}) {
_becomeParentOf(pattern);
_becomeParentOf(whenClause);
}
@override
Token get beginToken => pattern.beginToken;
@override
Token get endToken => whenClause?.endToken ?? pattern.endToken;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('pattern', pattern)
..addNode('whenClause', whenClause);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitGuardedPattern(this);
@override
void visitChildren(AstVisitor visitor) {
pattern.accept(visitor);
whenClause?.accept(visitor);
}
}
/// A combinator that restricts the names being imported to those that are not
/// in a given list.
///
/// hideCombinator ::=
/// 'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
abstract final class HideCombinator implements Combinator {
/// Return the list of names from the library that are hidden by this
/// combinator.
NodeList<SimpleIdentifier> get hiddenNames;
}
/// A combinator that restricts the names being imported to those that are not
/// in a given list.
///
/// hideCombinator ::=
/// 'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
final class HideCombinatorImpl extends CombinatorImpl
implements HideCombinator {
/// The list of names from the library that are hidden by this combinator.
final NodeListImpl<SimpleIdentifierImpl> _hiddenNames = NodeListImpl._();
/// Initialize a newly created import show combinator.
HideCombinatorImpl({
required super.keyword,
required List<SimpleIdentifierImpl> hiddenNames,
}) {
_hiddenNames._initialize(this, hiddenNames);
}
@override
Token get endToken => _hiddenNames.endToken!;
@override
NodeListImpl<SimpleIdentifierImpl> get hiddenNames => _hiddenNames;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('keyword', keyword)
..addNodeList('hiddenNames', hiddenNames);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitHideCombinator(this);
@override
void visitChildren(AstVisitor visitor) {
_hiddenNames.accept(visitor);
}
}
/// A node that represents an identifier.
///
/// identifier ::=
/// [SimpleIdentifier]
/// | [PrefixedIdentifier]
sealed class Identifier implements Expression, CommentReferableExpression {
/// Return the lexical representation of the identifier.
String get name;
/// Return the element associated with this identifier based on static type
/// information, or `null` if the AST structure has not been resolved or if
/// this identifier could not be resolved.
///
/// One example of the latter case is an identifier that is not defined
/// within the scope in which it appears.
Element? get staticElement;
/// Return `true` if the given [name] is visible only within the library in
/// which it is declared.
static bool isPrivateName(String name) => name.isNotEmpty && name[0] == "_";
}
/// A node that represents an identifier.
///
/// identifier ::=
/// [SimpleIdentifier]
/// | [PrefixedIdentifier]
sealed class IdentifierImpl extends CommentReferableExpressionImpl
implements Identifier {
@override
bool get isAssignable => true;
}
/// The basic structure of an if element.
abstract final class IfElement implements CollectionElement {
/// Return the `case` clause used to match a pattern against the [expression].
CaseClause? get caseClause;
/// Return the condition used to determine which of the statements is executed
/// next.
@Deprecated('Use expression instead')
Expression get condition;
/// Return the statement that is executed if the condition evaluates to
/// `false`, or `null` if there is no else statement.
CollectionElement? get elseElement;
/// Return the token representing the 'else' keyword, or `null` if there is no
/// else statement.
Token? get elseKeyword;
/// Return the expression used to either determine which of the statements is
/// executed next or to compute the value to be matched against the pattern in
/// the `case` clause.
Expression get expression;
/// Return the token representing the 'if' keyword.
Token get ifKeyword;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right parenthesis.
Token get rightParenthesis;
/// Return the statement that is executed if the condition evaluates to
/// `true`.
CollectionElement get thenElement;
}
final class IfElementImpl extends CollectionElementImpl
implements IfElement, IfElementOrStatementImpl<CollectionElementImpl> {
@override
final Token ifKeyword;
@override
final Token leftParenthesis;
ExpressionImpl _expression;
@override
final CaseClauseImpl? caseClause;
@override
final Token rightParenthesis;
@override
final Token? elseKeyword;
/// The element to be executed if the condition is `true`.
CollectionElementImpl _thenElement;
/// The element to be executed if the condition is `false`, or `null` if there
/// is no such element.
CollectionElementImpl? _elseElement;
/// Initialize a newly created for element.
IfElementImpl({
required this.ifKeyword,
required this.leftParenthesis,
required ExpressionImpl expression,
required this.caseClause,
required this.rightParenthesis,
required CollectionElementImpl thenElement,
required this.elseKeyword,
required CollectionElementImpl? elseElement,
}) : _expression = expression,
_thenElement = thenElement,
_elseElement = elseElement {
_becomeParentOf(_expression);
_becomeParentOf(caseClause);
_becomeParentOf(_thenElement);
_becomeParentOf(_elseElement);
}
@override
Token get beginToken => ifKeyword;
@Deprecated('Use expression instead')
@override
ExpressionImpl get condition => _expression;
set condition(ExpressionImpl condition) {
_expression = _becomeParentOf(condition);
}
@override
CollectionElementImpl? get elseElement => _elseElement;
set elseElement(CollectionElementImpl? element) {
_elseElement = _becomeParentOf(element);
}
@override
Token get endToken => _elseElement?.endToken ?? _thenElement.endToken;
@override
ExpressionImpl get expression => _expression;
@override
CollectionElementImpl? get ifFalse => elseElement;
@override
CollectionElementImpl get ifTrue => thenElement;
@override
CollectionElementImpl get thenElement => _thenElement;
set thenElement(CollectionElementImpl element) {
_thenElement = _becomeParentOf(element);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('ifKeyword', ifKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('expression', expression)
..addNode('caseClause', caseClause)
..addToken('rightParenthesis', rightParenthesis)
..addNode('thenElement', thenElement)
..addToken('elseKeyword', elseKeyword)
..addNode('elseElement', elseElement);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitIfElement(this);
@override
void resolveElement(
ResolverVisitor resolver, CollectionLiteralContext? context) {
resolver.visitIfElement(this, context: context);
resolver.pushRewrite(null);
}
@override
void visitChildren(AstVisitor visitor) {
expression.accept(visitor);
caseClause?.accept(visitor);
_thenElement.accept(visitor);
_elseElement?.accept(visitor);
}
}
sealed class IfElementOrStatementImpl<E extends AstNodeImpl>
implements AstNodeImpl {
/// Return the `case` clause used to match a pattern against the [expression].
CaseClauseImpl? get caseClause;
/// Return the expression used to either determine which of the statements is
/// executed next or to compute the value matched against the pattern in the
/// `case` clause.
ExpressionImpl get expression;
/// The node that is executed if the condition evaluates to `false`.
E? get ifFalse;
/// The node that is executed if the condition evaluates to `true`.
E get ifTrue;
}
/// An if statement.
///
/// ifStatement ::=
/// 'if' '(' [Expression] [CaseClause]? ')'[Statement]
/// ('else' [Statement])?
abstract final class IfStatement implements Statement {
/// Return the `case` clause used to match a pattern against the [expression].
CaseClause? get caseClause;
/// Return the condition used to determine which of the statements is executed
/// next.
@Deprecated('Use expression instead')
Expression get condition;
/// Return the token representing the 'else' keyword, or `null` if there is no
/// else statement.
Token? get elseKeyword;
/// Return the statement that is executed if the condition evaluates to
/// `false`, or `null` if there is no else statement.
Statement? get elseStatement;
/// Return the expression used to either determine which of the statements is
/// executed next or to compute the value matched against the pattern in the
/// `case` clause.
Expression get expression;
/// Return the token representing the 'if' keyword.
// TODO(scheglov): Extract shared `IfCondition`, see the patterns spec.
Token get ifKeyword;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right parenthesis.
Token get rightParenthesis;
/// Return the statement that is executed if the condition evaluates to
/// `true`.
Statement get thenStatement;
}
/// An if statement.
///
/// ifStatement ::=
/// 'if' '(' [Expression] [CaseClause]? ')'[Statement]
/// ('else' [Statement])?
final class IfStatementImpl extends StatementImpl
implements IfStatement, IfElementOrStatementImpl<StatementImpl> {
@override
final Token ifKeyword;
@override
final Token leftParenthesis;
/// The condition used to determine which of the branches is executed next.
ExpressionImpl _expression;
@override
final CaseClauseImpl? caseClause;
@override
final Token rightParenthesis;
@override
final Token? elseKeyword;
/// The statement that is executed if the condition evaluates to `true`.
StatementImpl _thenStatement;
/// The statement that is executed if the condition evaluates to `false`, or
/// `null` if there is no else statement.
StatementImpl? _elseStatement;
/// Initialize a newly created if statement. The [elseKeyword] and
/// [elseStatement] can be `null` if there is no else clause.
IfStatementImpl({
required this.ifKeyword,
required this.leftParenthesis,
required ExpressionImpl expression,
required this.caseClause,
required this.rightParenthesis,
required StatementImpl thenStatement,
required this.elseKeyword,
required StatementImpl? elseStatement,
}) : _expression = expression,
_thenStatement = thenStatement,
_elseStatement = elseStatement {
_becomeParentOf(_expression);
_becomeParentOf(caseClause);
_becomeParentOf(_thenStatement);
_becomeParentOf(_elseStatement);
}
@override
Token get beginToken => ifKeyword;
@Deprecated('Use expression instead')
@override
ExpressionImpl get condition => _expression;
set condition(ExpressionImpl condition) {
_expression = _becomeParentOf(condition);
}
@override
StatementImpl? get elseStatement => _elseStatement;
set elseStatement(StatementImpl? statement) {
_elseStatement = _becomeParentOf(statement);
}
@override
Token get endToken {
if (elseStatement case final elseStatement?) {
return elseStatement.endToken;
}
return _thenStatement.endToken;
}
@override
ExpressionImpl get expression => _expression;
@override
StatementImpl? get ifFalse => elseStatement;
@override
StatementImpl get ifTrue => thenStatement;
@override
StatementImpl get thenStatement => _thenStatement;
set thenStatement(StatementImpl statement) {
_thenStatement = _becomeParentOf(statement);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('ifKeyword', ifKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('expression', expression)
..addNode('caseClause', caseClause)
..addToken('rightParenthesis', rightParenthesis)
..addNode('thenStatement', thenStatement)
..addToken('elseKeyword', elseKeyword)
..addNode('elseStatement', elseStatement);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitIfStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
caseClause?.accept(visitor);
_thenStatement.accept(visitor);
_elseStatement?.accept(visitor);
}
}
/// The "implements" clause in an class declaration.
///
/// implementsClause ::=
/// 'implements' [NamedType] (',' [NamedType])*
abstract final class ImplementsClause implements AstNode {
/// Return the token representing the 'implements' keyword.
Token get implementsKeyword;
/// Return the list of the interfaces that are being implemented.
NodeList<NamedType> get interfaces;
}
/// The "implements" clause in an class declaration.
///
/// implementsClause ::=
/// 'implements' [NamedType] (',' [NamedType])*
final class ImplementsClauseImpl extends AstNodeImpl
implements ImplementsClause {
/// The token representing the 'implements' keyword.
@override
final Token implementsKeyword;
/// The interfaces that are being implemented.
final NodeListImpl<NamedTypeImpl> _interfaces = NodeListImpl._();
/// Initialize a newly created implements clause.
ImplementsClauseImpl({
required this.implementsKeyword,
required List<NamedTypeImpl> interfaces,
}) {
_interfaces._initialize(this, interfaces);
}
@override
Token get beginToken => implementsKeyword;
@override
Token get endToken => _interfaces.endToken ?? implementsKeyword;
@override
NodeListImpl<NamedTypeImpl> get interfaces => _interfaces;
@override
// TODO(paulberry): add commas.
ChildEntities get _childEntities => ChildEntities()
..addToken('implementsKeyword', implementsKeyword)
..addNodeList('interfaces', interfaces);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitImplementsClause(this);
@override
void visitChildren(AstVisitor visitor) {
_interfaces.accept(visitor);
}
}
/// An expression representing an implicit 'call' method reference.
///
/// Objects of this type are not produced directly by the parser (because the
/// parser cannot tell whether an expression refers to a callable type); they
/// are produced at resolution time.
abstract final class ImplicitCallReference
implements MethodReferenceExpression {
/// Return the expression from which a `call` method is being referenced.
Expression get expression;
/// Return the element associated with the implicit 'call' reference based on
/// the static types.
@override
MethodElement get staticElement;
/// The type arguments being applied to the tear-off, or `null` if there are
/// no type arguments.
TypeArgumentList? get typeArguments;
/// The actual type arguments being applied to the tear-off, either explicitly
/// specified in [typeArguments], or inferred.
///
/// Returns an empty list if the 'call' method does not have type parameters.
List<DartType> get typeArgumentTypes;
}
final class ImplicitCallReferenceImpl extends ExpressionImpl
implements ImplicitCallReference {
ExpressionImpl _expression;
TypeArgumentListImpl? _typeArguments;
@override
List<DartType> typeArgumentTypes;
@override
MethodElement staticElement;
ImplicitCallReferenceImpl({
required ExpressionImpl expression,
required this.staticElement,
required TypeArgumentListImpl? typeArguments,
required this.typeArgumentTypes,
}) : _expression = expression,
_typeArguments = typeArguments {
_becomeParentOf(_expression);
_becomeParentOf(_typeArguments);
}
@override
Token get beginToken => expression.beginToken;
@override
Token get endToken => typeArguments?.endToken ?? expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl value) {
_expression = _becomeParentOf(value);
}
@override
Precedence get precedence =>
typeArguments == null ? expression.precedence : Precedence.postfix;
@override
TypeArgumentListImpl? get typeArguments => _typeArguments;
set typeArguments(TypeArgumentListImpl? value) {
_typeArguments = _becomeParentOf(value);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('expression', expression)
..addNode('typeArguments', typeArguments);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitImplicitCallReference(this);
}
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitImplicitCallReference(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
expression.accept(visitor);
typeArguments?.accept(visitor);
}
}
/// An import directive.
///
/// importDirective ::=
/// [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
/// | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
abstract final class ImportDirective implements NamespaceDirective {
/// Return the token representing the 'as' keyword, or `null` if the imported
/// names are not prefixed.
Token? get asKeyword;
/// Return the token representing the 'deferred' keyword, or `null` if the
/// imported URI is not deferred.
Token? get deferredKeyword;
/// Return the element associated with this directive, or `null` if the AST
/// structure has not been resolved.
@override
LibraryImportElement? get element;
/// The token representing the 'import' keyword.
Token get importKeyword;
/// Return the prefix to be used with the imported names, or `null` if the
/// imported names are not prefixed.
SimpleIdentifier? get prefix;
}
/// An import directive.
///
/// importDirective ::=
/// [Annotation] 'import' [StringLiteral] ('as' identifier)?
// [Combinator]* ';'
/// | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier
// [Combinator]* ';'
final class ImportDirectiveImpl extends NamespaceDirectiveImpl
implements ImportDirective {
@override
final Token importKeyword;
/// The token representing the 'deferred' keyword, or `null` if the imported
/// is not deferred.
@override
final Token? deferredKeyword;
/// The token representing the 'as' keyword, or `null` if the imported names
/// are not prefixed.
@override
final Token? asKeyword;
/// The prefix to be used with the imported names, or `null` if the imported
/// names are not prefixed.
SimpleIdentifierImpl? _prefix;
/// Initialize a newly created import directive. Either or both of the
/// [comment] and [metadata] can be `null` if the function does not have the
/// corresponding attribute. The [deferredKeyword] can be `null` if the import
/// is not deferred. The [asKeyword] and [prefix] can be `null` if the import
/// does not specify a prefix. The list of [combinators] can be `null` if
/// there are no combinators.
ImportDirectiveImpl({
required super.comment,
required super.metadata,
required this.importKeyword,
required super.uri,
required super.configurations,
required this.deferredKeyword,
required this.asKeyword,
required SimpleIdentifierImpl? prefix,
required super.combinators,
required super.semicolon,
}) : _prefix = prefix {
_becomeParentOf(_prefix);
}
@override
LibraryImportElementImpl? get element =>
super.element as LibraryImportElementImpl?;
@override
Token get firstTokenAfterCommentAndMetadata => importKeyword;
@override
SimpleIdentifierImpl? get prefix => _prefix;
set prefix(SimpleIdentifierImpl? identifier) {
_prefix = _becomeParentOf(identifier);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('importKeyword', importKeyword)
..addNode('uri', uri)
..addToken('deferredKeyword', deferredKeyword)
..addToken('asKeyword', asKeyword)
..addNode('prefix', prefix)
..addNodeList('combinators', combinators)
..addNodeList('configurations', configurations)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitImportDirective(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
configurations.accept(visitor);
_prefix?.accept(visitor);
combinators.accept(visitor);
}
/// Return `true` if the non-URI components of the two directives are
/// syntactically identical. URIs are checked outside to see if they resolve
/// to the same absolute URI, so to the same library, regardless of the used
/// syntax (absolute, relative, not normalized).
static bool areSyntacticallyIdenticalExceptUri(
NamespaceDirective node1,
NamespaceDirective node2,
) {
if (node1 is ImportDirective &&
node2 is ImportDirective &&
node1.prefix?.name != node2.prefix?.name) {
return false;
}
bool areSameNames(
List<SimpleIdentifier> names1,
List<SimpleIdentifier> names2,
) {
if (names1.length != names2.length) {
return false;
}
for (var i = 0; i < names1.length; i++) {
if (names1[i].name != names2[i].name) {
return false;
}
}
return true;
}
final combinators1 = node1.combinators;
final combinators2 = node2.combinators;
if (combinators1.length != combinators2.length) {
return false;
}
for (var i = 0; i < combinators1.length; i++) {
final combinator1 = combinators1[i];
final combinator2 = combinators2[i];
if (combinator1 is HideCombinator && combinator2 is HideCombinator) {
if (!areSameNames(combinator1.hiddenNames, combinator2.hiddenNames)) {
return false;
}
} else if (combinator1 is ShowCombinator &&
combinator2 is ShowCombinator) {
if (!areSameNames(combinator1.shownNames, combinator2.shownNames)) {
return false;
}
} else {
return false;
}
}
return true;
}
}
/// Reference to an import prefix name.
abstract final class ImportPrefixReference implements AstNode {
/// The element to which [name] is resolved. Usually a [PrefixElement], but
/// can be anything in invalid code.
Element? get element;
/// The name of the referenced import prefix.
Token get name;
/// The `.` that separates [name] from the following identifier.
Token get period;
}
final class ImportPrefixReferenceImpl extends AstNodeImpl
implements ImportPrefixReference {
@override
final Token name;
@override
final Token period;
@override
Element? element;
ImportPrefixReferenceImpl({
required this.name,
required this.period,
});
@override
Token get beginToken => name;
@override
Token get endToken => period;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('name', name)
..addToken('period', period);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitImportPrefixReference(this);
}
@override
void visitChildren(AstVisitor visitor) {}
}
/// An index expression.
///
/// indexExpression ::=
/// [Expression] '[' [Expression] ']'
abstract final class IndexExpression
implements NullShortableExpression, MethodReferenceExpression {
/// Return the expression used to compute the index.
Expression get index;
/// Return `true` if this expression is cascaded.
///
/// If it is, then the target of this expression is not stored locally but is
/// stored in the nearest ancestor that is a [CascadeExpression].
bool get isCascaded;
/// Whether this index expression is null aware (as opposed to non-null).
bool get isNullAware;
/// Return the left square bracket.
Token get leftBracket;
/// Return the period (".." | "?..") before a cascaded index expression, or
/// `null` if this index expression is not part of a cascade expression.
Token? get period;
/// Return the question mark before the left bracket, or `null` if there is no
/// question mark.
Token? get question;
/// Return the expression used to compute the object being indexed.
///
/// If this index expression is not part of a cascade expression, then this
/// is the same as [target]. If this index expression is part of a cascade
/// expression, then the target expression stored with the cascade expression
/// is returned.
Expression get realTarget;
/// Return the right square bracket.
Token get rightBracket;
/// Return the expression used to compute the object being indexed, or `null`
/// if this index expression is part of a cascade expression.
///
/// Use [realTarget] to get the target independent of whether this is part of
/// a cascade expression.
Expression? get target;
/// Return `true` if this expression is computing a right-hand value (that is,
/// if this expression is in a context where the operator '[]' will be
/// invoked).
///
/// Note that [inGetterContext] and [inSetterContext] are not opposites, nor
/// are they mutually exclusive. In other words, it is possible for both
/// methods to return `true` when invoked on the same node.
// TODO(brianwilkerson): Convert this to a getter.
bool inGetterContext();
/// Return `true` if this expression is computing a left-hand value (that is,
/// if this expression is in a context where the operator '[]=' will be
/// invoked).
///
/// Note that [inGetterContext] and [inSetterContext] are not opposites, nor
/// are they mutually exclusive. In other words, it is possible for both
/// methods to return `true` when invoked on the same node.
// TODO(brianwilkerson): Convert this to a getter.
bool inSetterContext();
}
/// An index expression.
///
/// indexExpression ::=
/// [Expression] '[' [Expression] ']'
final class IndexExpressionImpl extends ExpressionImpl
with NullShortableExpressionImpl
implements IndexExpression {
@override
Token? period;
/// The expression used to compute the object being indexed, or `null` if this
/// index expression is part of a cascade expression.
ExpressionImpl? _target;
@override
final Token? question;
@override
final Token leftBracket;
/// The expression used to compute the index.
ExpressionImpl _index;
@override
final Token rightBracket;
/// The element associated with the operator based on the static type of the
/// target, or `null` if the AST structure has not been resolved or if the
/// operator could not be resolved.
@override
MethodElement? staticElement;
/// Initialize a newly created index expression that is a child of a cascade
/// expression.
IndexExpressionImpl.forCascade({
required this.period,
required this.question,
required this.leftBracket,
required ExpressionImpl index,
required this.rightBracket,
}) : _index = index {
_becomeParentOf(_index);
}
/// Initialize a newly created index expression that is not a child of a
/// cascade expression.
IndexExpressionImpl.forTarget({
required ExpressionImpl? target,
required this.question,
required this.leftBracket,
required ExpressionImpl index,
required this.rightBracket,
}) : _target = target,
_index = index {
_becomeParentOf(_target);
_becomeParentOf(_index);
}
@override
Token get beginToken {
if (target case final target?) {
return target.beginToken;
}
return period!;
}
@override
Token get endToken => rightBracket;
@override
ExpressionImpl get index => _index;
set index(ExpressionImpl expression) {
_index = _becomeParentOf(expression);
}
@override
bool get isAssignable => true;
@override
bool get isCascaded => period != null;
@override
bool get isNullAware {
if (isCascaded) {
return _ancestorCascade.isNullAware;
}
return question != null ||
(leftBracket.type == TokenType.OPEN_SQUARE_BRACKET &&
period != null &&
period!.type == TokenType.QUESTION_PERIOD_PERIOD);
}
@override
Precedence get precedence => Precedence.postfix;
@override
ExpressionImpl get realTarget {
if (isCascaded) {
return _ancestorCascade.target;
}
return _target!;
}
@override
ExpressionImpl? get target => _target;
set target(ExpressionImpl? expression) {
_target = _becomeParentOf(expression);
}
/// Return the cascade that contains this [IndexExpression].
///
/// We expect that [isCascaded] is `true`.
CascadeExpressionImpl get _ancestorCascade {
assert(isCascaded);
for (var ancestor = parent!;; ancestor = ancestor.parent!) {
if (ancestor is CascadeExpressionImpl) {
return ancestor;
}
}
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('target', target)
..addToken('period', period)
..addToken('leftBracket', leftBracket)
..addNode('index', index)
..addToken('rightBracket', rightBracket);
@override
AstNode get _nullShortingExtensionCandidate => parent!;
/// If the AST structure has been resolved, and the function being invoked is
/// known based on static type information, then return the parameter element
/// representing the parameter to which the value of the index expression will
/// be bound. Otherwise, return `null`.
ParameterElement? get _staticParameterElementForIndex {
Element? element = staticElement;
final parent = this.parent;
if (parent is CompoundAssignmentExpression) {
element = parent.writeElement ?? parent.readElement;
}
if (element is ExecutableElement) {
List<ParameterElement> parameters = element.parameters;
if (parameters.isEmpty) {
return null;
}
return parameters[0];
}
return null;
}
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitIndexExpression(this);
@override
bool inGetterContext() {
// TODO(brianwilkerson): Convert this to a getter.
final parent = this.parent!;
if (parent is AssignmentExpression) {
AssignmentExpression assignment = parent;
if (identical(assignment.leftHandSide, this) &&
assignment.operator.type == TokenType.EQ) {
return false;
}
}
return true;
}
@override
bool inSetterContext() {
// TODO(brianwilkerson): Convert this to a getter.
final parent = this.parent!;
if (parent is PrefixExpression) {
return parent.operator.type.isIncrementOperator;
} else if (parent is PostfixExpression) {
return parent.operator.type.isIncrementOperator;
} else if (parent is AssignmentExpression) {
return identical(parent.leftHandSide, this);
}
return false;
}
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitIndexExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_target?.accept(visitor);
_index.accept(visitor);
}
@override
bool _extendsNullShorting(Expression descendant) =>
identical(descendant, _target);
}
/// An instance creation expression.
///
/// newExpression ::=
/// ('new' | 'const')? [NamedType] ('.' [SimpleIdentifier])? [ArgumentList]
abstract final class InstanceCreationExpression implements Expression {
/// Return the list of arguments to the constructor.
ArgumentList get argumentList;
/// Return the name of the constructor to be invoked.
ConstructorName get constructorName;
/// Return `true` if this creation expression is used to invoke a constant
/// constructor, either because the keyword `const` was explicitly provided or
/// because no keyword was provided and this expression is in a constant
/// context.
bool get isConst;
/// Return the 'new' or 'const' keyword used to indicate how an object should
/// be created, or `null` if the keyword was not explicitly provided.
Token? get keyword;
}
/// An instance creation expression.
///
/// newExpression ::=
/// ('new' | 'const')? [NamedType] ('.' [SimpleIdentifier])?
/// [ArgumentList]
final class InstanceCreationExpressionImpl extends ExpressionImpl
implements InstanceCreationExpression {
// TODO(brianwilkerson): Consider making InstanceCreationExpressionImpl extend
// InvocationExpressionImpl. This would probably be a breaking change, but is
// also probably worth it.
/// The 'new' or 'const' keyword used to indicate how an object should be
/// created, or `null` if the keyword is implicit.
@override
Token? keyword;
/// The name of the constructor to be invoked.
ConstructorNameImpl _constructorName;
/// The type arguments associated with the constructor, rather than with the
/// class in which the constructor is defined. It is always an error if there
/// are type arguments because Dart doesn't currently support generic
/// constructors, but we capture them in the AST in order to recover better.
TypeArgumentListImpl? _typeArguments;
/// The list of arguments to the constructor.
ArgumentListImpl _argumentList;
/// Initialize a newly created instance creation expression.
InstanceCreationExpressionImpl({
required this.keyword,
required ConstructorNameImpl constructorName,
required ArgumentListImpl argumentList,
required TypeArgumentListImpl? typeArguments,
}) : _constructorName = constructorName,
_argumentList = argumentList,
_typeArguments = typeArguments {
_becomeParentOf(_constructorName);
_becomeParentOf(_argumentList);
_becomeParentOf(_typeArguments);
}
@override
ArgumentListImpl get argumentList => _argumentList;
set argumentList(ArgumentListImpl argumentList) {
_argumentList = _becomeParentOf(argumentList);
}
@override
Token get beginToken => keyword ?? _constructorName.beginToken;
@override
ConstructorNameImpl get constructorName => _constructorName;
set constructorName(ConstructorNameImpl name) {
_constructorName = _becomeParentOf(name);
}
@override
Token get endToken => _argumentList.endToken;
@override
bool get isConst {
if (!isImplicit) {
return keyword!.keyword == Keyword.CONST;
} else {
return inConstantContext;
}
}
/// Return `true` if this is an implicit constructor invocations.
bool get isImplicit => keyword == null;
@override
Precedence get precedence => Precedence.primary;
/// Return the type arguments associated with the constructor, rather than
/// with the class in which the constructor is defined. It is always an error
/// if there are type arguments because Dart doesn't currently support generic
/// constructors, but we capture them in the AST in order to recover better.
TypeArgumentListImpl? get typeArguments => _typeArguments;
/// Return the type arguments associated with the constructor, rather than
/// with the class in which the constructor is defined. It is always an error
/// if there are type arguments because Dart doesn't currently support generic
/// constructors, but we capture them in the AST in order to recover better.
set typeArguments(TypeArgumentListImpl? typeArguments) {
_typeArguments = _becomeParentOf(typeArguments);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('keyword', keyword)
..addNode('constructorName', constructorName)
..addNode('typeArguments', typeArguments)
..addNode('argumentList', argumentList);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitInstanceCreationExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitInstanceCreationExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_constructorName.accept(visitor);
_typeArguments?.accept(visitor);
_argumentList.accept(visitor);
}
}
/// An integer literal expression.
///
/// integerLiteral ::=
/// decimalIntegerLiteral
/// | hexadecimalIntegerLiteral
///
/// decimalIntegerLiteral ::=
/// decimalDigit+
///
/// hexadecimalIntegerLiteral ::=
/// '0x' hexadecimalDigit+
/// | '0X' hexadecimalDigit+
abstract final class IntegerLiteral implements Literal {
/// Return the token representing the literal.
Token get literal;
/// Return the value of the literal, or `null` when [literal] does not
/// represent a valid `int` value, for example because of overflow.
int? get value;
}
/// An integer literal expression.
///
/// integerLiteral ::=
/// decimalIntegerLiteral
/// | hexadecimalIntegerLiteral
///
/// decimalIntegerLiteral ::=
/// decimalDigit+
///
/// hexadecimalIntegerLiteral ::=
/// '0x' hexadecimalDigit+
/// | '0X' hexadecimalDigit+
final class IntegerLiteralImpl extends LiteralImpl implements IntegerLiteral {
/// The token representing the literal.
@override
final Token literal;
/// The value of the literal.
@override
int? value = 0;
/// Initialize a newly created integer literal.
IntegerLiteralImpl({
required this.literal,
required this.value,
});
@override
Token get beginToken => literal;
@override
Token get endToken => literal;
/// Returns whether this literal's [parent] is a [PrefixExpression] of unary
/// negation.
///
/// Note: this does *not* indicate that the value itself is negated, just that
/// the literal is the child of a negation operation. The literal value itself
/// will always be positive.
bool get immediatelyNegated {
final parent = this.parent!;
return parent is PrefixExpression &&
parent.operator.type == TokenType.MINUS;
}
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('literal', literal);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitIntegerLiteral(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitIntegerLiteral(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
static bool isValidAsDouble(String lexeme) {
// Less than 16 characters must be a valid double since it will be less than
// 9007199254740992, 0x10000000000000, both 16 characters and 53 bits.
if (lexeme.length < 16) {
return true;
}
var fullPrecision = BigInt.tryParse(lexeme);
if (fullPrecision == null) {
return false;
}
// Usually handled by the length check, however, we must check this before
// constructing a mask later, or we'd get a negative-shift runtime error.
int bitLengthAsInt = fullPrecision.bitLength;
if (bitLengthAsInt <= 53) {
return true;
}
// This would overflow the exponent (larger than maximum double).
if (fullPrecision > BigInt.from(double.maxFinite)) {
return false;
}
// Say [lexeme] uses 100 bits as an integer. The bottom 47 must be 0s -- so
// construct a mask of 47 ones, via of 2^n - 1 where n is 47.
BigInt bottomMask = (BigInt.one << (bitLengthAsInt - 53)) - BigInt.one;
return fullPrecision & bottomMask == BigInt.zero;
}
/// Return `true` if the given [lexeme] is a valid lexeme for an integer
/// literal. The flag [isNegative] should be `true` if the lexeme is preceded
/// by a unary negation operator.
static bool isValidAsInteger(String lexeme, bool isNegative) {
// TODO(jmesserly): this depends on the platform int implementation, and
// may not be accurate if run on dart4web.
//
// (Prior to https://dart-review.googlesource.com/c/sdk/+/63023 there was
// a partial implementation here which may be a good starting point.
// _isValidDecimalLiteral relied on int.parse so that would need some fixes.
// _isValidHexadecimalLiteral worked except for negative int64 max.)
if (isNegative) lexeme = '-$lexeme';
return int.tryParse(lexeme) != null;
}
/// Suggest the nearest valid double to a user. If the integer they wrote
/// requires more than a 53 bit mantissa, or more than 10 exponent bits, do
/// them the favor of suggesting the nearest integer that would work for them.
static double nearestValidDouble(String lexeme) =>
math.min(double.maxFinite, BigInt.parse(lexeme).toDouble());
}
/// A node within a [StringInterpolation].
///
/// interpolationElement ::=
/// [InterpolationExpression]
/// | [InterpolationString]
sealed class InterpolationElement implements AstNode {}
/// A node within a [StringInterpolation].
///
/// interpolationElement ::=
/// [InterpolationExpression]
/// | [InterpolationString]
sealed class InterpolationElementImpl extends AstNodeImpl
implements InterpolationElement {}
/// An expression embedded in a string interpolation.
///
/// interpolationExpression ::=
/// '$' [SimpleIdentifier]
/// | '$' '{' [Expression] '}'
abstract final class InterpolationExpression implements InterpolationElement {
/// Return the expression to be evaluated for the value to be converted into a
/// string.
Expression get expression;
/// Return the token used to introduce the interpolation expression; either
/// '$' if the expression is a simple identifier or '${' if the expression is
/// a full expression.
Token get leftBracket;
/// Return the right curly bracket, or `null` if the expression is an
/// identifier without brackets.
Token? get rightBracket;
}
/// An expression embedded in a string interpolation.
///
/// interpolationExpression ::=
/// '$' [SimpleIdentifier]
/// | '$' '{' [Expression] '}'
final class InterpolationExpressionImpl extends InterpolationElementImpl
implements InterpolationExpression {
/// The token used to introduce the interpolation expression; either '$' if
/// the expression is a simple identifier or '${' if the expression is a full
/// expression.
@override
final Token leftBracket;
/// The expression to be evaluated for the value to be converted into a
/// string.
ExpressionImpl _expression;
/// The right curly bracket, or `null` if the expression is an identifier
/// without brackets.
@override
final Token? rightBracket;
/// Initialize a newly created interpolation expression.
InterpolationExpressionImpl({
required this.leftBracket,
required ExpressionImpl expression,
required this.rightBracket,
}) : _expression = expression {
_becomeParentOf(_expression);
}
@override
Token get beginToken => leftBracket;
@override
Token get endToken => rightBracket ?? _expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('leftBracket', leftBracket)
..addNode('expression', expression)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitInterpolationExpression(this);
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
}
}
/// A non-empty substring of an interpolated string.
///
/// interpolationString ::=
/// characters
abstract final class InterpolationString implements InterpolationElement {
/// Return the characters that will be added to the string.
Token get contents;
/// Return the offset of the after-last contents character.
int get contentsEnd;
/// Return the offset of the first contents character.
int get contentsOffset;
/// Return the value of the literal.
String get value;
}
/// A non-empty substring of an interpolated string.
///
/// interpolationString ::=
/// characters
final class InterpolationStringImpl extends InterpolationElementImpl
implements InterpolationString {
/// The characters that will be added to the string.
@override
final Token contents;
/// The value of the literal.
@override
String value;
/// Initialize a newly created string of characters that are part of a string
/// interpolation.
InterpolationStringImpl({
required this.contents,
required this.value,
});
@override
Token get beginToken => contents;
@override
int get contentsEnd => offset + _lexemeHelper.end;
@override
int get contentsOffset => contents.offset + _lexemeHelper.start;
@override
Token get endToken => contents;
@override
StringInterpolation get parent => super.parent as StringInterpolation;
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('contents', contents);
StringLexemeHelper get _lexemeHelper {
String lexeme = contents.lexeme;
return StringLexemeHelper(lexeme, identical(this, parent.elements.first),
identical(this, parent.elements.last));
}
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitInterpolationString(this);
@override
void visitChildren(AstVisitor visitor) {}
}
/// The invocation of a function or method; either a
/// [FunctionExpressionInvocation] or a [MethodInvocation].
abstract final class InvocationExpression implements Expression {
/// Return the list of arguments to the method.
ArgumentList get argumentList;
/// The expression that identifies the function or method being invoked.
/// For example:
///
/// (o.m)<TArgs>(args); // target will be `o.m`
/// o.m<TArgs>(args); // target will be `m`
///
/// In either case, the [function.staticType] will be the
/// [staticInvokeType] before applying type arguments `TArgs`.
Expression get function;
/// Return the function type of the invocation based on the static type
/// information, or `null` if the AST structure has not been resolved, or if
/// the invoke could not be resolved.
///
/// This will usually be a [FunctionType], but it can also be `dynamic` or
/// `Function`. In the case of interface types that have a `call` method, we
/// store the type of that `call` method here as parameterized.
DartType? get staticInvokeType;
/// Return the type arguments to be applied to the method being invoked, or
/// `null` if no type arguments were provided.
TypeArgumentList? get typeArguments;
/// Return the actual type arguments of the invocation, either explicitly
/// specified in [typeArguments], or inferred.
///
/// If the AST has been resolved, never returns `null`, returns an empty list
/// if the [function] does not have type parameters.
///
/// Return `null` if the AST structure has not been resolved.
List<DartType>? get typeArgumentTypes;
}
/// Common base class for [FunctionExpressionInvocationImpl] and
/// [MethodInvocationImpl].
sealed class InvocationExpressionImpl extends ExpressionImpl
implements InvocationExpression {
/// The list of arguments to the function.
ArgumentListImpl _argumentList;
/// The type arguments to be applied to the method being invoked, or `null` if
/// no type arguments were provided.
TypeArgumentListImpl? _typeArguments;
@override
List<DartType>? typeArgumentTypes;
@override
DartType? staticInvokeType;
/// Initialize a newly created invocation.
InvocationExpressionImpl({
required TypeArgumentListImpl? typeArguments,
required ArgumentListImpl argumentList,
}) : _typeArguments = typeArguments,
_argumentList = argumentList {
_becomeParentOf(_typeArguments);
_becomeParentOf(_argumentList);
}
@override
ArgumentListImpl get argumentList => _argumentList;
set argumentList(ArgumentListImpl argumentList) {
_argumentList = _becomeParentOf(argumentList);
}
@override
TypeArgumentListImpl? get typeArguments => _typeArguments;
set typeArguments(TypeArgumentListImpl? typeArguments) {
_typeArguments = _becomeParentOf(typeArguments);
}
}
/// An is expression.
///
/// isExpression ::=
/// [Expression] 'is' '!'? [TypeAnnotation]
abstract final class IsExpression implements Expression {
/// Return the expression used to compute the value whose type is being
/// tested.
Expression get expression;
/// Return the is operator.
Token get isOperator;
/// Return the not operator, or `null` if the sense of the test is not
/// negated.
Token? get notOperator;
/// Return the type being tested for.
TypeAnnotation get type;
}
/// An is expression.
///
/// isExpression ::=
/// [Expression] 'is' '!'? [NamedType]
final class IsExpressionImpl extends ExpressionImpl implements IsExpression {
/// The expression used to compute the value whose type is being tested.
ExpressionImpl _expression;
/// The is operator.
@override
final Token isOperator;
/// The not operator, or `null` if the sense of the test is not negated.
@override
final Token? notOperator;
/// The name of the type being tested for.
TypeAnnotationImpl _type;
/// Initialize a newly created is expression. The [notOperator] can be `null`
/// if the sense of the test is not negated.
IsExpressionImpl({
required ExpressionImpl expression,
required this.isOperator,
required this.notOperator,
required TypeAnnotationImpl type,
}) : _expression = expression,
_type = type {
_becomeParentOf(_expression);
_becomeParentOf(_type);
}
@override
Token get beginToken => _expression.beginToken;
@override
Token get endToken => _type.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
Precedence get precedence => Precedence.relational;
@override
TypeAnnotationImpl get type => _type;
set type(TypeAnnotationImpl type) {
_type = _becomeParentOf(type);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('expression', expression)
..addToken('isOperator', isOperator)
..addToken('notOperator', notOperator)
..addNode('type', type);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitIsExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitIsExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
_type.accept(visitor);
}
}
/// A label on either a [LabeledStatement] or a [NamedExpression].
///
/// label ::=
/// [SimpleIdentifier] ':'
abstract final class Label implements AstNode {
/// Return the colon that separates the label from the statement.
Token get colon;
/// Return the label being associated with the statement.
SimpleIdentifier get label;
}
/// A statement that has a label associated with them.
///
/// labeledStatement ::=
/// [Label]+ [Statement]
abstract final class LabeledStatement implements Statement {
/// Return the labels being associated with the statement.
NodeList<Label> get labels;
/// Return the statement with which the labels are being associated.
Statement get statement;
}
/// A statement that has a label associated with them.
///
/// labeledStatement ::=
/// [Label]+ [Statement]
final class LabeledStatementImpl extends StatementImpl
implements LabeledStatement {
/// The labels being associated with the statement.
final NodeListImpl<LabelImpl> _labels = NodeListImpl._();
/// The statement with which the labels are being associated.
StatementImpl _statement;
/// Initialize a newly created labeled statement.
LabeledStatementImpl({
required List<LabelImpl> labels,
required StatementImpl statement,
}) : _statement = statement {
_labels._initialize(this, labels);
_becomeParentOf(_statement);
}
@override
Token get beginToken {
if (_labels.isNotEmpty) {
return _labels.beginToken!;
}
return _statement.beginToken;
}
@override
Token get endToken => _statement.endToken;
@override
NodeListImpl<LabelImpl> get labels => _labels;
@override
StatementImpl get statement => _statement;
set statement(StatementImpl statement) {
_statement = _becomeParentOf(statement);
}
@override
StatementImpl get unlabeled => _statement.unlabeled;
@override
ChildEntities get _childEntities => ChildEntities()
..addNodeList('labels', labels)
..addNode('statement', statement);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitLabeledStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_labels.accept(visitor);
_statement.accept(visitor);
}
}
/// A label on either a [LabeledStatement] or a [NamedExpression].
///
/// label ::=
/// [SimpleIdentifier] ':'
final class LabelImpl extends AstNodeImpl implements Label {
/// The label being associated with the statement.
SimpleIdentifierImpl _label;
/// The colon that separates the label from the statement.
@override
final Token colon;
/// Initialize a newly created label.
LabelImpl({
required SimpleIdentifierImpl label,
required this.colon,
}) : _label = label {
_becomeParentOf(_label);
}
@override
Token get beginToken => _label.beginToken;
@override
Token get endToken => colon;
@override
SimpleIdentifierImpl get label => _label;
set label(SimpleIdentifierImpl label) {
_label = _becomeParentOf(label);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('label', label)
..addToken('colon', colon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitLabel(this);
@override
void visitChildren(AstVisitor visitor) {
_label.accept(visitor);
}
}
/// A library augmentation directive.
///
/// libraryAugmentationDirective ::=
/// [metadata] 'library' 'augment' [StringLiteral] ';'
@experimental
abstract final class LibraryAugmentationDirective implements UriBasedDirective {
/// Return the token representing the 'augment' keyword.
Token get augmentKeyword;
/// Return the token representing the 'library' keyword.
Token get libraryKeyword;
/// Return the semicolon terminating the directive.
Token get semicolon;
}
/// A library directive.
///
/// libraryAugmentationDirective ::=
/// [metadata] 'library' 'augment' [StringLiteral] ';'
@experimental
final class LibraryAugmentationDirectiveImpl extends UriBasedDirectiveImpl
implements LibraryAugmentationDirective {
@override
final Token libraryKeyword;
@override
final Token augmentKeyword;
@override
final Token semicolon;
LibraryAugmentationDirectiveImpl({
required super.comment,
required super.metadata,
required this.libraryKeyword,
required this.augmentKeyword,
required super.uri,
required this.semicolon,
});
@override
Token get endToken => semicolon;
@override
Token get firstTokenAfterCommentAndMetadata => libraryKeyword;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('libraryKeyword', libraryKeyword)
..addToken('augmentKeyword', augmentKeyword)
..addNode('uri', uri)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitLibraryAugmentationDirective(this);
}
}
/// A library directive.
///
/// libraryDirective ::=
/// [Annotation] 'library' [LibraryIdentifier]? ';'
abstract final class LibraryDirective implements Directive {
/// Return the token representing the 'library' keyword.
Token get libraryKeyword;
/// Return the name of the library being defined.
LibraryIdentifier? get name2;
/// Return the semicolon terminating the directive.
Token get semicolon;
}
/// A library directive.
///
/// libraryDirective ::=
/// [Annotation] 'library' [Identifier] ';'
final class LibraryDirectiveImpl extends DirectiveImpl
implements LibraryDirective {
/// The token representing the 'library' keyword.
@override
final Token libraryKeyword;
/// The name of the library being defined.
LibraryIdentifierImpl? _name;
/// The semicolon terminating the directive.
@override
final Token semicolon;
/// Initialize a newly created library directive. Either or both of the
/// [comment] and [metadata] can be `null` if the directive does not have the
/// corresponding attribute.
LibraryDirectiveImpl({
required super.comment,
required super.metadata,
required this.libraryKeyword,
required LibraryIdentifierImpl? name,
required this.semicolon,
}) : _name = name {
_becomeParentOf(_name);
}
@override
Token get endToken => semicolon;
@override
Token get firstTokenAfterCommentAndMetadata => libraryKeyword;
set name(LibraryIdentifierImpl? name) {
_name = _becomeParentOf(name);
}
@override
LibraryIdentifierImpl? get name2 => _name;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('libraryKeyword', libraryKeyword)
..addNode('name', name2)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitLibraryDirective(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_name?.accept(visitor);
}
}
/// The identifier for a library.
///
/// libraryIdentifier ::=
/// [SimpleIdentifier] ('.' [SimpleIdentifier])*
abstract final class LibraryIdentifier implements Identifier {
/// Return the components of the identifier.
NodeList<SimpleIdentifier> get components;
}
/// The identifier for a library.
///
/// libraryIdentifier ::=
/// [SimpleIdentifier] ('.' [SimpleIdentifier])*
final class LibraryIdentifierImpl extends IdentifierImpl
implements LibraryIdentifier {
/// The components of the identifier.
final NodeListImpl<SimpleIdentifierImpl> _components = NodeListImpl._();
/// Initialize a newly created prefixed identifier.
LibraryIdentifierImpl({
required List<SimpleIdentifierImpl> components,
}) {
_components._initialize(this, components);
}
@override
Token get beginToken => _components.beginToken!;
@override
NodeListImpl<SimpleIdentifierImpl> get components => _components;
@override
Token get endToken => _components.endToken!;
@override
String get name {
StringBuffer buffer = StringBuffer();
bool needsPeriod = false;
int length = _components.length;
for (int i = 0; i < length; i++) {
SimpleIdentifier identifier = _components[i];
if (needsPeriod) {
buffer.write(".");
} else {
needsPeriod = true;
}
buffer.write(identifier.name);
}
return considerCanonicalizeString(buffer.toString());
}
@override
Precedence get precedence => Precedence.postfix;
@override
Element? get staticElement => null;
@override
// TODO(paulberry): add "." tokens.
ChildEntities get _childEntities =>
ChildEntities()..addNodeList('components', components);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitLibraryIdentifier(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitLibraryIdentifier(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_components.accept(visitor);
}
}
/// A list literal.
///
/// listLiteral ::=
/// 'const'? [TypeAnnotationList]? '[' elements? ']'
///
/// elements ::=
/// [CollectionElement] (',' [CollectionElement])* ','?
abstract final class ListLiteral implements TypedLiteral {
/// Return the syntactic elements used to compute the elements of the list.
NodeList<CollectionElement> get elements;
/// Return the left square bracket.
Token get leftBracket;
/// Return the right square bracket.
Token get rightBracket;
}
final class ListLiteralImpl extends TypedLiteralImpl implements ListLiteral {
/// The left square bracket.
@override
final Token leftBracket;
/// The expressions used to compute the elements of the list.
final NodeListImpl<CollectionElementImpl> _elements = NodeListImpl._();
/// The right square bracket.
@override
final Token rightBracket;
/// Initialize a newly created list literal. The [constKeyword] can be `null`
/// if the literal is not a constant. The [typeArguments] can be `null` if no
/// type arguments were declared. The list of [elements] can be `null` if the
/// list is empty.
ListLiteralImpl({
required super.constKeyword,
required super.typeArguments,
required this.leftBracket,
required List<CollectionElementImpl> elements,
required this.rightBracket,
}) {
_elements._initialize(this, elements);
}
@override
Token get beginToken {
if (constKeyword case final constKeyword?) {
return constKeyword;
}
final typeArguments = this.typeArguments;
if (typeArguments != null) {
return typeArguments.beginToken;
}
return leftBracket;
}
@override
NodeListImpl<CollectionElementImpl> get elements => _elements;
@override
Token get endToken => rightBracket;
@override
// TODO(paulberry): add commas.
ChildEntities get _childEntities => super._childEntities
..addToken('leftBracket', leftBracket)
..addNodeList('elements', elements)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitListLiteral(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitListLiteral(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_elements.accept(visitor);
}
}
/// A list pattern.
///
/// listPattern ::=
/// [TypeArgumentList]? '[' [DartPattern] (',' [DartPattern])* ','? ']'
abstract final class ListPattern implements DartPattern {
/// Return the elements in this pattern.
NodeList<ListPatternElement> get elements;
/// Return the left square bracket.
Token get leftBracket;
/// The required type, specified by [typeArguments] or inferred from the
/// matched value type; or `null` if the node is not resolved yet.
DartType? get requiredType;
/// Return the right square bracket.
Token get rightBracket;
/// Return the type arguments associated with this pattern, or `null` if no
/// type arguments were declared.
TypeArgumentList? get typeArguments;
}
/// An element of a list pattern.
sealed class ListPatternElement implements AstNode {}
abstract final class ListPatternElementImpl
implements AstNodeImpl, ListPatternElement {}
/// A list pattern.
///
/// listPattern ::=
/// [TypeArgumentList]? '[' [DartPattern] (',' [DartPattern])* ','? ']'
final class ListPatternImpl extends DartPatternImpl implements ListPattern {
@override
final TypeArgumentListImpl? typeArguments;
@override
final Token leftBracket;
final NodeListImpl<ListPatternElementImpl> _elements = NodeListImpl._();
@override
final Token rightBracket;
@override
DartType? requiredType;
ListPatternImpl({
required this.typeArguments,
required this.leftBracket,
required List<ListPatternElementImpl> elements,
required this.rightBracket,
}) {
_becomeParentOf(typeArguments);
_elements._initialize(this, elements);
}
@override
Token get beginToken => typeArguments?.beginToken ?? leftBracket;
@override
NodeList<ListPatternElementImpl> get elements => _elements;
@override
Token get endToken => rightBracket;
@override
PatternPrecedence get precedence => PatternPrecedence.primary;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('typeArguments', typeArguments)
..addToken('leftBracket', leftBracket)
..addNodeList('elements', elements)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitListPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
var elementType = typeArguments?.arguments.elementAtOrNull(0)?.typeOrThrow;
return resolverVisitor.analyzeListPatternSchema(
elementType: elementType,
elements: elements,
);
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
resolverVisitor.listPatternResolver.resolve(node: this, context: context);
}
@override
void visitChildren(AstVisitor visitor) {
typeArguments?.accept(visitor);
elements.accept(visitor);
}
}
/// A node that represents a literal expression.
///
/// literal ::=
/// [BooleanLiteral]
/// | [DoubleLiteral]
/// | [IntegerLiteral]
/// | [ListLiteral]
/// | [NullLiteral]
/// | [SetOrMapLiteral]
/// | [StringLiteral]
sealed class Literal implements Expression {}
/// A node that represents a literal expression.
///
/// literal ::=
/// [BooleanLiteral]
/// | [DoubleLiteral]
/// | [IntegerLiteral]
/// | [ListLiteral]
/// | [MapLiteral]
/// | [NullLiteral]
/// | [StringLiteral]
sealed class LiteralImpl extends ExpressionImpl implements Literal {
@override
Precedence get precedence => Precedence.primary;
}
/// Additional information about local variables within a function or method
/// produced at resolution time.
class LocalVariableInfo {
/// The set of local variables and parameters that are potentially mutated
/// within the scope of their declarations.
final Set<VariableElement> potentiallyMutatedInScope = <VariableElement>{};
}
/// A logical-and pattern.
///
/// logicalAndPattern ::=
/// [DartPattern] '&&' [DartPattern]
abstract final class LogicalAndPattern implements DartPattern {
/// The left sub-pattern.
DartPattern get leftOperand;
/// The `&&` operator.
Token get operator;
/// The right sub-pattern.
DartPattern get rightOperand;
}
/// A logical-and pattern.
///
/// logicalAndPattern ::=
/// [DartPattern] '&&' [DartPattern]
final class LogicalAndPatternImpl extends DartPatternImpl
implements LogicalAndPattern {
@override
final DartPatternImpl leftOperand;
@override
final Token operator;
@override
final DartPatternImpl rightOperand;
LogicalAndPatternImpl({
required this.leftOperand,
required this.operator,
required this.rightOperand,
}) {
_becomeParentOf(leftOperand);
_becomeParentOf(rightOperand);
}
@override
Token get beginToken => leftOperand.beginToken;
@override
Token get endToken => rightOperand.endToken;
@override
PatternPrecedence get precedence => PatternPrecedence.logicalAnd;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('leftOperand', leftOperand)
..addToken('operator', operator)
..addNode('rightOperand', rightOperand);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitLogicalAndPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor.analyzeLogicalAndPatternSchema(
leftOperand, rightOperand);
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
resolverVisitor.analyzeLogicalAndPattern(
context, this, leftOperand, rightOperand);
}
@override
void visitChildren(AstVisitor visitor) {
leftOperand.accept(visitor);
rightOperand.accept(visitor);
}
}
/// A logical-or pattern.
///
/// logicalOrPattern ::=
/// [DartPattern] '||' [DartPattern]
abstract final class LogicalOrPattern implements DartPattern {
/// The left sub-pattern.
DartPattern get leftOperand;
/// The `||` operator.
Token get operator;
/// The right sub-pattern.
DartPattern get rightOperand;
}
/// A logical-or pattern.
///
/// logicalOrPattern ::=
/// [DartPattern] '||' [DartPattern]
final class LogicalOrPatternImpl extends DartPatternImpl
implements LogicalOrPattern {
@override
final DartPatternImpl leftOperand;
@override
final Token operator;
@override
final DartPatternImpl rightOperand;
LogicalOrPatternImpl({
required this.leftOperand,
required this.operator,
required this.rightOperand,
}) {
_becomeParentOf(leftOperand);
_becomeParentOf(rightOperand);
}
@override
Token get beginToken => leftOperand.beginToken;
@override
Token get endToken => rightOperand.endToken;
@override
PatternPrecedence get precedence => PatternPrecedence.logicalOr;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('leftOperand', leftOperand)
..addToken('operator', operator)
..addNode('rightOperand', rightOperand);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitLogicalOrPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor.analyzeLogicalOrPatternSchema(
leftOperand, rightOperand);
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
resolverVisitor.analyzeLogicalOrPattern(
context, this, leftOperand, rightOperand);
resolverVisitor.nullSafetyDeadCodeVerifier.flowEnd(rightOperand);
}
@override
void visitChildren(AstVisitor visitor) {
leftOperand.accept(visitor);
rightOperand.accept(visitor);
}
}
/// A single key/value pair in a map literal.
///
/// mapLiteralEntry ::=
/// [Expression] ':' [Expression]
abstract final class MapLiteralEntry implements CollectionElement {
/// Return the expression computing the key with which the value will be
/// associated.
Expression get key;
/// Return the colon that separates the key from the value.
Token get separator;
/// Return the expression computing the value that will be associated with the
/// key.
Expression get value;
}
/// A single key/value pair in a map literal.
///
/// mapLiteralEntry ::=
/// [Expression] ':' [Expression]
final class MapLiteralEntryImpl extends CollectionElementImpl
implements MapLiteralEntry {
/// The expression computing the key with which the value will be associated.
ExpressionImpl _key;
/// The colon that separates the key from the value.
@override
final Token separator;
/// The expression computing the value that will be associated with the key.
ExpressionImpl _value;
/// Initialize a newly created map literal entry.
MapLiteralEntryImpl({
required ExpressionImpl key,
required this.separator,
required ExpressionImpl value,
}) : _key = key,
_value = value {
_becomeParentOf(_key);
_becomeParentOf(_value);
}
@override
Token get beginToken => _key.beginToken;
@override
Token get endToken => _value.endToken;
@override
ExpressionImpl get key => _key;
set key(ExpressionImpl string) {
_key = _becomeParentOf(string);
}
@override
ExpressionImpl get value => _value;
set value(ExpressionImpl expression) {
_value = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('key', key)
..addToken('separator', separator)
..addNode('value', value);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitMapLiteralEntry(this);
@override
void resolveElement(
ResolverVisitor resolver, CollectionLiteralContext? context) {
resolver.visitMapLiteralEntry(this, context: context);
resolver.pushRewrite(null);
}
@override
void visitChildren(AstVisitor visitor) {
_key.accept(visitor);
_value.accept(visitor);
}
}
/// A map pattern.
///
/// mapPattern ::=
/// [TypeArgumentList]? '{' [MapPatternEntry] (',' [MapPatternEntry])*
/// ','? '}'
abstract final class MapPattern implements DartPattern {
/// Return the elements in this pattern.
NodeList<MapPatternElement> get elements;
/// Return the left curly bracket.
Token get leftBracket;
/// The matched value type, or `null` if the node is not resolved yet.
DartType? get requiredType;
/// Return the right curly bracket.
Token get rightBracket;
/// Return the type arguments associated with this pattern, or `null` if no
/// type arguments were declared.
TypeArgumentList? get typeArguments;
}
/// An element of a map pattern.
sealed class MapPatternElement implements AstNode {}
sealed class MapPatternElementImpl implements AstNodeImpl, MapPatternElement {}
/// An entry in a map pattern.
///
/// mapPatternEntry ::=
/// [Expression] ':' [DartPattern]
abstract final class MapPatternEntry implements AstNode, MapPatternElement {
/// Return the expression computing the key of the entry to be matched.
Expression get key;
/// Return the colon that separates the key from the value.
Token get separator;
/// Return the pattern used to match the value.
DartPattern get value;
}
/// An entry in a map pattern.
///
/// mapPatternEntry ::=
/// [Expression] ':' [DartPattern]
final class MapPatternEntryImpl extends AstNodeImpl
implements MapPatternEntry, MapPatternElementImpl {
ExpressionImpl _key;
@override
final Token separator;
@override
final DartPatternImpl value;
MapPatternEntryImpl({
required ExpressionImpl key,
required this.separator,
required this.value,
}) : _key = key {
_becomeParentOf(_key);
_becomeParentOf(value);
}
@override
Token get beginToken => key.beginToken;
@override
Token get endToken => value.endToken;
@override
ExpressionImpl get key => _key;
set key(ExpressionImpl key) {
_key = _becomeParentOf(key);
}
@override
ChildEntities get _childEntities => super._childEntities
..addNode('key', key)
..addToken('separator', separator)
..addNode('value', value);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitMapPatternEntry(this);
@override
void visitChildren(AstVisitor visitor) {
key.accept(visitor);
value.accept(visitor);
}
}
/// A map pattern.
///
/// mapPattern ::=
/// [TypeArgumentList]? '{' [MapPatternEntry] (',' [MapPatternEntry])*
/// ','? '}'
final class MapPatternImpl extends DartPatternImpl implements MapPattern {
@override
final TypeArgumentListImpl? typeArguments;
@override
final Token leftBracket;
final NodeListImpl<MapPatternElementImpl> _elements = NodeListImpl._();
@override
final Token rightBracket;
@override
DartType? requiredType;
MapPatternImpl({
required this.typeArguments,
required this.leftBracket,
required List<MapPatternElementImpl> elements,
required this.rightBracket,
}) {
_becomeParentOf(typeArguments);
_elements._initialize(this, elements);
}
@override
Token get beginToken => typeArguments?.beginToken ?? leftBracket;
@override
NodeList<MapPatternElementImpl> get elements => _elements;
@override
Token get endToken => rightBracket;
@override
PatternPrecedence get precedence => PatternPrecedence.primary;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('typeArguments', typeArguments)
..addToken('leftBracket', leftBracket)
..addNodeList('elements', elements)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitMapPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
shared.MapPatternTypeArguments<DartType>? typeArguments;
final typeArgumentNodes = this.typeArguments?.arguments;
if (typeArgumentNodes != null && typeArgumentNodes.length == 2) {
typeArguments = shared.MapPatternTypeArguments(
keyType: typeArgumentNodes[0].typeOrThrow,
valueType: typeArgumentNodes[1].typeOrThrow,
);
}
return resolverVisitor.analyzeMapPatternSchema(
typeArguments: typeArguments,
elements: elements,
);
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
resolverVisitor.resolveMapPattern(node: this, context: context);
}
@override
void visitChildren(AstVisitor visitor) {
typeArguments?.accept(visitor);
elements.accept(visitor);
}
}
/// A method declaration.
///
/// methodDeclaration ::=
/// methodSignature [FunctionBody]
///
/// methodSignature ::=
/// 'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
/// methodName [TypeParameterList] [FormalParameterList]
///
/// methodName ::=
/// [SimpleIdentifier]
/// | 'operator' [SimpleIdentifier]
///
/// Prior to the 'extension-methods' experiment, these nodes were always
/// children of a class declaration. When the experiment is enabled, these nodes
/// can also be children of an extension declaration.
abstract final class MethodDeclaration implements ClassMember {
/// The token for the 'augment' keyword.
Token? get augmentKeyword;
/// Return the body of the method.
FunctionBody get body;
@override
ExecutableElement? get declaredElement;
/// Return the token for the 'external' keyword, or `null` if the constructor
/// is not external.
Token? get externalKeyword;
/// Return `true` if this method is declared to be an abstract method.
bool get isAbstract;
/// Return `true` if this method declares a getter.
bool get isGetter;
/// Return `true` if this method declares an operator.
bool get isOperator;
/// Return `true` if this method declares a setter.
bool get isSetter;
/// Return `true` if this method is declared to be a static method.
bool get isStatic;
/// Return the token representing the 'abstract' or 'static' keyword, or
/// `null` if neither modifier was specified.
Token? get modifierKeyword;
/// Return the name of the method.
Token get name;
/// Return the token representing the 'operator' keyword, or `null` if this
/// method does not declare an operator.
Token? get operatorKeyword;
/// Return the parameters associated with the method, or `null` if this method
/// declares a getter.
FormalParameterList? get parameters;
/// Return the token representing the 'get' or 'set' keyword, or `null` if
/// this is a method declaration rather than a property declaration.
Token? get propertyKeyword;
/// Return the return type of the method, or `null` if no return type was
/// declared.
TypeAnnotation? get returnType;
/// Return the type parameters associated with this method, or `null` if this
/// method is not a generic method.
TypeParameterList? get typeParameters;
}
final class MethodDeclarationImpl extends ClassMemberImpl
implements MethodDeclaration {
@override
final Token? augmentKeyword;
@override
final Token? externalKeyword;
@override
final Token? modifierKeyword;
@override
final TypeAnnotationImpl? returnType;
@override
final Token? propertyKeyword;
@override
final Token? operatorKeyword;
@override
final Token name;
@override
final TypeParameterListImpl? typeParameters;
@override
final FormalParameterListImpl? parameters;
@override
final FunctionBodyImpl body;
@override
ExecutableElementImpl? declaredElement;
MethodDeclarationImpl({
required super.comment,
required super.metadata,
required this.augmentKeyword,
required this.externalKeyword,
required this.modifierKeyword,
required this.returnType,
required this.propertyKeyword,
required this.operatorKeyword,
required this.name,
required this.typeParameters,
required this.parameters,
required this.body,
}) {
_becomeParentOf(returnType);
_becomeParentOf(typeParameters);
_becomeParentOf(parameters);
_becomeParentOf(body);
}
@override
Token get endToken => body.endToken;
@override
Token get firstTokenAfterCommentAndMetadata {
return augmentKeyword ??
Token.lexicallyFirst(externalKeyword, modifierKeyword) ??
returnType?.beginToken ??
Token.lexicallyFirst(propertyKeyword, operatorKeyword) ??
name;
}
@override
bool get isAbstract {
final body = this.body;
return externalKeyword == null &&
(body is EmptyFunctionBodyImpl && !body.semicolon.isSynthetic);
}
@override
bool get isGetter => propertyKeyword?.keyword == Keyword.GET;
@override
bool get isOperator => operatorKeyword != null;
@override
bool get isSetter => propertyKeyword?.keyword == Keyword.SET;
@override
bool get isStatic => modifierKeyword?.keyword == Keyword.STATIC;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('augmentKeyword', augmentKeyword)
..addToken('externalKeyword', externalKeyword)
..addToken('modifierKeyword', modifierKeyword)
..addNode('returnType', returnType)
..addToken('propertyKeyword', propertyKeyword)
..addToken('operatorKeyword', operatorKeyword)
..addToken('name', name)
..addNode('typeParameters', typeParameters)
..addNode('parameters', parameters)
..addNode('body', body);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitMethodDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
returnType?.accept(visitor);
typeParameters?.accept(visitor);
parameters?.accept(visitor);
body.accept(visitor);
}
}
/// The invocation of either a function or a method.
///
/// Invocations of functions resulting from evaluating an expression are
/// represented by [FunctionExpressionInvocation] nodes. Invocations of getters
/// and setters are represented by either [PrefixedIdentifier] or
/// [PropertyAccess] nodes.
///
/// methodInvocation ::=
/// ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
abstract final class MethodInvocation
implements NullShortableExpression, InvocationExpression {
/// Return `true` if this expression is cascaded.
///
/// If it is, then the target of this expression is not stored locally but is
/// stored in the nearest ancestor that is a [CascadeExpression].
bool get isCascaded;
/// Whether this method invocation is null aware (as opposed to non-null).
bool get isNullAware;
/// Return the name of the method being invoked.
SimpleIdentifier get methodName;
/// Return the operator that separates the target from the method name, or
/// `null` if there is no target.
///
/// In an ordinary method invocation this will be period ('.'). In a cascade
/// section this will be the cascade operator ('..').
Token? get operator;
/// Return the expression used to compute the receiver of the invocation.
///
/// If this invocation is not part of a cascade expression, then this is the
/// same as [target]. If this invocation is part of a cascade expression,
/// then the target stored with the cascade expression is returned.
Expression? get realTarget;
/// Return the expression producing the object on which the method is defined,
/// or `null` if there is no target (that is, the target is implicitly `this`)
/// or if this method invocation is part of a cascade expression.
///
/// Use [realTarget] to get the target independent of whether this is part of
/// a cascade expression.
Expression? get target;
}
/// The invocation of either a function or a method. Invocations of functions
/// resulting from evaluating an expression are represented by
/// [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
/// represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
///
/// methodInvocation ::=
/// ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]?
/// [ArgumentList]
final class MethodInvocationImpl extends InvocationExpressionImpl
with NullShortableExpressionImpl
implements MethodInvocation {
/// The expression producing the object on which the method is defined, or
/// `null` if there is no target (that is, the target is implicitly `this`).
ExpressionImpl? _target;
/// The operator that separates the target from the method name, or `null`
/// if there is no target. In an ordinary method invocation this will be a
/// period ('.'). In a cascade section this will be the cascade operator
/// ('..' | '?..').
@override
Token? operator;
/// The name of the method being invoked.
SimpleIdentifierImpl _methodName;
/// The invoke type of the [methodName] if the target element is a getter,
/// or `null` otherwise.
DartType? _methodNameType;
/// Initialize a newly created method invocation. The [target] and [operator]
/// can be `null` if there is no target.
MethodInvocationImpl({
required ExpressionImpl? target,
required this.operator,
required SimpleIdentifierImpl methodName,
required super.typeArguments,
required super.argumentList,
}) : _target = target,
_methodName = methodName {
_becomeParentOf(_target);
_becomeParentOf(_methodName);
}
@override
Token get beginToken {
if (target case final target?) {
return target.beginToken;
} else if (operator case final operator?) {
return operator;
}
return _methodName.beginToken;
}
@override
Token get endToken => _argumentList.endToken;
@override
ExpressionImpl get function => methodName;
@override
bool get isCascaded =>
operator != null &&
(operator!.type == TokenType.PERIOD_PERIOD ||
operator!.type == TokenType.QUESTION_PERIOD_PERIOD);
@override
bool get isNullAware {
if (isCascaded) {
return _ancestorCascade.isNullAware;
}
return operator != null &&
(operator!.type == TokenType.QUESTION_PERIOD ||
operator!.type == TokenType.QUESTION_PERIOD_PERIOD);
}
@override
SimpleIdentifierImpl get methodName => _methodName;
set methodName(SimpleIdentifierImpl identifier) {
_methodName = _becomeParentOf(identifier);
}
/// The invoke type of the [methodName].
///
/// If the target element is a [MethodElement], this is the same as the
/// [staticInvokeType]. If the target element is a getter, presumably
/// returning an [ExecutableElement] so that it can be invoked in this
/// [MethodInvocation], then this type is the type of the getter, and the
/// [staticInvokeType] is the invoked type of the returned element.
DartType? get methodNameType => _methodNameType ?? staticInvokeType;
/// Set the [methodName] invoke type, only if the target element is a getter.
/// Otherwise, the target element itself is invoked, [_methodNameType] is
/// `null`, and the getter will return [staticInvokeType].
set methodNameType(DartType? methodNameType) {
_methodNameType = methodNameType;
}
@override
Precedence get precedence => Precedence.postfix;
@override
ExpressionImpl? get realTarget {
if (isCascaded) {
return _ancestorCascade.target;
}
return _target;
}
@override
ExpressionImpl? get target => _target;
set target(ExpressionImpl? expression) {
_target = _becomeParentOf(expression);
}
/// Return the cascade that contains this [IndexExpression].
///
/// We expect that [isCascaded] is `true`.
CascadeExpressionImpl get _ancestorCascade {
assert(isCascaded);
for (var ancestor = parent!;; ancestor = ancestor.parent!) {
if (ancestor is CascadeExpressionImpl) {
return ancestor;
}
}
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('target', target)
..addToken('operator', operator)
..addNode('methodName', methodName)
..addNode('typeArguments', typeArguments)
..addNode('argumentList', argumentList);
@override
AstNode? get _nullShortingExtensionCandidate => parent;
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitMethodInvocation(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitMethodInvocation(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_target?.accept(visitor);
_methodName.accept(visitor);
_typeArguments?.accept(visitor);
_argumentList.accept(visitor);
}
@override
bool _extendsNullShorting(Expression descendant) =>
identical(descendant, _target);
}
/// An expression that implicitly makes reference to a method.
abstract final class MethodReferenceExpression implements Expression {
/// Return the element associated with the expression based on the static
/// types, or `null` if the AST structure has not been resolved, or there is
/// no meaningful static element to return (e.g. because this is a
/// non-compound assignment expression, or because the method referred to
/// could not be resolved).
MethodElement? get staticElement;
}
/// The declaration of a mixin.
///
/// mixinDeclaration ::=
/// 'base'? 'mixin' name [TypeParameterList]?
/// [OnClause]? [ImplementsClause]? '{' [ClassMember]* '}'
abstract final class MixinDeclaration implements NamedCompilationUnitMember {
/// Return the 'augment' keyword, or `null` if the keyword was absent.
Token? get augmentKeyword;
/// Return the 'base' keyword, or `null` if the keyword was absent.
Token? get baseKeyword;
@override
MixinElement? get declaredElement;
/// Returns the `implements` clause for the mixin, or `null` if the mixin
/// does not implement any interfaces.
ImplementsClause? get implementsClause;
/// Returns the left curly bracket.
Token get leftBracket;
/// Returns the members defined by the mixin.
NodeList<ClassMember> get members;
/// Return the token representing the 'mixin' keyword.
Token get mixinKeyword;
/// Return the on clause for the mixin, or `null` if the mixin does not have
/// any superclass constraints.
OnClause? get onClause;
/// Returns the right curly bracket.
Token get rightBracket;
/// Returns the type parameters for the mixin, or `null` if the mixin does
/// not have any type parameters.
TypeParameterList? get typeParameters;
}
final class MixinDeclarationImpl extends NamedCompilationUnitMemberImpl
implements MixinDeclaration {
@override
final Token? augmentKeyword;
@override
final Token? baseKeyword;
@override
final Token mixinKeyword;
@override
final TypeParameterListImpl? typeParameters;
@override
final OnClauseImpl? onClause;
@override
final ImplementsClauseImpl? implementsClause;
@override
final Token leftBracket;
@override
final NodeListImpl<ClassMemberImpl> members = NodeListImpl._();
@override
final Token rightBracket;
@override
MixinElementImpl? declaredElement;
MixinDeclarationImpl({
required super.comment,
required super.metadata,
required this.augmentKeyword,
required this.baseKeyword,
required this.mixinKeyword,
required super.name,
required this.typeParameters,
required this.onClause,
required this.implementsClause,
required this.leftBracket,
required List<ClassMemberImpl> members,
required this.rightBracket,
}) {
_becomeParentOf(typeParameters);
_becomeParentOf(onClause);
_becomeParentOf(implementsClause);
this.members._initialize(this, members);
}
@override
Token get endToken => rightBracket;
@override
Token get firstTokenAfterCommentAndMetadata {
return augmentKeyword ?? baseKeyword ?? mixinKeyword;
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('augmentKeyword', augmentKeyword)
..addToken('baseKeyword', baseKeyword)
..addToken('mixinKeyword', mixinKeyword)
..addToken('name', name)
..addNode('typeParameters', typeParameters)
..addNode('onClause', onClause)
..addNode('implementsClause', implementsClause)
..addToken('leftBracket', leftBracket)
..addNodeList('members', members)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitMixinDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
typeParameters?.accept(visitor);
onClause?.accept(visitor);
implementsClause?.accept(visitor);
members.accept(visitor);
}
}
/// A node that declares a single name within the scope of a compilation unit.
abstract final class NamedCompilationUnitMember
implements CompilationUnitMember {
/// Return the name of the member being declared.
Token get name;
}
/// A node that declares a single name within the scope of a compilation unit.
sealed class NamedCompilationUnitMemberImpl extends CompilationUnitMemberImpl
implements NamedCompilationUnitMember {
/// The name of the member being declared.
@override
final Token name;
/// Initialize a newly created compilation unit member with the given [name].
/// Either or both of the [comment] and [metadata] can be `null` if the member
/// does not have the corresponding attribute.
NamedCompilationUnitMemberImpl({
required super.comment,
required super.metadata,
required this.name,
});
}
/// An expression that has a name associated with it. They are used in method
/// invocations when there are named parameters.
///
/// namedExpression ::=
/// [Label] [Expression]
abstract final class NamedExpression implements Expression {
/// Return the element representing the parameter being named by this
/// expression, or `null` if the AST structure has not been resolved or if
/// there is no parameter with the same name as this expression.
ParameterElement? get element;
/// Return the expression with which the name is associated.
Expression get expression;
/// Return the name associated with the expression.
Label get name;
}
/// An expression that has a name associated with it. They are used in method
/// invocations when there are named parameters.
///
/// namedExpression ::=
/// [Label] [Expression]
final class NamedExpressionImpl extends ExpressionImpl
implements NamedExpression {
/// The name associated with the expression.
LabelImpl _name;
/// The expression with which the name is associated.
ExpressionImpl _expression;
/// Initialize a newly created named expression..
NamedExpressionImpl({
required LabelImpl name,
required ExpressionImpl expression,
}) : _name = name,
_expression = expression {
_becomeParentOf(_name);
_becomeParentOf(_expression);
}
@override
Token get beginToken => _name.beginToken;
@override
ParameterElement? get element {
var element = _name.label.staticElement;
if (element is ParameterElement) {
return element;
}
return null;
}
@override
Token get endToken => _expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
LabelImpl get name => _name;
set name(LabelImpl identifier) {
_name = _becomeParentOf(identifier);
}
@override
Precedence get precedence => Precedence.none;
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('name', name)
..addNode('expression', expression);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitNamedExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitNamedExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_name.accept(visitor);
_expression.accept(visitor);
}
}
/// A named type, which can optionally include type arguments.
///
/// namedType ::=
/// [ImportPrefixReference]? name typeArguments?
abstract final class NamedType implements TypeAnnotation {
/// The element of [name2] considering [importPrefix] for example a
/// [ClassElement], or [TypeAliasElement]. Can be `null` if [name2] cannot
/// be resolved, or there is no element for the type name, e.g. for `void`.
Element? get element;
/// The optional import prefix before [name2].
ImportPrefixReference? get importPrefix;
/// Return `true` if this type is a deferred type.
///
/// 15.1 Static Types: A type <i>T</i> is deferred iff it is of the form
/// </i>p.T</i> where <i>p</i> is a deferred prefix.
bool get isDeferred;
/// Return the name of the type.
Token get name2;
/// Return the type arguments associated with the type, or `null` if there are
/// no type arguments.
TypeArgumentList? get typeArguments;
}
/// The name of a type, which can optionally include type arguments.
///
/// typeName ::=
/// [Identifier] typeArguments? '?'?
final class NamedTypeImpl extends TypeAnnotationImpl implements NamedType {
@override
final ImportPrefixReferenceImpl? importPrefix;
@override
final Token name2;
@override
Element? element;
@override
TypeArgumentListImpl? typeArguments;
@override
final Token? question;
/// The type being named, or `null` if the AST structure has not been
/// resolved, or if this is part of a [ConstructorReference].
@override
DartType? type;
/// Initialize a newly created type name. The [typeArguments] can be `null` if
/// there are no type arguments.
NamedTypeImpl({
required this.importPrefix,
required this.name2,
required this.typeArguments,
required this.question,
}) {
_becomeParentOf(importPrefix);
_becomeParentOf(typeArguments);
}
@override
Token get beginToken => importPrefix?.beginToken ?? name2;
@override
Token get endToken => question ?? typeArguments?.endToken ?? name2;
@override
bool get isDeferred {
final importPrefixElement = importPrefix?.element;
if (importPrefixElement is PrefixElement) {
final imports = importPrefixElement.imports;
if (imports.length != 1) {
return false;
}
return imports[0].prefix is DeferredImportElementPrefix;
}
return false;
}
@override
bool get isSynthetic => name2.isSynthetic && typeArguments == null;
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('importPrefix', importPrefix)
..addToken('name', name2)
..addNode('typeArguments', typeArguments)
..addToken('question', question);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitNamedType(this);
@override
void visitChildren(AstVisitor visitor) {
importPrefix?.accept(visitor);
typeArguments?.accept(visitor);
}
}
/// A node that represents a directive that impacts the namespace of a library.
///
/// directive ::=
/// [ExportDirective]
/// | [ImportDirective]
sealed class NamespaceDirective implements UriBasedDirective {
/// Return the combinators used to control how names are imported or exported.
NodeList<Combinator> get combinators;
/// Return the configurations used to control which library will actually be
/// loaded at run-time.
NodeList<Configuration> get configurations;
/// Return the semicolon terminating the directive.
Token get semicolon;
}
/// A node that represents a directive that impacts the namespace of a library.
///
/// directive ::=
/// [ExportDirective]
/// | [ImportDirective]
sealed class NamespaceDirectiveImpl extends UriBasedDirectiveImpl
implements NamespaceDirective {
/// The configurations used to control which library will actually be loaded
/// at run-time.
final NodeListImpl<ConfigurationImpl> _configurations = NodeListImpl._();
/// The combinators used to control which names are imported or exported.
final NodeListImpl<CombinatorImpl> _combinators = NodeListImpl._();
/// The semicolon terminating the directive.
@override
final Token semicolon;
/// Initialize a newly created namespace 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
/// are no combinators.
NamespaceDirectiveImpl({
required super.comment,
required super.metadata,
required super.uri,
required List<ConfigurationImpl>? configurations,
required List<CombinatorImpl>? combinators,
required this.semicolon,
}) {
_configurations._initialize(this, configurations);
_combinators._initialize(this, combinators);
}
@override
NodeListImpl<CombinatorImpl> get combinators => _combinators;
@override
NodeListImpl<ConfigurationImpl> get configurations => _configurations;
@override
Token get endToken => semicolon;
}
/// The "native" clause in an class declaration.
///
/// nativeClause ::=
/// 'native' [StringLiteral]
abstract final class NativeClause implements AstNode {
/// Return the name of the native object that implements the class.
StringLiteral? get name;
/// Return the token representing the 'native' keyword.
Token get nativeKeyword;
}
/// The "native" clause in an class declaration.
///
/// nativeClause ::=
/// 'native' [StringLiteral]
final class NativeClauseImpl extends AstNodeImpl implements NativeClause {
@override
final Token nativeKeyword;
@override
final StringLiteralImpl? name;
/// Initialize a newly created native clause.
NativeClauseImpl({
required this.nativeKeyword,
required this.name,
}) {
_becomeParentOf(name);
}
@override
Token get beginToken => nativeKeyword;
@override
Token get endToken {
return name?.endToken ?? nativeKeyword;
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('nativeKeyword', nativeKeyword)
..addNode('name', name);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitNativeClause(this);
@override
void visitChildren(AstVisitor visitor) {
name?.accept(visitor);
}
}
/// A function body that consists of a native keyword followed by a string
/// literal.
///
/// nativeFunctionBody ::=
/// 'native' [SimpleStringLiteral] ';'
abstract final class NativeFunctionBody implements FunctionBody {
/// Return the token representing 'native' that marks the start of the
/// function body.
Token get nativeKeyword;
/// Return the token representing the semicolon that marks the end of the
/// function body.
Token get semicolon;
/// Return the string literal representing the string after the 'native'
/// token.
StringLiteral? get stringLiteral;
}
/// A function body that consists of a native keyword followed by a string
/// literal.
///
/// nativeFunctionBody ::=
/// 'native' [SimpleStringLiteral] ';'
final class NativeFunctionBodyImpl extends FunctionBodyImpl
implements NativeFunctionBody {
/// The token representing 'native' that marks the start of the function body.
@override
final Token nativeKeyword;
/// The string literal, after the 'native' token.
StringLiteralImpl? _stringLiteral;
/// The token representing the semicolon that marks the end of the function
/// body.
@override
final Token semicolon;
/// Initialize a newly created function body consisting of the 'native' token,
/// a string literal, and a semicolon.
NativeFunctionBodyImpl({
required this.nativeKeyword,
required StringLiteralImpl? stringLiteral,
required this.semicolon,
}) : _stringLiteral = stringLiteral {
_becomeParentOf(_stringLiteral);
}
@override
Token get beginToken => nativeKeyword;
@override
Token get endToken => semicolon;
@override
StringLiteralImpl? get stringLiteral => _stringLiteral;
set stringLiteral(StringLiteralImpl? stringLiteral) {
_stringLiteral = _becomeParentOf(stringLiteral);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('nativeKeyword', nativeKeyword)
..addNode('stringLiteral', stringLiteral)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitNativeFunctionBody(this);
@override
DartType resolve(ResolverVisitor resolver, DartType? imposedType) =>
resolver.visitNativeFunctionBody(this, imposedType: imposedType);
@override
void visitChildren(AstVisitor visitor) {
_stringLiteral?.accept(visitor);
}
}
/// A list of AST nodes that have a common parent.
abstract final class NodeList<E extends AstNode> implements List<E> {
/// Return the first token included in this node list's source range, or
/// `null` if the list is empty.
Token? get beginToken;
/// Return the last token included in this node list's source range, or `null`
/// if the list is empty.
Token? get endToken;
@Deprecated('NodeList cannot be resized')
@override
set length(int newLength);
/// Return the node that is the parent of each of the elements in the list.
AstNode get owner;
/// Return the node at the given [index] in the list or throw a [RangeError]
/// if [index] is out of bounds.
@override
E operator [](int index);
/// Use the given [visitor] to visit each of the nodes in this list.
void accept(AstVisitor visitor);
@Deprecated('NodeList cannot be resized')
@override
void add(E element);
@Deprecated('NodeList cannot be resized')
@override
void addAll(Iterable<E> iterable);
@Deprecated('NodeList cannot be resized')
@override
void clear();
@Deprecated('NodeList cannot be resized')
@override
void insert(int index, E element);
@Deprecated('NodeList cannot be resized')
@override
E removeAt(int index);
}
/// A list of AST nodes that have a common parent.
final class NodeListImpl<E extends AstNode>
with ListMixin<E>
implements NodeList<E> {
/// The node that is the parent of each of the elements in the list.
late final AstNodeImpl _owner;
/// The elements contained in the list.
late final List<E> _elements;
/// Initialize a newly created list of nodes such that all of the nodes that
/// are added to the list will have their parent set to the given [owner].
NodeListImpl(AstNodeImpl owner) : _owner = owner;
/// Create a partially initialized instance, [_initialize] must be called.
NodeListImpl._();
@override
Token? get beginToken {
if (_elements.isEmpty) {
return null;
}
return _elements[0].beginToken;
}
@override
Token? get endToken {
int length = _elements.length;
if (length == 0) {
return null;
}
return _elements[length - 1].endToken;
}
@override
int get length => _elements.length;
@Deprecated('NodeList cannot be resized')
@override
set length(int newLength) {
throw UnsupportedError("Cannot resize NodeList.");
}
@override
AstNodeImpl get owner => _owner;
@override
E operator [](int index) {
if (index < 0 || index >= _elements.length) {
throw RangeError("Index: $index, Size: ${_elements.length}");
}
return _elements[index];
}
@override
void operator []=(int index, E node) {
if (index < 0 || index >= _elements.length) {
throw RangeError("Index: $index, Size: ${_elements.length}");
}
_elements[index] = node;
_owner._becomeParentOf(node as AstNodeImpl);
}
@override
void accept(AstVisitor visitor) {
int length = _elements.length;
for (var i = 0; i < length; i++) {
_elements[i].accept(visitor);
}
}
@Deprecated('NodeList cannot be resized')
@override
void add(E element) {
throw UnsupportedError("Cannot resize NodeList.");
}
@Deprecated('NodeList cannot be resized')
@override
void addAll(Iterable<E> iterable) {
throw UnsupportedError("Cannot resize NodeList.");
}
@Deprecated('NodeList cannot be resized')
@override
void clear() {
throw UnsupportedError("Cannot resize NodeList.");
}
@Deprecated('NodeList cannot be resized')
@override
void insert(int index, E element) {
throw UnsupportedError("Cannot resize NodeList.");
}
@Deprecated('NodeList cannot be resized')
@override
E removeAt(int index) {
throw UnsupportedError("Cannot resize NodeList.");
}
/// Set the [owner] of this container, and populate it with [elements].
void _initialize(AstNodeImpl owner, List<E>? elements) {
_owner = owner;
if (elements == null || elements.isEmpty) {
_elements = const <Never>[];
} else {
_elements = elements.toList(growable: false);
var length = elements.length;
for (var i = 0; i < length; i++) {
var node = elements[i];
owner._becomeParentOf(node as AstNodeImpl);
}
}
}
}
/// A formal parameter that is required (is not optional).
///
/// normalFormalParameter ::=
/// [FunctionTypedFormalParameter]
/// | [FieldFormalParameter]
/// | [SimpleFormalParameter]
sealed class NormalFormalParameter implements FormalParameter {
/// Return the documentation comment associated with this parameter, or `null`
/// if this parameter does not have a documentation comment associated with
/// it.
Comment? get documentationComment;
/// Return a list containing the comment and annotations associated with this
/// parameter, sorted in lexical order.
List<AstNode> get sortedCommentAndAnnotations;
}
/// A formal parameter that is required (is not optional).
///
/// normalFormalParameter ::=
/// [FunctionTypedFormalParameter]
/// | [FieldFormalParameter]
/// | [SimpleFormalParameter]
sealed class NormalFormalParameterImpl extends FormalParameterImpl
implements NormalFormalParameter {
/// The documentation comment associated with this parameter, or `null` if
/// this parameter does not have a documentation comment associated with it.
CommentImpl? _comment;
/// The annotations associated with this parameter.
final NodeListImpl<AnnotationImpl> _metadata = NodeListImpl._();
/// The 'covariant' keyword, or `null` if the keyword was not used.
@override
final Token? covariantKeyword;
/// The 'required' keyword, or `null` if the keyword was not used.
@override
final Token? requiredKeyword;
@override
final Token? name;
/// Initialize a newly created formal parameter. Either or both of the
/// [comment] and [metadata] can be `null` if the parameter does not have the
/// corresponding attribute.
NormalFormalParameterImpl({
required CommentImpl? comment,
required List<AnnotationImpl>? metadata,
required this.covariantKeyword,
required this.requiredKeyword,
required this.name,
}) : _comment = comment {
_becomeParentOf(_comment);
_metadata._initialize(this, metadata);
}
@override
CommentImpl? get documentationComment => _comment;
set documentationComment(CommentImpl? comment) {
_comment = _becomeParentOf(comment);
}
@override
ParameterKind get kind {
final parent = this.parent;
if (parent is DefaultFormalParameterImpl) {
return parent.kind;
}
return ParameterKind.REQUIRED;
}
@override
NodeListImpl<AnnotationImpl> get metadata => _metadata;
@override
List<AstNode> get sortedCommentAndAnnotations {
var comment = _comment;
return <AstNode>[
if (comment != null) comment,
..._metadata,
]..sort(AstNode.LEXICAL_ORDER);
}
@override
ChildEntities get _childEntities {
return ChildEntities()
..addNode('documentationComment', documentationComment)
..addNodeList('metadata', metadata)
..addToken('requiredKeyword', requiredKeyword)
..addToken('covariantKeyword', covariantKeyword);
}
@override
void visitChildren(AstVisitor visitor) {
//
// Note that subclasses are responsible for visiting the identifier because
// they often need to visit other nodes before visiting the identifier.
//
if (_commentIsBeforeAnnotations()) {
_comment?.accept(visitor);
_metadata.accept(visitor);
} else {
List<AstNode> children = sortedCommentAndAnnotations;
int length = children.length;
for (int i = 0; i < length; i++) {
children[i].accept(visitor);
}
}
}
/// Return `true` if the comment is lexically before any annotations.
bool _commentIsBeforeAnnotations() {
if (_comment == null || _metadata.isEmpty) {
return true;
}
Annotation firstAnnotation = _metadata[0];
return _comment!.offset < firstAnnotation.offset;
}
}
/// A null-assert pattern.
///
/// nullAssertPattern ::=
/// [DartPattern] '!'
abstract final class NullAssertPattern implements DartPattern {
/// The `!` token.
Token get operator;
/// The sub-pattern.
DartPattern get pattern;
}
/// A null-assert pattern.
///
/// nullAssertPattern ::=
/// [DartPattern] '!'
final class NullAssertPatternImpl extends DartPatternImpl
implements NullAssertPattern {
@override
final DartPatternImpl pattern;
@override
final Token operator;
NullAssertPatternImpl({
required this.pattern,
required this.operator,
}) {
_becomeParentOf(pattern);
}
@override
Token get beginToken => pattern.beginToken;
@override
Token get endToken => operator;
@override
PatternPrecedence get precedence => PatternPrecedence.postfix;
@override
VariablePatternImpl? get variablePattern => pattern.variablePattern;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('pattern', pattern)
..addToken('operator', operator);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitNullAssertPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor.analyzeNullCheckOrAssertPatternSchema(
pattern,
isAssert: true,
);
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
resolverVisitor.analyzeNullCheckOrAssertPattern(context, this, pattern,
isAssert: true);
}
@override
void visitChildren(AstVisitor visitor) {
pattern.accept(visitor);
}
}
/// A null-check pattern.
///
/// nullCheckPattern ::=
/// [DartPattern] '?'
abstract final class NullCheckPattern implements DartPattern {
/// The `?` token.
Token get operator;
/// The sub-pattern.
DartPattern get pattern;
}
/// A null-check pattern.
///
/// nullCheckPattern ::=
/// [DartPattern] '?'
final class NullCheckPatternImpl extends DartPatternImpl
implements NullCheckPattern {
@override
final DartPatternImpl pattern;
@override
final Token operator;
NullCheckPatternImpl({
required this.pattern,
required this.operator,
}) {
_becomeParentOf(pattern);
}
@override
Token get beginToken => pattern.beginToken;
@override
Token get endToken => operator;
@override
PatternPrecedence get precedence => PatternPrecedence.postfix;
@override
VariablePatternImpl? get variablePattern => pattern.variablePattern;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('pattern', pattern)
..addToken('operator', operator);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitNullCheckPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor.analyzeNullCheckOrAssertPatternSchema(
pattern,
isAssert: false,
);
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
resolverVisitor.analyzeNullCheckOrAssertPattern(context, this, pattern,
isAssert: false);
}
@override
void visitChildren(AstVisitor visitor) {
pattern.accept(visitor);
}
}
/// A null literal expression.
///
/// nullLiteral ::=
/// 'null'
abstract final class NullLiteral implements Literal {
/// Return the token representing the literal.
Token get literal;
}
/// A null literal expression.
///
/// nullLiteral ::=
/// 'null'
final class NullLiteralImpl extends LiteralImpl implements NullLiteral {
/// The token representing the literal.
@override
final Token literal;
/// Initialize a newly created null literal.
NullLiteralImpl({
required this.literal,
});
@override
Token get beginToken => literal;
@override
Token get endToken => literal;
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('literal', literal);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitNullLiteral(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitNullLiteral(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
}
/// Abstract interface for expressions that may participate in null-shorting.
abstract final class NullShortableExpression implements Expression {
/// Returns the expression that terminates any null shorting that might occur
/// in this expression. This may be called regardless of whether this
/// expression is itself null-aware.
///
/// For example, the statement `a?.b[c] = d;` contains the following
/// null-shortable subexpressions:
/// - `a?.b`
/// - `a?.b[c]`
/// - `a?.b[c] = d`
///
/// Calling [nullShortingTermination] on any of these subexpressions yields
/// the expression `a?.b[c] = d`, indicating that the null-shorting induced by
/// the `?.` causes the rest of the subexpression `a?.b[c] = d` to be skipped.
Expression get nullShortingTermination;
}
/// Mixin that can be used to implement [NullShortableExpression].
base mixin NullShortableExpressionImpl implements NullShortableExpression {
@override
Expression get nullShortingTermination {
var result = this;
while (true) {
var parent = result._nullShortingExtensionCandidate;
if (parent is NullShortableExpressionImpl &&
parent._extendsNullShorting(result)) {
result = parent;
} else {
return result;
}
}
}
/// Gets the ancestor of this node to which null-shorting might be extended.
/// Usually this is just the node's parent, however if `this` is the base of
/// a cascade section, it will be the cascade expression itself, which may be
/// a more distant ancestor.
AstNode? get _nullShortingExtensionCandidate;
/// Indicates whether the effect of any null-shorting within [descendant]
/// (which should be a descendant of `this`) should extend to include `this`.
bool _extendsNullShorting(Expression descendant);
}
/// An object pattern.
///
/// objectPattern ::=
/// [Identifier] [TypeArgumentList]? '(' [PatternField] ')'
abstract final class ObjectPattern implements DartPattern {
/// Return the patterns matching the properties of the object.
NodeList<PatternField> get fields;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right parenthesis.
Token get rightParenthesis;
/// The name of the type of object from which values will be extracted.
NamedType get type;
}
/// An object pattern.
///
/// objectPattern ::=
/// [Identifier] [TypeArgumentList]? '(' [PatternField] ')'
final class ObjectPatternImpl extends DartPatternImpl implements ObjectPattern {
final NodeListImpl<PatternFieldImpl> _fields = NodeListImpl._();
@override
final Token leftParenthesis;
@override
final Token rightParenthesis;
@override
final NamedTypeImpl type;
ObjectPatternImpl({
required this.type,
required this.leftParenthesis,
required List<PatternFieldImpl> fields,
required this.rightParenthesis,
}) {
_becomeParentOf(type);
_fields._initialize(this, fields);
}
@override
Token get beginToken => type.beginToken;
@override
Token get endToken => rightParenthesis;
@override
NodeList<PatternFieldImpl> get fields => _fields;
@override
PatternPrecedence get precedence => PatternPrecedence.primary;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('type', type)
..addToken('leftParenthesis', leftParenthesis)
..addNodeList('fields', fields)
..addToken('rightParenthesis', rightParenthesis);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitObjectPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor.analyzeObjectPatternSchema(type.typeOrThrow);
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
final result = resolverVisitor.analyzeObjectPattern(
context,
this,
fields: resolverVisitor.buildSharedPatternFields(
fields,
mustBeNamed: true,
),
);
resolverVisitor.checkPatternNeverMatchesValueType(
context: context,
pattern: this,
requiredType: result.requiredType,
);
}
@override
void visitChildren(AstVisitor visitor) {
type.accept(visitor);
fields.accept(visitor);
}
}
/// The "on" clause in a mixin declaration.
///
/// onClause ::=
/// 'on' [NamedType] (',' [NamedType])*
abstract final class OnClause implements AstNode {
/// Return the token representing the 'on' keyword.
Token get onKeyword;
/// Return the list of the classes are superclass constraints for the mixin.
NodeList<NamedType> get superclassConstraints;
}
/// The "on" clause in a mixin declaration.
///
/// onClause ::=
/// 'on' [NamedType] (',' [NamedType])*
final class OnClauseImpl extends AstNodeImpl implements OnClause {
@override
final Token onKeyword;
/// The classes are super-class constraints for the mixin.
final NodeListImpl<NamedTypeImpl> _superclassConstraints = NodeListImpl._();
/// Initialize a newly created on clause.
OnClauseImpl({
required this.onKeyword,
required List<NamedTypeImpl> superclassConstraints,
}) {
_superclassConstraints._initialize(this, superclassConstraints);
}
@override
Token get beginToken => onKeyword;
@override
Token get endToken => _superclassConstraints.endToken ?? onKeyword;
@override
NodeListImpl<NamedTypeImpl> get superclassConstraints =>
_superclassConstraints;
@override
// TODO(paulberry): add commas.
ChildEntities get _childEntities => ChildEntities()
..addToken('onKeyword', onKeyword)
..addNodeList('superclassConstraints', superclassConstraints);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitOnClause(this);
@override
void visitChildren(AstVisitor visitor) {
_superclassConstraints.accept(visitor);
}
}
/// A parenthesized expression.
///
/// parenthesizedExpression ::=
/// '(' [Expression] ')'
abstract final class ParenthesizedExpression implements Expression {
/// Return the expression within the parentheses.
Expression get expression;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right parenthesis.
Token get rightParenthesis;
}
/// A parenthesized expression.
///
/// parenthesizedExpression ::=
/// '(' [Expression] ')'
final class ParenthesizedExpressionImpl extends ExpressionImpl
implements ParenthesizedExpression {
/// The left parenthesis.
@override
final Token leftParenthesis;
/// The expression within the parentheses.
ExpressionImpl _expression;
/// The right parenthesis.
@override
final Token rightParenthesis;
/// Initialize a newly created parenthesized expression.
ParenthesizedExpressionImpl({
required this.leftParenthesis,
required ExpressionImpl expression,
required this.rightParenthesis,
}) : _expression = expression {
_becomeParentOf(_expression);
}
@override
Token get beginToken => leftParenthesis;
@override
Token get endToken => rightParenthesis;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
Precedence get precedence => Precedence.primary;
@override
ExpressionImpl get unParenthesized {
// This is somewhat inefficient, but it avoids a stack overflow in the
// degenerate case.
var expression = _expression;
while (expression is ParenthesizedExpressionImpl) {
expression = expression._expression;
}
return expression;
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('leftParenthesis', leftParenthesis)
..addNode('expression', expression)
..addToken('rightParenthesis', rightParenthesis);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitParenthesizedExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitParenthesizedExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
}
}
/// A parenthesized pattern.
///
/// parenthesizedPattern ::=
/// '(' [DartPattern] ')'
abstract final class ParenthesizedPattern implements DartPattern {
/// Return the left parenthesis.
Token get leftParenthesis;
/// The pattern within the parentheses.
DartPattern get pattern;
/// Return the right parenthesis.
Token get rightParenthesis;
}
/// A parenthesized pattern.
///
/// parenthesizedPattern ::=
/// '(' [DartPattern] ')'
final class ParenthesizedPatternImpl extends DartPatternImpl
implements ParenthesizedPattern {
@override
final Token leftParenthesis;
@override
final DartPatternImpl pattern;
@override
final Token rightParenthesis;
ParenthesizedPatternImpl({
required this.leftParenthesis,
required this.pattern,
required this.rightParenthesis,
}) {
_becomeParentOf(pattern);
}
@override
Token get beginToken => leftParenthesis;
@override
Token get endToken => rightParenthesis;
@override
PatternPrecedence get precedence => PatternPrecedence.primary;
@override
DartPattern get unParenthesized {
var result = pattern;
while (result is ParenthesizedPatternImpl) {
result = result.pattern;
}
return result;
}
@override
VariablePatternImpl? get variablePattern => pattern.variablePattern;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('leftParenthesis', leftParenthesis)
..addNode('pattern', pattern)
..addToken('rightParenthesis', rightParenthesis);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitParenthesizedPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor.dispatchPatternSchema(pattern);
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
resolverVisitor.dispatchPattern(context, pattern);
}
@override
void visitChildren(AstVisitor visitor) {
pattern.accept(visitor);
}
}
/// A part directive.
///
/// partDirective ::=
/// [Annotation] 'part' [StringLiteral] ';'
abstract final class PartDirective implements UriBasedDirective {
@override
PartElement? get element;
/// Return the token representing the 'part' keyword.
Token get partKeyword;
/// Return the semicolon terminating the directive.
Token get semicolon;
}
/// A part directive.
///
/// partDirective ::=
/// [Annotation] 'part' [StringLiteral] ';'
final class PartDirectiveImpl extends UriBasedDirectiveImpl
implements PartDirective {
/// The token representing the 'part' keyword.
@override
final Token partKeyword;
/// The semicolon terminating the directive.
@override
final Token semicolon;
/// Initialize a newly created part directive. Either or both of the [comment]
/// and [metadata] can be `null` if the directive does not have the
/// corresponding attribute.
PartDirectiveImpl({
required super.comment,
required super.metadata,
required this.partKeyword,
required super.uri,
required this.semicolon,
});
@override
PartElement? get element {
return super.element as PartElement?;
}
@override
Token get endToken => semicolon;
@override
Token get firstTokenAfterCommentAndMetadata => partKeyword;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('partKeyword', partKeyword)
..addNode('uri', uri)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPartDirective(this);
}
/// A part-of directive.
///
/// partOfDirective ::=
/// [Annotation] 'part' 'of' [Identifier] ';'
abstract final class PartOfDirective implements Directive {
/// Return the name of the library that the containing compilation unit is
/// part of.
LibraryIdentifier? get libraryName;
/// Return the token representing the 'of' keyword.
Token get ofKeyword;
/// Return the token representing the 'part' keyword.
Token get partKeyword;
/// Return the semicolon terminating the directive.
Token get semicolon;
/// Return the URI of the library that the containing compilation unit is part
/// of, or `null` if no URI was given (typically because a library name was
/// provided).
StringLiteral? get uri;
}
/// A part-of directive.
///
/// partOfDirective ::=
/// [Annotation] 'part' 'of' [Identifier] ';'
final class PartOfDirectiveImpl extends DirectiveImpl
implements PartOfDirective {
/// The token representing the 'part' keyword.
@override
final Token partKeyword;
/// The token representing the 'of' keyword.
@override
final Token ofKeyword;
/// The URI of the library that the containing compilation unit is part of.
StringLiteralImpl? _uri;
/// The name of the library that the containing compilation unit is part of,
/// or `null` if no name was given (typically because a library URI was
/// provided).
LibraryIdentifierImpl? _libraryName;
/// The semicolon terminating the directive.
@override
final Token semicolon;
/// Initialize a newly created part-of directive. Either or both of the
/// [comment] and [metadata] can be `null` if the directive does not have the
/// corresponding attribute.
PartOfDirectiveImpl({
required super.comment,
required super.metadata,
required this.partKeyword,
required this.ofKeyword,
required StringLiteralImpl? uri,
required LibraryIdentifierImpl? libraryName,
required this.semicolon,
}) : _uri = uri,
_libraryName = libraryName {
_becomeParentOf(_uri);
_becomeParentOf(_libraryName);
}
@override
Token get endToken => semicolon;
@override
Token get firstTokenAfterCommentAndMetadata => partKeyword;
@override
LibraryIdentifierImpl? get libraryName => _libraryName;
set libraryName(LibraryIdentifierImpl? libraryName) {
_libraryName = _becomeParentOf(libraryName);
}
@override
StringLiteralImpl? get uri => _uri;
set uri(StringLiteralImpl? uri) {
_uri = _becomeParentOf(uri);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('partKeyword', partKeyword)
..addToken('ofKeyword', ofKeyword)
..addNode('uri', uri)
..addNode('libraryName', libraryName)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPartOfDirective(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_libraryName?.accept(visitor);
_uri?.accept(visitor);
}
}
/// A pattern assignment.
///
/// patternAssignment ::=
/// [DartPattern] '=' [Expression]
abstract final class PatternAssignment implements Expression {
/// Return the equal sign separating the pattern from the expression.
Token get equals;
/// The expression that will be matched by the pattern.
Expression get expression;
/// The pattern that will match the expression.
DartPattern get pattern;
}
/// A pattern assignment.
///
/// patternAssignment ::=
/// [DartPattern] '=' [Expression]
///
/// When used as the condition in an `if`, the pattern is always a
/// [PatternVariable] whose type is not `null`.
final class PatternAssignmentImpl extends ExpressionImpl
implements PatternAssignment {
@override
final Token equals;
ExpressionImpl _expression;
@override
final DartPatternImpl pattern;
/// The pattern type schema, used for downward inference of [expression];
/// or `null` if the node is not resolved yet.
DartType? patternTypeSchema;
PatternAssignmentImpl({
required this.pattern,
required this.equals,
required ExpressionImpl expression,
}) : _expression = expression {
_becomeParentOf(pattern);
_becomeParentOf(_expression);
}
@override
Token get beginToken => pattern.beginToken;
@override
Token get endToken => expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
// TODO(brianwilkerson): Create a new precedence constant for pattern
// assignments. The proposal doesn't make the actual value clear.
Precedence get precedence => Precedence.assignment;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('pattern', pattern)
..addToken('equals', equals)
..addNode('expression', expression);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPatternAssignment(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType? contextType) {
resolver.visitPatternAssignment(this);
}
@override
void visitChildren(AstVisitor visitor) {
pattern.accept(visitor);
expression.accept(visitor);
}
}
/// A field in an object or record pattern.
///
/// patternField ::=
/// [PatternFieldName]? [DartPattern]
abstract final class PatternField implements AstNode {
/// The name specified explicitly by [name], or implied by the variable
/// pattern inside [pattern]. Always `null` if [name] is `null`. Can be `null`
/// if [name] does not have the explicit name and [pattern] is not a variable
/// pattern.
String? get effectiveName;
/// The element referenced by [effectiveName]. Is `null` if not resolved yet,
/// not `null` inside valid [ObjectPattern]s, always `null` inside
/// [RecordPattern]s.
Element? get element;
/// The name of the field, or `null` if the field is a positional field.
PatternFieldName? get name;
/// The pattern used to match the corresponding record field.
DartPattern get pattern;
}
/// A field in a record pattern.
///
/// patternField ::=
/// [PatternFieldName]? [DartPattern]
final class PatternFieldImpl extends AstNodeImpl implements PatternField {
@override
Element? element;
@override
final PatternFieldNameImpl? name;
@override
final DartPatternImpl pattern;
PatternFieldImpl({required this.name, required this.pattern}) {
_becomeParentOf(name);
_becomeParentOf(pattern);
}
@override
Token get beginToken => name?.beginToken ?? pattern.beginToken;
@override
String? get effectiveName {
final nameNode = name;
if (nameNode != null) {
final nameToken = nameNode.name ?? pattern.variablePattern?.name;
return nameToken?.lexeme;
}
return null;
}
@override
Token get endToken => pattern.endToken;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('name', name)
..addNode('pattern', pattern);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPatternField(this);
@override
void visitChildren(AstVisitor visitor) {
name?.accept(visitor);
pattern.accept(visitor);
}
}
/// A field name in an object or record pattern field.
///
/// patternFieldName ::=
/// [Token]? ':'
abstract final class PatternFieldName implements AstNode {
/// The colon following the name.
Token get colon;
/// The name of the field.
Token? get name;
}
/// A field name in a record pattern field.
///
/// patternFieldName ::=
/// [Token]? ':'
final class PatternFieldNameImpl extends AstNodeImpl
implements PatternFieldName {
@override
final Token colon;
@override
final Token? name;
PatternFieldNameImpl({required this.name, required this.colon});
@override
Token get beginToken => name ?? colon;
@override
Token get endToken => colon;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('name', name)
..addToken('colon', colon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPatternFieldName(this);
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
}
/// A pattern variable declaration.
///
/// patternDeclaration ::=
/// ( 'final' | 'var' ) [DartPattern] '=' [Expression]
abstract final class PatternVariableDeclaration implements AnnotatedNode {
/// Return the equal sign separating the pattern from the expression.
Token get equals;
/// The expression that will be matched by the pattern.
Expression get expression;
/// Return the `var` or `final` keyword introducing the declaration.
Token get keyword;
/// The pattern that will match the expression.
DartPattern get pattern;
}
/// A pattern variable declaration.
///
/// patternDeclaration ::=
/// ( 'final' | 'var' ) [DartPattern] '=' [Expression]
final class PatternVariableDeclarationImpl extends AnnotatedNodeImpl
implements PatternVariableDeclaration {
@override
final Token equals;
ExpressionImpl _expression;
@override
final Token keyword;
@override
final DartPatternImpl pattern;
/// The pattern type schema, used for downward inference of [expression];
/// or `null` if the node is not resolved yet.
DartType? patternTypeSchema;
/// Variables declared in [pattern].
late final List<BindPatternVariableElementImpl> elements;
PatternVariableDeclarationImpl({
required this.keyword,
required this.pattern,
required this.equals,
required ExpressionImpl expression,
required super.comment,
required super.metadata,
}) : _expression = expression {
_becomeParentOf(pattern);
_becomeParentOf(_expression);
}
@override
Token get endToken => expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
/// If [keyword] is `final`, returns it.
Token? get finalKeyword {
if (keyword.keyword == Keyword.FINAL) {
return keyword;
}
return null;
}
@override
Token get firstTokenAfterCommentAndMetadata => keyword;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('keyword', keyword)
..addNode('pattern', pattern)
..addToken('equals', equals)
..addNode('expression', expression);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitPatternVariableDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
pattern.accept(visitor);
expression.accept(visitor);
}
}
/// A pattern variable declaration statement.
///
/// patternDeclaration ::=
/// [PatternVariableDeclaration] ';'
abstract final class PatternVariableDeclarationStatement implements Statement {
/// The pattern declaration.
PatternVariableDeclaration get declaration;
/// Return the semicolon terminating the statement.
Token get semicolon;
}
/// A pattern variable declaration statement.
///
/// patternDeclarationStatement ::=
/// [PatternVariableDeclaration] ';'
final class PatternVariableDeclarationStatementImpl extends StatementImpl
implements PatternVariableDeclarationStatement {
@override
final PatternVariableDeclarationImpl declaration;
@override
final Token semicolon;
PatternVariableDeclarationStatementImpl({
required this.declaration,
required this.semicolon,
}) {
_becomeParentOf(declaration);
}
@override
Token get beginToken => declaration.beginToken;
@override
Token get endToken => semicolon;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('declaration', declaration)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitPatternVariableDeclarationStatement(this);
@override
void visitChildren(AstVisitor visitor) {
declaration.accept(visitor);
}
}
/// A postfix unary expression.
///
/// postfixExpression ::=
/// [Expression] [Token]
abstract final class PostfixExpression
implements
Expression,
NullShortableExpression,
MethodReferenceExpression,
CompoundAssignmentExpression {
/// Return the expression computing the operand for the operator.
Expression get operand;
/// Return the postfix operator being applied to the operand.
Token get operator;
}
/// A postfix unary expression.
///
/// postfixExpression ::=
/// [Expression] [Token]
final class PostfixExpressionImpl extends ExpressionImpl
with NullShortableExpressionImpl, CompoundAssignmentExpressionImpl
implements PostfixExpression {
/// The expression computing the operand for the operator.
ExpressionImpl _operand;
/// The postfix operator being applied to the operand.
@override
final Token operator;
/// The element associated with the operator based on the static type of the
/// operand, or `null` if the AST structure has not been resolved, if the
/// operator is not user definable, or if the operator could not be resolved.
@override
MethodElement? staticElement;
/// Initialize a newly created postfix expression.
PostfixExpressionImpl({
required ExpressionImpl operand,
required this.operator,
}) : _operand = operand {
_becomeParentOf(_operand);
}
@override
Token get beginToken => _operand.beginToken;
@override
Token get endToken => operator;
@override
ExpressionImpl get operand => _operand;
set operand(ExpressionImpl expression) {
_operand = _becomeParentOf(expression);
}
@override
Precedence get precedence => Precedence.postfix;
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('operand', operand)
..addToken('operator', operator);
@override
AstNode? get _nullShortingExtensionCandidate => parent;
/// If the AST structure has been resolved, and the function being invoked is
/// known based on static type information, then return the parameter element
/// representing the parameter to which the value of the operand will be
/// bound. Otherwise, return `null`.
ParameterElement? get _staticParameterElementForOperand {
if (staticElement == null) {
return null;
}
List<ParameterElement> parameters = staticElement!.parameters;
if (parameters.isEmpty) {
return null;
}
return parameters[0];
}
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPostfixExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitPostfixExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_operand.accept(visitor);
}
@override
bool _extendsNullShorting(Expression descendant) =>
identical(descendant, operand);
}
/// An identifier that is prefixed or an access to an object property where the
/// target of the property access is a simple identifier.
///
/// prefixedIdentifier ::=
/// [SimpleIdentifier] '.' [SimpleIdentifier]
abstract final class PrefixedIdentifier implements Identifier {
/// Return the identifier being prefixed.
SimpleIdentifier get identifier;
/// Return `true` if this type is a deferred type. If the AST structure has
/// not been resolved, then return `false`.
///
/// 15.1 Static Types: A type <i>T</i> is deferred iff it is of the form
/// </i>p.T</i> where <i>p</i> is a deferred prefix.
bool get isDeferred;
/// Return the period used to separate the prefix from the identifier.
Token get period;
/// Return the prefix associated with the library in which the identifier is
/// defined.
SimpleIdentifier get prefix;
}
/// An identifier that is prefixed or an access to an object property where the
/// target of the property access is a simple identifier.
///
/// prefixedIdentifier ::=
/// [SimpleIdentifier] '.' [SimpleIdentifier]
final class PrefixedIdentifierImpl extends IdentifierImpl
implements PrefixedIdentifier {
/// The prefix associated with the library in which the identifier is defined.
SimpleIdentifierImpl _prefix;
/// The period used to separate the prefix from the identifier.
@override
final Token period;
/// The identifier being prefixed.
SimpleIdentifierImpl _identifier;
/// Initialize a newly created prefixed identifier.
PrefixedIdentifierImpl({
required SimpleIdentifierImpl prefix,
required this.period,
required SimpleIdentifierImpl identifier,
}) : _prefix = prefix,
_identifier = identifier {
_becomeParentOf(_prefix);
_becomeParentOf(_identifier);
}
@override
Token get beginToken => _prefix.beginToken;
@override
Token get endToken => _identifier.endToken;
@override
SimpleIdentifierImpl get identifier => _identifier;
set identifier(SimpleIdentifierImpl identifier) {
_identifier = _becomeParentOf(identifier);
}
@override
bool get isDeferred {
Element? element = _prefix.staticElement;
if (element is PrefixElement) {
final imports = element.imports;
if (imports.length != 1) {
return false;
}
return imports[0].prefix is DeferredImportElementPrefix;
}
return false;
}
@override
String get name => "${_prefix.name}.${_identifier.name}";
@override
Precedence get precedence => Precedence.postfix;
@override
SimpleIdentifierImpl get prefix => _prefix;
set prefix(SimpleIdentifierImpl identifier) {
_prefix = _becomeParentOf(identifier);
}
@override
Element? get staticElement {
return _identifier.staticElement;
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('prefix', prefix)
..addToken('period', period)
..addNode('identifier', identifier);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPrefixedIdentifier(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitPrefixedIdentifier(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_prefix.accept(visitor);
_identifier.accept(visitor);
}
}
/// A prefix unary expression.
///
/// prefixExpression ::=
/// [Token] [Expression]
abstract final class PrefixExpression
implements
Expression,
NullShortableExpression,
MethodReferenceExpression,
CompoundAssignmentExpression {
/// Return the expression computing the operand for the operator.
Expression get operand;
/// Return the prefix operator being applied to the operand.
Token get operator;
}
/// A prefix unary expression.
///
/// prefixExpression ::=
/// [Token] [Expression]
final class PrefixExpressionImpl extends ExpressionImpl
with NullShortableExpressionImpl, CompoundAssignmentExpressionImpl
implements PrefixExpression {
/// The prefix operator being applied to the operand.
@override
final Token operator;
/// The expression computing the operand for the operator.
ExpressionImpl _operand;
/// The element associated with the operator based on the static type of the
/// operand, or `null` if the AST structure has not been resolved, if the
/// operator is not user definable, or if the operator could not be resolved.
@override
MethodElement? staticElement;
/// Initialize a newly created prefix expression.
PrefixExpressionImpl({
required this.operator,
required ExpressionImpl operand,
}) : _operand = operand {
_becomeParentOf(_operand);
}
@override
Token get beginToken => operator;
@override
Token get endToken => _operand.endToken;
@override
ExpressionImpl get operand => _operand;
set operand(ExpressionImpl expression) {
_operand = _becomeParentOf(expression);
}
@override
Precedence get precedence => Precedence.prefix;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('operator', operator)
..addNode('operand', operand);
@override
AstNode? get _nullShortingExtensionCandidate => parent;
/// If the AST structure has been resolved, and the function being invoked is
/// known based on static type information, then return the parameter element
/// representing the parameter to which the value of the operand will be
/// bound. Otherwise, return `null`.
ParameterElement? get _staticParameterElementForOperand {
if (staticElement == null) {
return null;
}
List<ParameterElement> parameters = staticElement!.parameters;
if (parameters.isEmpty) {
return null;
}
return parameters[0];
}
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPrefixExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitPrefixExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_operand.accept(visitor);
}
@override
bool _extendsNullShorting(Expression descendant) =>
identical(descendant, operand) && operator.type.isIncrementOperator;
}
/// The access of a property of an object.
///
/// Note, however, that accesses to properties of objects can also be
/// represented as [PrefixedIdentifier] nodes in cases where the target is also
/// a simple identifier.
///
/// propertyAccess ::=
/// [Expression] '.' [SimpleIdentifier]
abstract final class PropertyAccess
implements NullShortableExpression, CommentReferableExpression {
/// Return `true` if this expression is cascaded.
///
/// If it is, then the target of this expression is not stored locally but is
/// stored in the nearest ancestor that is a [CascadeExpression].
bool get isCascaded;
/// Whether this property access is null aware (as opposed to non-null).
bool get isNullAware;
/// Return the property access operator.
Token get operator;
/// Return the name of the property being accessed.
SimpleIdentifier get propertyName;
/// Return the expression used to compute the receiver of the invocation.
///
/// If this invocation is not part of a cascade expression, then this is the
/// same as [target]. If this invocation is part of a cascade expression,
/// then the target stored with the cascade expression is returned.
Expression get realTarget;
/// Return the expression computing the object defining the property being
/// accessed, or `null` if this property access is part of a cascade
/// expression.
///
/// Use [realTarget] to get the target independent of whether this is part of
/// a cascade expression.
Expression? get target;
}
/// The access of a property of an object.
///
/// Note, however, that accesses to properties of objects can also be
/// represented as [PrefixedIdentifier] nodes in cases where the target is also
/// a simple identifier.
///
/// propertyAccess ::=
/// [Expression] '.' [SimpleIdentifier]
final class PropertyAccessImpl extends CommentReferableExpressionImpl
with NullShortableExpressionImpl
implements PropertyAccess {
/// The expression computing the object defining the property being accessed.
ExpressionImpl? _target;
/// The property access operator.
@override
final Token operator;
/// The name of the property being accessed.
SimpleIdentifierImpl _propertyName;
/// Initialize a newly created property access expression.
PropertyAccessImpl({
required ExpressionImpl? target,
required this.operator,
required SimpleIdentifierImpl propertyName,
}) : _target = target,
_propertyName = propertyName {
_becomeParentOf(_target);
_becomeParentOf(_propertyName);
}
@override
Token get beginToken {
if (target case final target?) {
return target.beginToken;
}
return operator;
}
@override
Token get endToken => _propertyName.endToken;
@override
bool get isAssignable => true;
@override
bool get isCascaded =>
operator.type == TokenType.PERIOD_PERIOD ||
operator.type == TokenType.QUESTION_PERIOD_PERIOD;
@override
bool get isNullAware {
if (isCascaded) {
return _ancestorCascade.isNullAware;
}
return operator.type == TokenType.QUESTION_PERIOD ||
operator.type == TokenType.QUESTION_PERIOD_PERIOD;
}
@override
Precedence get precedence => Precedence.postfix;
@override
SimpleIdentifierImpl get propertyName => _propertyName;
set propertyName(SimpleIdentifierImpl identifier) {
_propertyName = _becomeParentOf(identifier);
}
@override
ExpressionImpl get realTarget {
if (isCascaded) {
return _ancestorCascade.target;
}
return _target!;
}
@override
ExpressionImpl? get target => _target;
set target(ExpressionImpl? expression) {
_target = _becomeParentOf(expression);
}
/// Return the cascade that contains this [IndexExpression].
///
/// We expect that [isCascaded] is `true`.
CascadeExpressionImpl get _ancestorCascade {
assert(isCascaded);
for (var ancestor = parent!;; ancestor = ancestor.parent!) {
if (ancestor is CascadeExpressionImpl) {
return ancestor;
}
}
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('target', target)
..addToken('operator', operator)
..addNode('propertyName', propertyName);
@override
AstNode? get _nullShortingExtensionCandidate => parent;
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitPropertyAccess(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitPropertyAccess(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_target?.accept(visitor);
_propertyName.accept(visitor);
}
@override
bool _extendsNullShorting(Expression descendant) =>
identical(descendant, _target);
}
/// A record literal.
///
/// recordLiteral ::= '(' recordField (',' recordField)* ','? ')'
///
/// recordField ::= (identifier ':')? [Expression]
abstract final class RecordLiteral implements Literal {
/// Return the token representing the 'const' keyword, or `null` if the
/// literal is not a constant.
Token? get constKeyword;
/// Return the syntactic elements used to compute the fields of the record.
NodeList<Expression> get fields;
/// Return `true` if this literal is a constant expression, either because the
/// keyword `const` was explicitly provided or because no keyword was provided
/// and this expression is in a constant context.
bool get isConst;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right parenthesis.
Token get rightParenthesis;
}
final class RecordLiteralImpl extends LiteralImpl implements RecordLiteral {
@override
final Token? constKeyword;
@override
final Token leftParenthesis;
/// The syntactic elements used to compute the fields of the record.
final NodeListImpl<ExpressionImpl> _fields = NodeListImpl._();
@override
final Token rightParenthesis;
/// Initialize a newly created record literal.
RecordLiteralImpl({
required this.constKeyword,
required this.leftParenthesis,
required List<ExpressionImpl> fields,
required this.rightParenthesis,
}) {
_fields._initialize(this, fields);
}
@override
Token get beginToken => constKeyword ?? leftParenthesis;
@override
Token get endToken => rightParenthesis;
@override
NodeList<ExpressionImpl> get fields => _fields;
@override
bool get isConst => constKeyword != null || inConstantContext;
@override
// TODO(paulberry): add commas.
ChildEntities get _childEntities => super._childEntities
..addToken('constKeyword', constKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNodeList('fields', fields)
..addToken('rightParenthesis', rightParenthesis);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitRecordLiteral(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitRecordLiteral(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_fields.accept(visitor);
}
}
/// A record pattern.
///
/// recordPattern ::=
/// '(' [PatternField] (',' [PatternField])* ')'
abstract final class RecordPattern implements DartPattern {
/// Return the fields of the record pattern.
NodeList<PatternField> get fields;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right parenthesis.
Token get rightParenthesis;
}
/// A record pattern.
///
/// recordPattern ::=
/// '(' [PatternField] (',' [PatternField])* ')'
final class RecordPatternImpl extends DartPatternImpl implements RecordPattern {
final NodeListImpl<PatternFieldImpl> _fields = NodeListImpl._();
@override
final Token leftParenthesis;
@override
final Token rightParenthesis;
bool hasDuplicateNamedField = false;
RecordPatternImpl({
required this.leftParenthesis,
required List<PatternFieldImpl> fields,
required this.rightParenthesis,
}) {
_fields._initialize(this, fields);
}
@override
Token get beginToken => leftParenthesis;
@override
Token get endToken => rightParenthesis;
@override
NodeList<PatternFieldImpl> get fields => _fields;
@override
PatternPrecedence get precedence => PatternPrecedence.primary;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('leftParenthesis', leftParenthesis)
..addNodeList('fields', fields)
..addToken('rightParenthesis', rightParenthesis);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitRecordPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor.analyzeRecordPatternSchema(
fields: resolverVisitor.buildSharedPatternFields(
fields,
mustBeNamed: false,
),
);
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
final result = resolverVisitor.analyzeRecordPattern(
context,
this,
fields: resolverVisitor.buildSharedPatternFields(
fields,
mustBeNamed: false,
),
);
if (!hasDuplicateNamedField) {
resolverVisitor.checkPatternNeverMatchesValueType(
context: context,
pattern: this,
requiredType: result.requiredType,
);
}
}
@override
void visitChildren(AstVisitor visitor) {
fields.accept(visitor);
}
}
/// A record type.
///
/// recordType ::=
/// '(' recordTypeFields ',' recordTypeNamedFields ')'
/// | '(' recordTypeFields ','? ')'
/// | '(' recordTypeNamedFields ')'
///
/// recordTypeFields ::= recordTypeField ( ',' recordTypeField )*
///
/// recordTypeField ::= metadata type identifier?
///
/// recordTypeNamedFields ::=
/// '{' recordTypeNamedField
/// ( ',' recordTypeNamedField )* ','? '}'
///
/// recordTypeNamedField ::= metadata type identifier
abstract final class RecordTypeAnnotation implements TypeAnnotation {
/// The left parenthesis.
Token get leftParenthesis;
/// The optional named fields.
RecordTypeAnnotationNamedFields? get namedFields;
/// The positional fields (might be empty).
NodeList<RecordTypeAnnotationPositionalField> get positionalFields;
/// The right parenthesis.
Token get rightParenthesis;
}
/// A field in a [RecordTypeAnnotation].
sealed class RecordTypeAnnotationField implements AstNode {
/// The annotations associated with the field.
NodeList<Annotation> get metadata;
/// The name of the field.
Token? get name;
/// The type of the field.
TypeAnnotation get type;
}
sealed class RecordTypeAnnotationFieldImpl extends AstNodeImpl
implements RecordTypeAnnotationField {
@override
final NodeListImpl<AnnotationImpl> metadata = NodeListImpl._();
@override
final TypeAnnotationImpl type;
RecordTypeAnnotationFieldImpl({
required List<AnnotationImpl>? metadata,
required this.type,
}) {
this.metadata._initialize(this, metadata);
_becomeParentOf(type);
}
@override
Token get beginToken => metadata.beginToken ?? type.beginToken;
@override
Token get endToken => name ?? type.endToken;
@override
ChildEntities get _childEntities => super._childEntities
..addNodeList('metadata', metadata)
..addNode('type', type)
..addToken('name', name);
@override
void visitChildren(AstVisitor visitor) {
metadata.accept(visitor);
type.accept(visitor);
}
}
final class RecordTypeAnnotationImpl extends TypeAnnotationImpl
implements RecordTypeAnnotation {
@override
final Token leftParenthesis;
@override
final NodeListImpl<RecordTypeAnnotationPositionalFieldImpl> positionalFields =
NodeListImpl._();
@override
final RecordTypeAnnotationNamedFieldsImpl? namedFields;
@override
final Token rightParenthesis;
@override
final Token? question;
@override
DartType? type;
RecordTypeAnnotationImpl({
required this.leftParenthesis,
required List<RecordTypeAnnotationPositionalFieldImpl> positionalFields,
required this.namedFields,
required this.rightParenthesis,
required this.question,
}) {
_becomeParentOf(namedFields);
this.positionalFields._initialize(this, positionalFields);
}
@override
Token get beginToken => leftParenthesis;
@override
Token get endToken => question ?? rightParenthesis;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('leftParenthesis', leftParenthesis)
..addNodeList('positionalFields', positionalFields)
..addNode('namedFields', namedFields)
..addToken('rightParenthesis', rightParenthesis)
..addToken('question', question);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitRecordTypeAnnotation(this);
}
@override
void visitChildren(AstVisitor visitor) {
positionalFields.accept(visitor);
namedFields?.accept(visitor);
}
}
/// A named field in a [RecordTypeAnnotation].
abstract final class RecordTypeAnnotationNamedField
implements RecordTypeAnnotationField {
@override
Token get name;
}
final class RecordTypeAnnotationNamedFieldImpl
extends RecordTypeAnnotationFieldImpl
implements RecordTypeAnnotationNamedField {
@override
final Token name;
RecordTypeAnnotationNamedFieldImpl({
required super.metadata,
required super.type,
required this.name,
});
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitRecordTypeAnnotationNamedField(this);
}
}
/// The portion of a [RecordTypeAnnotation] with named fields.
abstract final class RecordTypeAnnotationNamedFields implements AstNode {
/// The fields contained in the block.
NodeList<RecordTypeAnnotationNamedField> get fields;
/// The left curly bracket.
Token get leftBracket;
/// The right curly bracket.
Token get rightBracket;
}
final class RecordTypeAnnotationNamedFieldsImpl extends AstNodeImpl
implements RecordTypeAnnotationNamedFields {
@override
final Token leftBracket;
@override
final NodeListImpl<RecordTypeAnnotationNamedFieldImpl> fields =
NodeListImpl._();
@override
final Token rightBracket;
RecordTypeAnnotationNamedFieldsImpl({
required this.leftBracket,
required List<RecordTypeAnnotationNamedFieldImpl> fields,
required this.rightBracket,
}) {
this.fields._initialize(this, fields);
}
@override
Token get beginToken => leftBracket;
@override
Token get endToken => rightBracket;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('leftBracket', leftBracket)
..addNodeList('fields', fields)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitRecordTypeAnnotationNamedFields(this);
}
@override
void visitChildren(AstVisitor visitor) {
fields.accept(visitor);
}
}
/// A positional field in a [RecordTypeAnnotation].
abstract final class RecordTypeAnnotationPositionalField
implements RecordTypeAnnotationField {}
final class RecordTypeAnnotationPositionalFieldImpl
extends RecordTypeAnnotationFieldImpl
implements RecordTypeAnnotationPositionalField {
@override
final Token? name;
RecordTypeAnnotationPositionalFieldImpl({
required super.metadata,
required super.type,
required this.name,
});
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitRecordTypeAnnotationPositionalField(this);
}
}
/// The invocation of a constructor in the same class from within a
/// constructor's initialization list.
///
/// redirectingConstructorInvocation ::=
/// 'this' ('.' identifier)? arguments
abstract final class RedirectingConstructorInvocation
implements ConstructorInitializer, ConstructorReferenceNode {
/// Return the list of arguments to the constructor.
ArgumentList get argumentList;
/// Return the name of the constructor that is being invoked, or `null` if the
/// unnamed constructor is being invoked.
SimpleIdentifier? get constructorName;
/// Return the token for the period before the name of the constructor that is
/// being invoked, or `null` if the unnamed constructor is being invoked.
Token? get period;
/// Return the token for the 'this' keyword.
Token get thisKeyword;
}
/// The invocation of a constructor in the same class from within a
/// constructor's initialization list.
///
/// redirectingConstructorInvocation ::=
/// 'this' ('.' identifier)? arguments
final class RedirectingConstructorInvocationImpl
extends ConstructorInitializerImpl
implements RedirectingConstructorInvocation {
/// The token for the 'this' keyword.
@override
final Token thisKeyword;
/// The token for the period before the name of the constructor that is being
/// invoked, or `null` if the unnamed constructor is being invoked.
@override
final Token? period;
/// The name of the constructor that is being invoked, or `null` if the
/// unnamed constructor is being invoked.
SimpleIdentifierImpl? _constructorName;
/// The list of arguments to the constructor.
ArgumentListImpl _argumentList;
/// The element associated with the constructor based on static type
/// information, or `null` if the AST structure has not been resolved or if
/// the constructor could not be resolved.
@override
ConstructorElement? staticElement;
/// Initialize a newly created redirecting invocation to invoke the
/// constructor with the given name with the given arguments. The
/// [constructorName] can be `null` if the constructor being invoked is the
/// unnamed constructor.
RedirectingConstructorInvocationImpl({
required this.thisKeyword,
required this.period,
required SimpleIdentifierImpl? constructorName,
required ArgumentListImpl argumentList,
}) : _constructorName = constructorName,
_argumentList = argumentList {
_becomeParentOf(_constructorName);
_becomeParentOf(_argumentList);
}
@override
ArgumentListImpl get argumentList => _argumentList;
set argumentList(ArgumentListImpl argumentList) {
_argumentList = _becomeParentOf(argumentList);
}
@override
Token get beginToken => thisKeyword;
@override
SimpleIdentifierImpl? get constructorName => _constructorName;
set constructorName(SimpleIdentifierImpl? identifier) {
_constructorName = _becomeParentOf(identifier);
}
@override
Token get endToken => _argumentList.endToken;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('thisKeyword', thisKeyword)
..addToken('period', period)
..addNode('constructorName', constructorName)
..addNode('argumentList', argumentList);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitRedirectingConstructorInvocation(this);
@override
void visitChildren(AstVisitor visitor) {
_constructorName?.accept(visitor);
_argumentList.accept(visitor);
}
}
/// A relational pattern.
///
/// relationalPattern ::=
/// (equalityOperator | relationalOperator) [Expression]
abstract final class RelationalPattern implements DartPattern {
/// The element of the [operator] for the matched type.
MethodElement? get element;
/// Return the expression used to compute the operand.
Expression get operand;
/// Return the relational operator being applied.
Token get operator;
}
/// A relational pattern.
///
/// relationalPattern ::=
/// (equalityOperator | relationalOperator) [Expression]
final class RelationalPatternImpl extends DartPatternImpl
implements RelationalPattern {
ExpressionImpl _operand;
@override
final Token operator;
@override
MethodElement? element;
RelationalPatternImpl({
required this.operator,
required ExpressionImpl operand,
}) : _operand = operand {
_becomeParentOf(operand);
}
@override
Token get beginToken => operator;
@override
Token get endToken => operand.endToken;
@override
ExpressionImpl get operand => _operand;
set operand(ExpressionImpl operand) {
_operand = _becomeParentOf(operand);
}
@override
PatternPrecedence get precedence => PatternPrecedence.relational;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('operator', operator)
..addNode('operand', operand);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitRelationalPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor.analyzeRelationalPatternSchema();
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
resolverVisitor.analyzeRelationalPattern(context, this, operand);
resolverVisitor.popRewrite();
}
@override
void visitChildren(AstVisitor visitor) {
operand.accept(visitor);
}
}
/// The name of the primary constructor of an extension type.
@experimental
abstract final class RepresentationConstructorName implements AstNode {
/// The name of the primary constructor.
Token get name;
/// The period separating [name] from the previous token.
Token get period;
}
final class RepresentationConstructorNameImpl extends AstNodeImpl
implements RepresentationConstructorName {
@override
final Token period;
@override
final Token name;
RepresentationConstructorNameImpl({
required this.period,
required this.name,
});
@override
Token get beginToken => period;
@override
Token get endToken => name;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('period', period)
..addToken('name', name);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitRepresentationConstructorName(this);
}
@override
void visitChildren(AstVisitor visitor) {}
}
/// The declaration an extension type representation.
///
/// It declares at the same time the representation field, and the primary
/// constructor.
///
/// <representationDeclaration> ::=
/// ('.' <identifierOrNew>)? '(' <metadata> <type> <identifier> ')'
@experimental
abstract final class RepresentationDeclaration implements AstNode {
/// The element of the primary constructor.
ConstructorElement? get constructorElement;
/// The optional name of the primary constructor.
RepresentationConstructorName? get constructorName;
/// The element for [fieldName] with [fieldType].
FieldElement? get fieldElement;
/// The annotations associated with the field.
NodeList<Annotation> get fieldMetadata;
/// The representation name.
Token get fieldName;
/// The representation type.
TypeAnnotation get fieldType;
/// The left parenthesis.
Token get leftParenthesis;
/// The right parenthesis.
Token get rightParenthesis;
}
final class RepresentationDeclarationImpl extends AstNodeImpl
implements RepresentationDeclaration {
@override
final RepresentationConstructorNameImpl? constructorName;
@override
ConstructorElementImpl? constructorElement;
@override
final Token leftParenthesis;
@override
final NodeListImpl<Annotation> fieldMetadata = NodeListImpl._();
@override
final TypeAnnotationImpl fieldType;
@override
final Token fieldName;
@override
FieldElementImpl? fieldElement;
@override
final Token rightParenthesis;
RepresentationDeclarationImpl({
required this.constructorName,
required this.leftParenthesis,
required List<AnnotationImpl> fieldMetadata,
required this.fieldType,
required this.fieldName,
required this.rightParenthesis,
}) {
this.fieldMetadata._initialize(this, fieldMetadata);
_becomeParentOf(constructorName);
_becomeParentOf(fieldType);
}
@override
Token get beginToken => constructorName?.beginToken ?? leftParenthesis;
@override
Token get endToken => rightParenthesis;
@override
ChildEntities get _childEntities => super._childEntities
..addNode('constructorName', constructorName)
..addToken('leftParenthesis', leftParenthesis)
..addNodeList('fieldMetadata', fieldMetadata)
..addNode('fieldType', fieldType)
..addToken('fieldName', fieldName)
..addToken('rightParenthesis', rightParenthesis);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitRepresentationDeclaration(this);
}
@override
void visitChildren(AstVisitor visitor) {
constructorName?.accept(visitor);
fieldMetadata.accept(visitor);
fieldType.accept(visitor);
}
}
/// A rest pattern element.
///
/// restPatternElement ::= '...' [DartPattern]?
abstract final class RestPatternElement
implements ListPatternElement, MapPatternElement {
/// The operator token '...'.
Token get operator;
/// The optional pattern.
DartPattern? get pattern;
}
final class RestPatternElementImpl extends AstNodeImpl
implements
RestPatternElement,
ListPatternElementImpl,
MapPatternElementImpl {
@override
final Token operator;
@override
final DartPatternImpl? pattern;
RestPatternElementImpl({
required this.operator,
required this.pattern,
}) {
_becomeParentOf(pattern);
}
@override
Token get beginToken => operator;
@override
Token get endToken => pattern?.endToken ?? operator;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('operator', operator)
..addNode('pattern', pattern);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitRestPatternElement(this);
}
@override
void visitChildren(AstVisitor visitor) {
pattern?.accept(visitor);
}
}
/// A rethrow expression.
///
/// rethrowExpression ::=
/// 'rethrow'
abstract final class RethrowExpression implements Expression {
/// Return the token representing the 'rethrow' keyword.
Token get rethrowKeyword;
}
/// A rethrow expression.
///
/// rethrowExpression ::=
/// 'rethrow'
final class RethrowExpressionImpl extends ExpressionImpl
implements RethrowExpression {
/// The token representing the 'rethrow' keyword.
@override
final Token rethrowKeyword;
/// Initialize a newly created rethrow expression.
RethrowExpressionImpl({
required this.rethrowKeyword,
});
@override
Token get beginToken => rethrowKeyword;
@override
Token get endToken => rethrowKeyword;
@override
Precedence get precedence => Precedence.assignment;
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('rethrowKeyword', rethrowKeyword);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitRethrowExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitRethrowExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
}
/// A return statement.
///
/// returnStatement ::=
/// 'return' [Expression]? ';'
abstract final class ReturnStatement implements Statement {
/// Return the expression computing the value to be returned, or `null` if no
/// explicit value was provided.
Expression? get expression;
/// Return the token representing the 'return' keyword.
Token get returnKeyword;
/// Return the semicolon terminating the statement.
Token get semicolon;
}
/// A return statement.
///
/// returnStatement ::=
/// 'return' [Expression]? ';'
final class ReturnStatementImpl extends StatementImpl
implements ReturnStatement {
/// The token representing the 'return' keyword.
@override
final Token returnKeyword;
/// The expression computing the value to be returned, or `null` if no
/// explicit value was provided.
ExpressionImpl? _expression;
/// The semicolon terminating the statement.
@override
final Token semicolon;
/// Initialize a newly created return statement. The [expression] can be
/// `null` if no explicit value was provided.
ReturnStatementImpl({
required this.returnKeyword,
required ExpressionImpl? expression,
required this.semicolon,
}) : _expression = expression {
_becomeParentOf(_expression);
}
@override
Token get beginToken => returnKeyword;
@override
Token get endToken => semicolon;
@override
ExpressionImpl? get expression => _expression;
set expression(ExpressionImpl? expression) {
_expression = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('returnKeyword', returnKeyword)
..addNode('expression', expression)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitReturnStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_expression?.accept(visitor);
}
}
/// A script tag that can optionally occur at the beginning of a compilation
/// unit.
///
/// scriptTag ::=
/// '#!' (~NEWLINE)* NEWLINE
abstract final class ScriptTag implements AstNode {
/// Return the token representing this script tag.
Token get scriptTag;
}
/// A script tag that can optionally occur at the beginning of a compilation
/// unit.
///
/// scriptTag ::=
/// '#!' (~NEWLINE)* NEWLINE
final class ScriptTagImpl extends AstNodeImpl implements ScriptTag {
/// The token representing this script tag.
@override
final Token scriptTag;
/// Initialize a newly created script tag.
ScriptTagImpl({
required this.scriptTag,
});
@override
Token get beginToken => scriptTag;
@override
Token get endToken => scriptTag;
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('scriptTag', scriptTag);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitScriptTag(this);
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
}
/// A set or map literal.
///
/// setOrMapLiteral ::=
/// 'const'? [TypeArgumentList]? '{' elements? '}'
///
/// elements ::=
/// [CollectionElement] ( ',' [CollectionElement] )* ','?
///
/// This is the class that is used to represent either a map or set literal when
/// either the 'control-flow-collections' or 'spread-collections' experiments
/// are enabled. If neither of those experiments are enabled, then `MapLiteral`
/// will be used to represent a map literal and `SetLiteral` will be used for
/// set literals.
abstract final class SetOrMapLiteral implements TypedLiteral {
/// Return the syntactic elements used to compute the elements of the set or
/// map.
NodeList<CollectionElement> get elements;
/// Return `true` if this literal represents a map literal.
///
/// This getter will always return `false` if [isSet] returns `true`.
///
/// However, this getter is _not_ the inverse of [isSet]. It is possible for
/// both getters to return `false` if
///
/// - the AST has not been resolved (because determining the kind of the
/// literal is done during resolution),
/// - the literal is ambiguous (contains one or more spread elements and none
/// of those elements can be used to determine the kind of the literal), or
/// - the literal is invalid because it contains both expressions (for sets)
/// and map entries (for maps).
///
/// In both of the latter two cases there will be compilation errors
/// associated with the literal.
bool get isMap;
/// Return `true` if this literal represents a set literal.
///
/// This getter will always return `false` if [isMap] returns `true`.
///
/// However, this getter is _not_ the inverse of [isMap]. It is possible for
/// both getters to return `false` if
///
/// - the AST has not been resolved (because determining the kind of the
/// literal is done during resolution),
/// - the literal is ambiguous (contains one or more spread elements and none
/// of those elements can be used to determine the kind of the literal), or
/// - the literal is invalid because it contains both expressions (for sets)
/// and map entries (for maps).
///
/// In both of the latter two cases there will be compilation errors
/// associated with the literal.
bool get isSet;
/// Return the left curly bracket.
Token get leftBracket;
/// Return the right curly bracket.
Token get rightBracket;
}
final class SetOrMapLiteralImpl extends TypedLiteralImpl
implements SetOrMapLiteral {
@override
final Token leftBracket;
/// The syntactic elements in the set.
final NodeListImpl<CollectionElementImpl> _elements = NodeListImpl._();
@override
final Token rightBracket;
/// A representation of whether this literal represents a map or a set, or
/// whether the kind has not or cannot be determined.
_SetOrMapKind _resolvedKind = _SetOrMapKind.unresolved;
/// The context type computed by
/// [ResolverVisitor._computeSetOrMapContextType].
///
/// Note that this is not the same as the context pushed down by type
/// inference (which can be obtained via [InferenceContext.getContext]). For
/// example, in the following code:
///
/// var m = {};
///
/// The context pushed down by type inference is null, whereas the
/// `contextType` is `Map<dynamic, dynamic>`.
InterfaceType? contextType;
/// Initialize a newly created set or map literal. The [constKeyword] can be
/// `null` if the literal is not a constant. The [typeArguments] can be `null`
/// if no type arguments were declared. The [elements] can be `null` if the
/// set is empty.
SetOrMapLiteralImpl({
required super.constKeyword,
required super.typeArguments,
required this.leftBracket,
required List<CollectionElementImpl> elements,
required this.rightBracket,
}) {
_elements._initialize(this, elements);
}
@override
Token get beginToken {
if (constKeyword case final constKeyword?) {
return constKeyword;
}
final typeArguments = this.typeArguments;
if (typeArguments != null) {
return typeArguments.beginToken;
}
return leftBracket;
}
@override
NodeListImpl<CollectionElementImpl> get elements => _elements;
@override
Token get endToken => rightBracket;
@override
bool get isMap => _resolvedKind == _SetOrMapKind.map;
@override
bool get isSet => _resolvedKind == _SetOrMapKind.set;
@override
// TODO(paulberry): add commas.
ChildEntities get _childEntities => super._childEntities
..addToken('leftBracket', leftBracket)
..addNodeList('elements', elements)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSetOrMapLiteral(this);
void becomeMap() {
assert(_resolvedKind == _SetOrMapKind.unresolved ||
_resolvedKind == _SetOrMapKind.map);
_resolvedKind = _SetOrMapKind.map;
}
void becomeSet() {
assert(_resolvedKind == _SetOrMapKind.unresolved ||
_resolvedKind == _SetOrMapKind.set);
_resolvedKind = _SetOrMapKind.set;
}
void becomeUnresolved() {
_resolvedKind = _SetOrMapKind.unresolved;
}
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitSetOrMapLiteral(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_elements.accept(visitor);
}
}
/// A combinator that restricts the names being imported to those in a given list.
///
/// showCombinator ::=
/// 'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
abstract final class ShowCombinator implements Combinator {
/// Return the list of names from the library that are made visible by this
/// combinator.
NodeList<SimpleIdentifier> get shownNames;
}
/// A combinator that restricts the names being imported to those in a given
/// list.
///
/// showCombinator ::=
/// 'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
final class ShowCombinatorImpl extends CombinatorImpl
implements ShowCombinator {
/// The list of names from the library that are made visible by this
/// combinator.
final NodeListImpl<SimpleIdentifierImpl> _shownNames = NodeListImpl._();
/// Initialize a newly created import show combinator.
ShowCombinatorImpl({
required super.keyword,
required List<SimpleIdentifierImpl> shownNames,
}) {
_shownNames._initialize(this, shownNames);
}
@override
Token get endToken => _shownNames.endToken!;
@override
NodeListImpl<SimpleIdentifierImpl> get shownNames => _shownNames;
@override
// TODO(paulberry): add commas.
ChildEntities get _childEntities => ChildEntities()
..addToken('keyword', keyword)
..addNodeList('shownNames', shownNames);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitShowCombinator(this);
@override
void visitChildren(AstVisitor visitor) {
_shownNames.accept(visitor);
}
}
/// A simple formal parameter.
///
/// simpleFormalParameter ::=
/// ('final' [TypeAnnotation] | 'var' | [TypeAnnotation])? [SimpleIdentifier]
abstract final class SimpleFormalParameter implements NormalFormalParameter {
/// Return the token representing either the 'final', 'const' or 'var'
/// keyword, or `null` if no keyword was used.
Token? get keyword;
/// Return the declared type of the parameter, or `null` if the parameter does
/// not have a declared type.
TypeAnnotation? get type;
}
/// A simple formal parameter.
///
/// simpleFormalParameter ::=
/// ('final' [NamedType] | 'var' | [NamedType])? [SimpleIdentifier]
final class SimpleFormalParameterImpl extends NormalFormalParameterImpl
implements SimpleFormalParameter {
/// The token representing either the 'final', 'const' or 'var' keyword, or
/// `null` if no keyword was used.
@override
final Token? keyword;
/// The name of the declared type of the parameter, or `null` if the parameter
/// does not have a declared type.
TypeAnnotationImpl? _type;
/// Initialize a newly created formal parameter. Either or both of the
/// [comment] and [metadata] can be `null` if the parameter does not have the
/// corresponding attribute. The [keyword] can be `null` if a type was
/// specified. The [type] must be `null` if the keyword is 'var'.
SimpleFormalParameterImpl({
required super.comment,
required super.metadata,
required super.covariantKeyword,
required super.requiredKeyword,
required this.keyword,
required TypeAnnotationImpl? type,
required super.name,
}) : _type = type {
_becomeParentOf(_type);
}
@override
Token get beginToken {
final metadata = this.metadata;
if (metadata.isNotEmpty) {
return metadata.beginToken!;
} else if (requiredKeyword case final requiredKeyword?) {
return requiredKeyword;
} else if (covariantKeyword case final covariantKeyword?) {
return covariantKeyword;
} else if (keyword case final keyword?) {
return keyword;
} else if (type case final type?) {
return type.beginToken;
}
return name!;
}
@override
Token get endToken => name ?? type!.endToken;
@override
bool get isConst => keyword?.keyword == Keyword.CONST;
@override
bool get isExplicitlyTyped => _type != null;
@override
bool get isFinal => keyword?.keyword == Keyword.FINAL;
@override
TypeAnnotationImpl? get type => _type;
set type(TypeAnnotationImpl? type) {
_type = _becomeParentOf(type);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('keyword', keyword)
..addNode('type', type)
..addToken('name', name);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitSimpleFormalParameter(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_type?.accept(visitor);
}
}
/// A simple identifier.
///
/// simpleIdentifier ::=
/// initialCharacter internalCharacter*
///
/// initialCharacter ::= '_' | '$' | letter
///
/// internalCharacter ::= '_' | '$' | letter | digit
abstract final class SimpleIdentifier implements Identifier {
/// Return `true` if this identifier is the "name" part of a prefixed
/// identifier or a method invocation.
bool get isQualified;
/// If the identifier is a tear-off, return the inferred type arguments
/// applied to the function type of the element to produce its `[staticType]`.
///
/// Return an empty list if the function type does not have type parameters.
///
/// Return an empty list if the context type has type parameters.
///
/// Return `null` if not a tear-off.
///
/// Return `null` if the AST structure has not been resolved.
List<DartType>? get tearOffTypeArgumentTypes;
/// Return the token representing the identifier.
Token get token;
/// Return `true` if this identifier is the name being declared in a
/// declaration.
// TODO(brianwilkerson): Convert this to a getter.
bool inDeclarationContext();
/// Return `true` if this expression is computing a right-hand value.
///
/// Note that [inGetterContext] and [inSetterContext] are not opposites, nor
/// are they mutually exclusive. In other words, it is possible for both
/// methods to return `true` when invoked on the same node.
// TODO(brianwilkerson): Convert this to a getter.
bool inGetterContext();
/// Return `true` if this expression is computing a left-hand value.
///
/// Note that [inGetterContext] and [inSetterContext] are not opposites, nor
/// are they mutually exclusive. In other words, it is possible for both
/// methods to return `true` when invoked on the same node.
// TODO(brianwilkerson): Convert this to a getter.
bool inSetterContext();
}
/// A simple identifier.
///
/// simpleIdentifier ::=
/// initialCharacter internalCharacter*
///
/// initialCharacter ::= '_' | '$' | letter
///
/// internalCharacter ::= '_' | '$' | letter | digit
final class SimpleIdentifierImpl extends IdentifierImpl
implements SimpleIdentifier {
/// The token representing the identifier.
@override
Token token;
/// The element associated with this identifier based on static type
/// information, or `null` if the AST structure has not been resolved or if
/// this identifier could not be resolved.
Element? _staticElement;
@override
List<DartType>? tearOffTypeArgumentTypes;
/// If this identifier is meant to be looked up in the enclosing scope, the
/// raw result the scope lookup, prior to figuring out whether a write or a
/// read context is intended, and prior to falling back on implicit `this` (if
/// appropriate).
///
/// `null` if this identifier is not meant to be looked up in the enclosing
/// scope.
ScopeLookupResult? scopeLookupResult;
/// Initialize a newly created identifier.
SimpleIdentifierImpl(this.token);
/// Return the cascade that contains this [SimpleIdentifier].
CascadeExpressionImpl? get ancestorCascade {
var operatorType = token.previous?.type;
if (operatorType == TokenType.PERIOD_PERIOD ||
operatorType == TokenType.QUESTION_PERIOD_PERIOD) {
return thisOrAncestorOfType<CascadeExpressionImpl>();
}
return null;
}
@override
Token get beginToken => token;
@override
Token get endToken => token;
@override
bool get isQualified {
final parent = this.parent!;
if (parent is PrefixedIdentifier) {
return identical(parent.identifier, this);
} else if (parent is PropertyAccess) {
return identical(parent.propertyName, this);
} else if (parent is ConstructorName) {
return identical(parent.name, this);
} else if (parent is MethodInvocation) {
MethodInvocation invocation = parent;
return identical(invocation.methodName, this) &&
invocation.realTarget != null;
}
return false;
}
@override
bool get isSynthetic => token.isSynthetic;
@override
String get name => token.lexeme;
@override
Precedence get precedence => Precedence.primary;
/// This element is set when this identifier is used not as an expression,
/// but just to reference some element.
///
/// Examples are the name of the type in a [NamedType], the name of the method
/// in a [MethodInvocation], the name of the constructor in a
/// [ConstructorName], the name of the property in a [PropertyAccess], the
/// prefix and the identifier in a [PrefixedIdentifier] (which then can be
/// used to read or write a value).
///
/// In invalid code, for recovery, any element could be used, e.g. a
/// setter as a type name `set mySetter(_) {} mySetter topVar;`. We do this
/// to help the user to navigate to this element, and maybe change its name,
/// add a new declaration, etc.
///
/// Return `null` if this identifier is used to either read or write a value,
/// or the AST structure has not been resolved, or if this identifier could
/// not be resolved.
///
/// If either [readElement] or [writeElement] are not `null`, the
/// [referenceElement] is `null`, because the identifier is being used to
/// read or write a value.
///
/// All three [readElement], [writeElement], and [referenceElement] can be
/// `null` when the AST structure has not been resolved, or this identifier
/// could not be resolved.
Element? get referenceElement => null;
@override
Element? get staticElement => _staticElement;
set staticElement(Element? element) {
_staticElement = element;
}
@override
ChildEntities get _childEntities => ChildEntities()..addToken('token', token);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSimpleIdentifier(this);
@override
bool inDeclarationContext() {
final parent = this.parent;
switch (parent) {
case ImportDirective():
return parent.prefix == this;
case Label():
final parent2 = parent.parent;
return parent2 is Statement || parent2 is SwitchMember;
}
return false;
}
@override
bool inGetterContext() {
// TODO(brianwilkerson): Convert this to a getter.
AstNode initialParent = this.parent!;
AstNode parent = initialParent;
AstNode target = this;
// skip prefix
if (initialParent is PrefixedIdentifier) {
if (identical(initialParent.prefix, this)) {
return true;
}
parent = initialParent.parent!;
target = initialParent;
} else if (initialParent is PropertyAccess) {
if (identical(initialParent.target, this)) {
return true;
}
parent = initialParent.parent!;
target = initialParent;
}
// skip label
if (parent is Label) {
return false;
}
// analyze usage
if (parent is AssignmentExpression) {
if (identical(parent.leftHandSide, target) &&
parent.operator.type == TokenType.EQ) {
return false;
}
}
if (parent is ConstructorFieldInitializer &&
identical(parent.fieldName, target)) {
return false;
}
if (parent is ForEachPartsWithIdentifier) {
if (identical(parent.identifier, target)) {
return false;
}
}
return true;
}
@override
bool inSetterContext() {
// TODO(brianwilkerson): Convert this to a getter.
AstNode initialParent = this.parent!;
AstNode parent = initialParent;
AstNode target = this;
// skip prefix
if (initialParent is PrefixedIdentifier) {
// if this is the prefix, then return false
if (identical(initialParent.prefix, this)) {
return false;
}
parent = initialParent.parent!;
target = initialParent;
} else if (initialParent is PropertyAccess) {
if (identical(initialParent.target, this)) {
return false;
}
parent = initialParent.parent!;
target = initialParent;
}
// analyze usage
if (parent is PrefixExpression) {
return parent.operator.type.isIncrementOperator;
} else if (parent is PostfixExpression) {
return parent.operator.type.isIncrementOperator;
} else if (parent is AssignmentExpression) {
return identical(parent.leftHandSide, target);
} else if (parent is ForEachPartsWithIdentifier) {
return identical(parent.identifier, target);
}
return false;
}
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitSimpleIdentifier(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
}
/// A string literal expression that does not contain any interpolations.
///
/// simpleStringLiteral ::=
/// rawStringLiteral
/// | basicStringLiteral
///
/// rawStringLiteral ::=
/// 'r' basicStringLiteral
///
/// basicStringLiteral ::=
/// multiLineStringLiteral
/// | singleLineStringLiteral
///
/// multiLineStringLiteral ::=
/// "'''" characters "'''"
/// | '"""' characters '"""'
///
/// singleLineStringLiteral ::=
/// "'" characters "'"
/// | '"' characters '"'
abstract final class SimpleStringLiteral implements SingleStringLiteral {
/// Return the token representing the literal.
Token get literal;
/// Return the value of the literal.
String get value;
}
/// A string literal expression that does not contain any interpolations.
///
/// simpleStringLiteral ::=
/// rawStringLiteral
/// | basicStringLiteral
///
/// rawStringLiteral ::=
/// 'r' basicStringLiteral
///
/// simpleStringLiteral ::=
/// multiLineStringLiteral
/// | singleLineStringLiteral
///
/// multiLineStringLiteral ::=
/// "'''" characters "'''"
/// | '"""' characters '"""'
///
/// singleLineStringLiteral ::=
/// "'" characters "'"
/// | '"' characters '"'
final class SimpleStringLiteralImpl extends SingleStringLiteralImpl
implements SimpleStringLiteral {
/// The token representing the literal.
@override
final Token literal;
/// The value of the literal.
@override
String value;
/// Initialize a newly created simple string literal.
SimpleStringLiteralImpl({
required this.literal,
required this.value,
});
@override
Token get beginToken => literal;
@override
int get contentsEnd => offset + _helper.end;
@override
int get contentsOffset => offset + _helper.start;
@override
Token get endToken => literal;
@override
bool get isMultiline => _helper.isMultiline;
@override
bool get isRaw => _helper.isRaw;
@override
bool get isSingleQuoted => _helper.isSingleQuoted;
@override
bool get isSynthetic => literal.isSynthetic;
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('literal', literal);
StringLexemeHelper get _helper {
return StringLexemeHelper(literal.lexeme, true, true);
}
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSimpleStringLiteral(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitSimpleStringLiteral(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
@override
void _appendStringValue(StringBuffer buffer) {
buffer.write(value);
}
}
/// A single string literal expression.
///
/// singleStringLiteral ::=
/// [SimpleStringLiteral]
/// | [StringInterpolation]
sealed class SingleStringLiteral implements StringLiteral {
/// Return the offset of the after-last contents character.
int get contentsEnd;
/// Return the offset of the first contents character.
///
/// If the string is multiline, then leading whitespaces are skipped.
int get contentsOffset;
/// Return `true` if this string literal is a multi-line string.
bool get isMultiline;
/// Return `true` if this string literal is a raw string.
bool get isRaw;
/// Return `true` if this string literal uses single quotes (' or '''), or
/// `false` if this string literal uses double quotes (" or """).
bool get isSingleQuoted;
}
/// A single string literal expression.
///
/// singleStringLiteral ::=
/// [SimpleStringLiteral]
/// | [StringInterpolation]
sealed class SingleStringLiteralImpl extends StringLiteralImpl
implements SingleStringLiteral {}
/// A spread element.
///
/// spreadElement:
/// ( '...' | '...?' ) [Expression]
abstract final class SpreadElement implements CollectionElement {
/// The expression used to compute the collection being spread.
Expression get expression;
/// Whether this is a null-aware spread, as opposed to a non-null spread.
bool get isNullAware;
/// The spread operator, either '...' or '...?'.
Token get spreadOperator;
}
final class SpreadElementImpl extends AstNodeImpl
implements CollectionElementImpl, SpreadElement {
@override
final Token spreadOperator;
ExpressionImpl _expression;
SpreadElementImpl({
required this.spreadOperator,
required ExpressionImpl expression,
}) : _expression = expression {
_becomeParentOf(_expression);
}
@override
Token get beginToken => spreadOperator;
@override
Token get endToken => _expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
bool get isNullAware =>
spreadOperator.type == TokenType.PERIOD_PERIOD_PERIOD_QUESTION;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('spreadOperator', spreadOperator)
..addNode('expression', expression);
@override
E? accept<E>(AstVisitor<E> visitor) {
return visitor.visitSpreadElement(this);
}
@override
void resolveElement(
ResolverVisitor resolver, CollectionLiteralContext? context) {
resolver.visitSpreadElement(this, context: context);
resolver.pushRewrite(null);
}
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
}
}
/// A node that represents a statement.
///
/// statement ::=
/// [Block]
/// | [VariableDeclarationStatement]
/// | [ForStatement]
/// | [ForEachStatement]
/// | [WhileStatement]
/// | [DoStatement]
/// | [SwitchStatement]
/// | [IfStatement]
/// | [TryStatement]
/// | [BreakStatement]
/// | [ContinueStatement]
/// | [ReturnStatement]
/// | [ExpressionStatement]
/// | [FunctionDeclarationStatement]
abstract final class Statement implements AstNode {
/// If this is a labeled statement, return the unlabeled portion of the
/// statement, otherwise return the statement itself.
Statement get unlabeled;
}
/// A node that represents a statement.
///
/// statement ::=
/// [Block]
/// | [VariableDeclarationStatement]
/// | [ForStatement]
/// | [ForEachStatement]
/// | [WhileStatement]
/// | [DoStatement]
/// | [SwitchStatement]
/// | [IfStatement]
/// | [TryStatement]
/// | [BreakStatement]
/// | [ContinueStatement]
/// | [ReturnStatement]
/// | [ExpressionStatement]
/// | [FunctionDeclarationStatement]
sealed class StatementImpl extends AstNodeImpl implements Statement {
@override
StatementImpl get unlabeled => this;
}
/// A string interpolation literal.
///
/// stringInterpolation ::=
/// ''' [InterpolationElement]* '''
/// | '"' [InterpolationElement]* '"'
abstract final class StringInterpolation implements SingleStringLiteral {
/// Return the elements that will be composed to produce the resulting string.
/// The list includes [firstString] and [lastString].
NodeList<InterpolationElement> get elements;
/// Return the first element in this interpolation, which is always a string.
/// The string might be empty if there is no text before the first
/// interpolation expression (such as in `'$foo bar'`).
InterpolationString get firstString;
/// Return the last element in this interpolation, which is always a string.
/// The string might be empty if there is no text after the last
/// interpolation expression (such as in `'foo $bar'`).
InterpolationString get lastString;
}
/// A string interpolation literal.
///
/// stringInterpolation ::=
/// ''' [InterpolationElement]* '''
/// | '"' [InterpolationElement]* '"'
final class StringInterpolationImpl extends SingleStringLiteralImpl
implements StringInterpolation {
/// The elements that will be composed to produce the resulting string.
final NodeListImpl<InterpolationElementImpl> _elements = NodeListImpl._();
/// Initialize a newly created string interpolation expression.
StringInterpolationImpl({
required List<InterpolationElementImpl> elements,
}) {
// TODO(scheglov): Replace asserts with appropriately typed parameters.
assert(elements.length > 2, 'Expected at last three elements.');
assert(
elements.first is InterpolationStringImpl,
'The first element must be a string.',
);
assert(
elements[1] is InterpolationExpressionImpl,
'The second element must be an expression.',
);
assert(
elements.last is InterpolationStringImpl,
'The last element must be a string.',
);
_elements._initialize(this, elements);
}
@override
Token get beginToken => _elements.beginToken!;
@override
int get contentsEnd {
var element = _elements.last as InterpolationString;
return element.contentsEnd;
}
@override
int get contentsOffset {
var element = _elements.first as InterpolationString;
return element.contentsOffset;
}
/// Return the elements that will be composed to produce the resulting string.
@override
NodeListImpl<InterpolationElementImpl> get elements => _elements;
@override
Token get endToken => _elements.endToken!;
@override
InterpolationStringImpl get firstString =>
elements.first as InterpolationStringImpl;
@override
bool get isMultiline => _firstHelper.isMultiline;
@override
bool get isRaw => false;
@override
bool get isSingleQuoted => _firstHelper.isSingleQuoted;
@override
InterpolationStringImpl get lastString =>
elements.last as InterpolationStringImpl;
@override
ChildEntities get _childEntities =>
ChildEntities()..addNodeList('elements', elements);
StringLexemeHelper get _firstHelper {
var lastString = _elements.first as InterpolationString;
String lexeme = lastString.contents.lexeme;
return StringLexemeHelper(lexeme, true, false);
}
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitStringInterpolation(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitStringInterpolation(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_elements.accept(visitor);
}
@override
void _appendStringValue(StringBuffer buffer) {
throw ArgumentError();
}
}
/// A helper for analyzing string lexemes.
class StringLexemeHelper {
final String lexeme;
final bool isFirst;
final bool isLast;
bool isRaw = false;
bool isSingleQuoted = false;
bool isMultiline = false;
int start = 0;
int end = 0;
StringLexemeHelper(this.lexeme, this.isFirst, this.isLast) {
if (isFirst) {
isRaw = lexeme.startsWith('r');
if (isRaw) {
start++;
}
if (lexeme.startsWith("'''", start)) {
isSingleQuoted = true;
isMultiline = true;
start += 3;
start = _trimInitialWhitespace(start);
} else if (lexeme.startsWith('"""', start)) {
isSingleQuoted = false;
isMultiline = true;
start += 3;
start = _trimInitialWhitespace(start);
} else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x27) {
isSingleQuoted = true;
isMultiline = false;
start++;
} else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x22) {
isSingleQuoted = false;
isMultiline = false;
start++;
}
}
end = lexeme.length;
if (isLast) {
if (start + 3 <= end &&
(lexeme.endsWith("'''") || lexeme.endsWith('"""'))) {
end -= 3;
} else if (start + 1 <= end &&
(lexeme.endsWith("'") || lexeme.endsWith('"'))) {
end -= 1;
}
}
}
/// Given the [lexeme] for a multi-line string whose content begins at the
/// given [start] index, return the index of the first character that is
/// included in the value of the string. According to the specification:
///
/// If the first line of a multiline string consists solely of the whitespace
/// characters defined by the production WHITESPACE 20.1), possibly prefixed
/// by \, then that line is ignored, including the new line at its end.
int _trimInitialWhitespace(int start) {
int length = lexeme.length;
int index = start;
while (index < length) {
int currentChar = lexeme.codeUnitAt(index);
if (currentChar == 0x0D) {
if (index + 1 < length && lexeme.codeUnitAt(index + 1) == 0x0A) {
return index + 2;
}
return index + 1;
} else if (currentChar == 0x0A) {
return index + 1;
} else if (currentChar == 0x5C) {
if (index + 1 >= length) {
return start;
}
currentChar = lexeme.codeUnitAt(index + 1);
if (currentChar != 0x0D &&
currentChar != 0x0A &&
currentChar != 0x09 &&
currentChar != 0x20) {
return start;
}
} else if (currentChar != 0x09 && currentChar != 0x20) {
return start;
}
index++;
}
return start;
}
}
/// A string literal expression.
///
/// stringLiteral ::=
/// [SimpleStringLiteral]
/// | [AdjacentStrings]
/// | [StringInterpolation]
sealed class StringLiteral implements Literal {
/// Return the value of the string literal, or `null` if the string is not a
/// constant string without any string interpolation.
String? get stringValue;
}
/// A string literal expression.
///
/// stringLiteral ::=
/// [SimpleStringLiteral]
/// | [AdjacentStrings]
/// | [StringInterpolation]
sealed class StringLiteralImpl extends LiteralImpl implements StringLiteral {
@override
String? get stringValue {
StringBuffer buffer = StringBuffer();
try {
_appendStringValue(buffer);
} on ArgumentError {
return null;
}
return buffer.toString();
}
/// Append the value of this string literal to the given [buffer]. Throw an
/// [ArgumentError] if the string is not a constant string without any
/// string interpolation.
void _appendStringValue(StringBuffer buffer);
}
/// The invocation of a superclass' constructor from within a constructor's
/// initialization list.
///
/// superInvocation ::=
/// 'super' ('.' [SimpleIdentifier])? [ArgumentList]
abstract final class SuperConstructorInvocation
implements ConstructorInitializer, ConstructorReferenceNode {
/// Return the list of arguments to the constructor.
ArgumentList get argumentList;
/// Return the name of the constructor that is being invoked, or `null` if the
/// unnamed constructor is being invoked.
SimpleIdentifier? get constructorName;
/// Return the token for the period before the name of the constructor that is
/// being invoked, or `null` if the unnamed constructor is being invoked.
Token? get period;
/// Return the token for the 'super' keyword.
Token get superKeyword;
}
/// The invocation of a superclass' constructor from within a constructor's
/// initialization list.
///
/// superInvocation ::=
/// 'super' ('.' [SimpleIdentifier])? [ArgumentList]
final class SuperConstructorInvocationImpl extends ConstructorInitializerImpl
implements SuperConstructorInvocation {
/// The token for the 'super' keyword.
@override
final Token superKeyword;
/// The token for the period before the name of the constructor that is being
/// invoked, or `null` if the unnamed constructor is being invoked.
@override
final Token? period;
/// The name of the constructor that is being invoked, or `null` if the
/// unnamed constructor is being invoked.
SimpleIdentifierImpl? _constructorName;
/// The list of arguments to the constructor.
ArgumentListImpl _argumentList;
/// The element associated with the constructor based on static type
/// information, or `null` if the AST structure has not been resolved or if
/// the constructor could not be resolved.
@override
ConstructorElement? staticElement;
/// Initialize a newly created super invocation to invoke the inherited
/// constructor with the given name with the given arguments. The [period] and
/// [constructorName] can be `null` if the constructor being invoked is the
/// unnamed constructor.
SuperConstructorInvocationImpl({
required this.superKeyword,
required this.period,
required SimpleIdentifierImpl? constructorName,
required ArgumentListImpl argumentList,
}) : _constructorName = constructorName,
_argumentList = argumentList {
_becomeParentOf(_constructorName);
_becomeParentOf(_argumentList);
}
@override
ArgumentListImpl get argumentList => _argumentList;
set argumentList(ArgumentListImpl argumentList) {
_argumentList = _becomeParentOf(argumentList);
}
@override
Token get beginToken => superKeyword;
@override
SimpleIdentifierImpl? get constructorName => _constructorName;
set constructorName(SimpleIdentifierImpl? identifier) {
_constructorName = _becomeParentOf(identifier);
}
@override
Token get endToken => _argumentList.endToken;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('superKeyword', superKeyword)
..addToken('period', period)
..addNode('constructorName', constructorName)
..addNode('argumentList', argumentList);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitSuperConstructorInvocation(this);
@override
void visitChildren(AstVisitor visitor) {
_constructorName?.accept(visitor);
_argumentList.accept(visitor);
}
}
/// A super expression.
///
/// superExpression ::=
/// 'super'
abstract final class SuperExpression implements Expression {
/// Return the token representing the 'super' keyword.
Token get superKeyword;
}
/// A super expression.
///
/// superExpression ::=
/// 'super'
final class SuperExpressionImpl extends ExpressionImpl
implements SuperExpression {
/// The token representing the 'super' keyword.
@override
final Token superKeyword;
/// Initialize a newly created super expression.
SuperExpressionImpl({
required this.superKeyword,
});
@override
Token get beginToken => superKeyword;
@override
Token get endToken => superKeyword;
@override
Precedence get precedence => Precedence.primary;
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('superKeyword', superKeyword);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSuperExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitSuperExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
}
/// A super-initializer formal parameter.
///
/// superFormalParameter ::=
/// ('final' [TypeAnnotation] | 'const' [TypeAnnotation] | 'var' | [TypeAnnotation])?
/// 'super' '.' name ([TypeParameterList]? [FormalParameterList])?
abstract final class SuperFormalParameter implements NormalFormalParameter {
/// Return the token representing either the 'final', 'const' or 'var'
/// keyword, or `null` if no keyword was used.
Token? get keyword;
@override
Token get name;
/// Return the parameters of the function-typed parameter, or `null` if this
/// is not a function-typed field formal parameter.
FormalParameterList? get parameters;
/// Return the token representing the period.
Token get period;
/// If the parameter is function-typed, and has the question mark, then its
/// function type is nullable. Having a nullable function type means that the
/// parameter can be null.
Token? get question;
/// Return the token representing the 'super' keyword.
Token get superKeyword;
/// Return the declared type of the parameter, or `null` if the parameter does
/// not have a declared type.
///
/// Note that if this is a function-typed field formal parameter this is the
/// return type of the function.
TypeAnnotation? get type;
/// Return the type parameters associated with this method, or `null` if this
/// method is not a generic method.
TypeParameterList? get typeParameters;
}
/// A super-initializer formal parameter.
///
/// fieldFormalParameter ::=
/// ('final' [NamedType] | 'const' [NamedType] | 'var' | [NamedType])?
/// 'super' '.' [SimpleIdentifier]
/// ([TypeParameterList]? [FormalParameterList])?
final class SuperFormalParameterImpl extends NormalFormalParameterImpl
implements SuperFormalParameter {
/// The token representing either the 'final', 'const' or 'var' keyword, or
/// `null` if no keyword was used.
@override
final Token? keyword;
/// The name of the declared type of the parameter, or `null` if the parameter
/// does not have a declared type.
TypeAnnotationImpl? _type;
/// The token representing the 'super' keyword.
@override
final Token superKeyword;
/// The token representing the period.
@override
final Token period;
/// The type parameters associated with the method, or `null` if the method is
/// not a generic method.
TypeParameterListImpl? _typeParameters;
/// The parameters of the function-typed parameter, or `null` if this is not a
/// function-typed field formal parameter.
FormalParameterListImpl? _parameters;
@override
final Token? question;
/// Initialize a newly created formal parameter. Either or both of the
/// [comment] and [metadata] can be `null` if the parameter does not have the
/// corresponding attribute. The [keyword] can be `null` if there is a type.
/// The [type] must be `null` if the keyword is 'var'. The [thisKeyword] and
/// [period] can be `null` if the keyword 'this' was not provided. The
/// [parameters] can be `null` if this is not a function-typed field formal
/// parameter.
SuperFormalParameterImpl({
required super.comment,
required super.metadata,
required super.covariantKeyword,
required super.requiredKeyword,
required this.keyword,
required TypeAnnotationImpl? type,
required this.superKeyword,
required this.period,
required super.name,
required TypeParameterListImpl? typeParameters,
required FormalParameterListImpl? parameters,
required this.question,
}) : _type = type,
_typeParameters = typeParameters,
_parameters = parameters {
_becomeParentOf(_type);
_becomeParentOf(_typeParameters);
_becomeParentOf(_parameters);
}
@override
Token get beginToken {
final metadata = this.metadata;
if (metadata.isNotEmpty) {
return metadata.beginToken!;
} else if (requiredKeyword case final requiredKeyword?) {
return requiredKeyword;
} else if (covariantKeyword case final covariantKeyword?) {
return covariantKeyword;
} else if (keyword case final keyword?) {
return keyword;
} else if (type case final type?) {
return type.beginToken;
}
return superKeyword;
}
@override
Token get endToken {
return question ?? _parameters?.endToken ?? name;
}
@override
bool get isConst => keyword?.keyword == Keyword.CONST;
@override
bool get isExplicitlyTyped => _parameters != null || _type != null;
@override
bool get isFinal => keyword?.keyword == Keyword.FINAL;
@override
Token get name => super.name!;
@override
FormalParameterListImpl? get parameters => _parameters;
set parameters(FormalParameterListImpl? parameters) {
_parameters = _becomeParentOf(parameters);
}
@override
TypeAnnotationImpl? get type => _type;
set type(TypeAnnotationImpl? type) {
_type = _becomeParentOf(type as TypeAnnotationImpl);
}
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
set typeParameters(TypeParameterListImpl? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('keyword', keyword)
..addNode('type', type)
..addToken('superKeyword', superKeyword)
..addToken('period', period)
..addToken('name', name)
..addNode('typeParameters', typeParameters)
..addNode('parameters', parameters);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitSuperFormalParameter(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_type?.accept(visitor);
_typeParameters?.accept(visitor);
_parameters?.accept(visitor);
}
}
/// A case in a switch statement.
///
/// switchCase ::=
/// [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
abstract final class SwitchCase implements SwitchMember {
/// Return the expression controlling whether the statements will be executed.
Expression get expression;
}
/// A case in a switch statement.
///
/// switchCase ::=
/// [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
final class SwitchCaseImpl extends SwitchMemberImpl implements SwitchCase {
/// The expression controlling whether the statements will be executed.
ExpressionImpl _expression;
/// Initialize a newly created switch case. The list of [labels] can be `null`
/// if there are no labels.
SwitchCaseImpl({
required super.labels,
required super.keyword,
required ExpressionImpl expression,
required super.colon,
required super.statements,
}) : _expression = expression {
_becomeParentOf(_expression);
}
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNodeList('labels', labels)
..addToken('keyword', keyword)
..addNode('expression', expression)
..addToken('colon', colon)
..addNodeList('statements', statements);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSwitchCase(this);
@override
void visitChildren(AstVisitor visitor) {
labels.accept(visitor);
_expression.accept(visitor);
statements.accept(visitor);
}
}
/// The default case in a switch statement.
///
/// switchDefault ::=
/// [SimpleIdentifier]* 'default' ':' [Statement]*
abstract final class SwitchDefault implements SwitchMember {}
/// The default case in a switch statement.
///
/// switchDefault ::=
/// [SimpleIdentifier]* 'default' ':' [Statement]*
final class SwitchDefaultImpl extends SwitchMemberImpl
implements SwitchDefault {
/// Initialize a newly created switch default. The list of [labels] can be
/// `null` if there are no labels.
SwitchDefaultImpl({
required super.labels,
required super.keyword,
required super.colon,
required super.statements,
});
@override
ChildEntities get _childEntities => ChildEntities()
..addNodeList('labels', labels)
..addToken('keyword', keyword)
..addToken('colon', colon)
..addNodeList('statements', statements);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSwitchDefault(this);
@override
void visitChildren(AstVisitor visitor) {
labels.accept(visitor);
statements.accept(visitor);
}
}
/// A switch expression.
///
/// switchExpression ::=
/// 'switch' '(' [Expression] ')' '{' [SwitchExpressionCase]
/// (',' [SwitchExpressionCase])* ','? '}'
abstract final class SwitchExpression implements Expression {
/// Return the cases that can be selected by the expression.
NodeList<SwitchExpressionCase> get cases;
/// Return the expression used to determine which of the switch cases will
/// be selected.
Expression get expression;
/// Return the left curly bracket.
Token get leftBracket;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right curly bracket.
Token get rightBracket;
/// Return the right parenthesis.
Token get rightParenthesis;
/// Return the token representing the 'switch' keyword.
Token get switchKeyword;
}
/// A case in a switch expression.
///
/// switchExpressionCase ::=
/// [GuardedPattern] '=>' [Expression]
abstract final class SwitchExpressionCase implements AstNode {
/// Return the arrow separating the pattern from the expression.
Token get arrow;
/// Return the expression whose value will be returned from the switch
/// expression if the pattern matches.
Expression get expression;
/// Return the refutable pattern that must match for the [expression] to
/// be executed.
GuardedPattern get guardedPattern;
}
/// A case in a switch expression.
///
/// switchExpressionCase ::=
/// [GuardedPattern] '=>' [Expression]
final class SwitchExpressionCaseImpl extends AstNodeImpl
implements SwitchExpressionCase {
@override
final GuardedPatternImpl guardedPattern;
@override
final Token arrow;
ExpressionImpl _expression;
SwitchExpressionCaseImpl({
required this.guardedPattern,
required this.arrow,
required ExpressionImpl expression,
}) : _expression = expression {
_becomeParentOf(guardedPattern);
_becomeParentOf(_expression);
}
@override
Token get beginToken => guardedPattern.beginToken;
@override
Token get endToken => expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => super._childEntities
..addNode('guardedPattern', guardedPattern)
..addToken('arrow', arrow)
..addNode('expression', expression);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitSwitchExpressionCase(this);
@override
void visitChildren(AstVisitor visitor) {
guardedPattern.accept(visitor);
expression.accept(visitor);
}
}
/// A switch expression.
///
/// switchExpression ::=
/// 'switch' '(' [Expression] ')' '{' [SwitchExpressionCase]
/// (',' [SwitchExpressionCase])* ','? '}'
final class SwitchExpressionImpl extends ExpressionImpl
implements SwitchExpression {
@override
final Token switchKeyword;
@override
final Token leftParenthesis;
ExpressionImpl _expression;
@override
final Token rightParenthesis;
@override
final Token leftBracket;
@override
final NodeListImpl<SwitchExpressionCaseImpl> cases = NodeListImpl._();
@override
final Token rightBracket;
SwitchExpressionImpl({
required this.switchKeyword,
required this.leftParenthesis,
required ExpressionImpl expression,
required this.rightParenthesis,
required this.leftBracket,
required List<SwitchExpressionCaseImpl> cases,
required this.rightBracket,
}) : _expression = expression {
_becomeParentOf(_expression);
this.cases._initialize(this, cases);
}
@override
Token get beginToken => switchKeyword;
@override
Token get endToken => rightBracket;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
Precedence get precedence => Precedence.primary;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('switchKeyword', switchKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('expression', expression)
..addToken('rightParenthesis', rightParenthesis)
..addToken('leftBracket', leftBracket)
..addNodeList('cases', cases)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSwitchExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
var previousExhaustiveness = resolver.legacySwitchExhaustiveness;
staticType = resolver
.analyzeSwitchExpression(this, expression, cases.length, contextType)
.type;
resolver.popRewrite();
resolver.legacySwitchExhaustiveness = previousExhaustiveness;
}
@override
void visitChildren(AstVisitor visitor) {
expression.accept(visitor);
cases.accept(visitor);
}
}
/// An element within a switch statement.
///
/// switchMember ::=
/// [SwitchCase]
/// | [SwitchDefault]
/// | [SwitchPatternCase]
///
/// The class [SwitchPatternCase] exists only to support the 'patterns' feature.
///
/// Note that when the patterns feature is enabled by default, the class
/// [SwitchPatternCase] might replace [SwitchCase] entirely. If we do that, then
/// legacy code (code opted into a version prior to the release of patterns)
/// will likely wrap the expression in a [ConstantPattern] with synthetic
/// tokens.
// TODO(brianwilkerson): Consider renaming `SwitchMember`, `SwitchCase`, and
// `SwitchDefault` to start with `SwitchStatement` for consistency.
sealed class SwitchMember implements AstNode {
/// Return the colon separating the keyword or the expression from the
/// statements.
Token get colon;
/// Return the token representing the 'case' or 'default' keyword.
Token get keyword;
/// Return the labels associated with the switch member.
NodeList<Label> get labels;
/// Return the statements that will be executed if this switch member is
/// selected.
NodeList<Statement> get statements;
}
/// An element within a switch statement.
///
/// switchMember ::=
/// switchCase
/// | switchDefault
sealed class SwitchMemberImpl extends AstNodeImpl implements SwitchMember {
/// The labels associated with the switch member.
final NodeListImpl<LabelImpl> _labels = NodeListImpl._();
/// The token representing the 'case' or 'default' keyword.
@override
final Token keyword;
/// The colon separating the keyword or the expression from the statements.
@override
final Token colon;
/// The statements that will be executed if this switch member is selected.
final NodeListImpl<StatementImpl> _statements = NodeListImpl._();
/// Initialize a newly created switch member. The list of [labels] can be
/// `null` if there are no labels.
SwitchMemberImpl({
required List<LabelImpl> labels,
required this.keyword,
required this.colon,
required List<StatementImpl> statements,
}) {
_labels._initialize(this, labels);
_statements._initialize(this, statements);
}
@override
Token get beginToken {
if (_labels.isNotEmpty) {
return _labels.beginToken!;
}
return keyword;
}
@override
Token get endToken {
if (_statements.isNotEmpty) {
return _statements.endToken!;
}
return colon;
}
@override
NodeListImpl<LabelImpl> get labels => _labels;
@override
NodeListImpl<StatementImpl> get statements => _statements;
}
/// A pattern-based case in a switch statement.
///
/// switchPatternCase ::=
/// [Label]* 'case' [DartPattern] [WhenClause]? ':' [Statement]*
abstract final class SwitchPatternCase implements SwitchMember {
/// Return the pattern controlling whether the statements will be executed.
GuardedPattern get guardedPattern;
}
/// A pattern-based case in a switch statement.
///
/// switchPatternCase ::=
/// [Label]* 'case' [DartPattern] [WhenClause]? ':' [Statement]*
final class SwitchPatternCaseImpl extends SwitchMemberImpl
implements SwitchPatternCase {
@override
final GuardedPatternImpl guardedPattern;
SwitchPatternCaseImpl({
required super.labels,
required super.keyword,
required this.guardedPattern,
required super.colon,
required super.statements,
}) {
_becomeParentOf(guardedPattern);
}
@override
ChildEntities get _childEntities => super._childEntities
..addNodeList('labels', labels)
..addToken('keyword', keyword)
..addNode('guardedPattern', guardedPattern)
..addToken('colon', colon)
..addNodeList('statements', statements);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSwitchPatternCase(this);
@override
void visitChildren(AstVisitor visitor) {
labels.accept(visitor);
guardedPattern.accept(visitor);
statements.accept(visitor);
}
}
/// A switch statement.
///
/// switchStatement ::=
/// 'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
abstract final class SwitchStatement implements Statement {
/// Return the expression used to determine which of the switch members will
/// be selected.
Expression get expression;
/// Return the left curly bracket.
Token get leftBracket;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the switch members that can be selected by the expression.
NodeList<SwitchMember> get members;
/// Return the right curly bracket.
Token get rightBracket;
/// Return the right parenthesis.
Token get rightParenthesis;
/// Return the token representing the 'switch' keyword.
Token get switchKeyword;
}
class SwitchStatementCaseGroup {
final List<SwitchMemberImpl> members;
final bool hasLabels;
/// Joined variables declared in [members], available in [statements].
late Map<String, PromotableElement> variables;
SwitchStatementCaseGroup(this.members, this.hasLabels);
NodeListImpl<StatementImpl> get statements {
return members.last.statements;
}
}
/// A switch statement.
///
/// switchStatement ::=
/// 'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
final class SwitchStatementImpl extends StatementImpl
implements SwitchStatement {
/// The token representing the 'switch' keyword.
@override
final Token switchKeyword;
/// The left parenthesis.
@override
final Token leftParenthesis;
/// The expression used to determine which of the switch members will be
/// selected.
ExpressionImpl _expression;
/// The right parenthesis.
@override
final Token rightParenthesis;
/// The left curly bracket.
@override
final Token leftBracket;
/// The switch members that can be selected by the expression.
final NodeListImpl<SwitchMemberImpl> _members = NodeListImpl._();
late final List<SwitchStatementCaseGroup> memberGroups =
_computeMemberGroups();
/// The right curly bracket.
@override
final Token rightBracket;
/// Initialize a newly created switch statement. The list of [members] can be
/// `null` if there are no switch members.
SwitchStatementImpl({
required this.switchKeyword,
required this.leftParenthesis,
required ExpressionImpl expression,
required this.rightParenthesis,
required this.leftBracket,
required List<SwitchMemberImpl> members,
required this.rightBracket,
}) : _expression = expression {
_becomeParentOf(_expression);
_members._initialize(this, members);
}
@override
Token get beginToken => switchKeyword;
@override
Token get endToken => rightBracket;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
NodeListImpl<SwitchMemberImpl> get members => _members;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('switchKeyword', switchKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('expression', expression)
..addToken('rightParenthesis', rightParenthesis)
..addToken('leftBracket', leftBracket)
..addNodeList('members', members)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSwitchStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
_members.accept(visitor);
}
List<SwitchStatementCaseGroup> _computeMemberGroups() {
var groups = <SwitchStatementCaseGroup>[];
var groupMembers = <SwitchMemberImpl>[];
var groupHasLabels = false;
for (var member in members) {
groupMembers.add(member);
groupHasLabels |= member.labels.isNotEmpty;
if (member.statements.isNotEmpty) {
groups.add(
SwitchStatementCaseGroup(groupMembers, groupHasLabels),
);
groupMembers = [];
groupHasLabels = false;
}
}
if (groupMembers.isNotEmpty) {
groups.add(
SwitchStatementCaseGroup(groupMembers, groupHasLabels),
);
}
return groups;
}
}
/// A symbol literal expression.
///
/// symbolLiteral ::=
/// '#' (operator | (identifier ('.' identifier)*))
abstract final class SymbolLiteral implements Literal {
/// Return the components of the literal.
List<Token> get components;
/// Return the token introducing the literal.
Token get poundSign;
}
/// A symbol literal expression.
///
/// symbolLiteral ::=
/// '#' (operator | (identifier ('.' identifier)*))
final class SymbolLiteralImpl extends LiteralImpl implements SymbolLiteral {
/// The token introducing the literal.
@override
final Token poundSign;
/// The components of the literal.
@override
final List<Token> components;
/// Initialize a newly created symbol literal.
SymbolLiteralImpl({
required this.poundSign,
required this.components,
});
@override
Token get beginToken => poundSign;
@override
Token get endToken => components[components.length - 1];
@override
// TODO(paulberry): add "." tokens.
ChildEntities get _childEntities => ChildEntities()
..addToken('poundSign', poundSign)
..addTokenList('components', components);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitSymbolLiteral(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitSymbolLiteral(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
}
/// An identifier that can be used to look up names in the lexical scope when
/// there is no identifier in the AST structure. There is no identifier in the
/// AST when the parser could not distinguish between a method invocation and an
/// invocation of a top-level function imported with a prefix.
final class SyntheticIdentifier implements SimpleIdentifier {
@override
final String name;
SyntheticIdentifier(this.name);
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
/// A this expression.
///
/// thisExpression ::=
/// 'this'
abstract final class ThisExpression implements Expression {
/// Return the token representing the 'this' keyword.
Token get thisKeyword;
}
/// A this expression.
///
/// thisExpression ::=
/// 'this'
final class ThisExpressionImpl extends ExpressionImpl
implements ThisExpression {
/// The token representing the 'this' keyword.
@override
final Token thisKeyword;
/// Initialize a newly created this expression.
ThisExpressionImpl({
required this.thisKeyword,
});
@override
Token get beginToken => thisKeyword;
@override
Token get endToken => thisKeyword;
@override
Precedence get precedence => Precedence.primary;
@override
ChildEntities get _childEntities =>
ChildEntities()..addToken('thisKeyword', thisKeyword);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitThisExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitThisExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
// There are no children to visit.
}
}
/// A throw expression.
///
/// throwExpression ::=
/// 'throw' [Expression]
abstract final class ThrowExpression implements Expression {
/// Return the expression computing the exception to be thrown.
Expression get expression;
/// Return the token representing the 'throw' keyword.
Token get throwKeyword;
}
/// A throw expression.
///
/// throwExpression ::=
/// 'throw' [Expression]
final class ThrowExpressionImpl extends ExpressionImpl
implements ThrowExpression {
/// The token representing the 'throw' keyword.
@override
final Token throwKeyword;
/// The expression computing the exception to be thrown.
ExpressionImpl _expression;
/// Initialize a newly created throw expression.
ThrowExpressionImpl({
required this.throwKeyword,
required ExpressionImpl expression,
}) : _expression = expression {
_becomeParentOf(_expression);
}
@override
Token get beginToken => throwKeyword;
@override
Token get endToken {
return _expression.endToken;
}
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
Precedence get precedence => Precedence.assignment;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('throwKeyword', throwKeyword)
..addNode('expression', expression);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitThrowExpression(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitThrowExpression(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
}
}
/// The declaration of one or more top-level variables of the same type.
///
/// topLevelVariableDeclaration ::=
/// ('final' | 'const') <type>? <staticFinalDeclarationList> ';'
/// | 'late' 'final' <type>? <initializedIdentifierList> ';'
/// | 'late'? <varOrType> <initializedIdentifierList> ';'
/// | 'external' <finalVarOrType> <identifierList> ';'
///
/// (Note: there is no <topLevelVariableDeclaration> production in the grammar;
/// this is a subset of the grammar production <topLevelDeclaration>, which
/// encompasses everything that can appear inside a Dart file after part
/// directives).
abstract final class TopLevelVariableDeclaration
implements CompilationUnitMember {
/// The `external` keyword, or `null` if the keyword was not used.
Token? get externalKeyword;
/// Return the semicolon terminating the declaration.
Token get semicolon;
/// Return the top-level variables being declared.
VariableDeclarationList get variables;
}
/// The declaration of one or more top-level variables of the same type.
///
/// topLevelVariableDeclaration ::=
/// ('final' | 'const') type? staticFinalDeclarationList ';'
/// | variableDeclaration ';'
final class TopLevelVariableDeclarationImpl extends CompilationUnitMemberImpl
implements TopLevelVariableDeclaration {
/// The top-level variables being declared.
VariableDeclarationListImpl _variableList;
@override
final Token? externalKeyword;
/// The semicolon terminating the declaration.
@override
final Token semicolon;
/// Initialize a newly created top-level variable declaration. Either or both
/// of the [comment] and [metadata] can be `null` if the variable does not
/// have the corresponding attribute.
TopLevelVariableDeclarationImpl({
required super.comment,
required super.metadata,
required this.externalKeyword,
required VariableDeclarationListImpl variableList,
required this.semicolon,
}) : _variableList = variableList {
_becomeParentOf(_variableList);
}
@override
Element? get declaredElement => null;
@override
Token get endToken => semicolon;
@override
Token get firstTokenAfterCommentAndMetadata =>
externalKeyword ?? _variableList.beginToken;
@override
VariableDeclarationListImpl get variables => _variableList;
set variables(VariableDeclarationListImpl variables) {
_variableList = _becomeParentOf(variables);
}
@override
ChildEntities get _childEntities => super._childEntities
..addNode('variables', variables)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitTopLevelVariableDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_variableList.accept(visitor);
}
}
/// A try statement.
///
/// tryStatement ::=
/// 'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
///
/// finallyClause ::=
/// 'finally' [Block]
abstract final class TryStatement implements Statement {
/// Return the body of the statement.
Block get body;
/// Return the catch clauses contained in the try statement.
NodeList<CatchClause> get catchClauses;
/// Return the finally block contained in the try statement, or `null` if the
/// statement does not contain a finally clause.
Block? get finallyBlock;
/// Return the token representing the 'finally' keyword, or `null` if the
/// statement does not contain a finally clause.
Token? get finallyKeyword;
/// Return the token representing the 'try' keyword.
Token get tryKeyword;
}
/// A try statement.
///
/// tryStatement ::=
/// 'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
///
/// finallyClause ::=
/// 'finally' [Block]
final class TryStatementImpl extends StatementImpl implements TryStatement {
/// The token representing the 'try' keyword.
@override
final Token tryKeyword;
/// The body of the statement.
BlockImpl _body;
/// The catch clauses contained in the try statement.
final NodeListImpl<CatchClauseImpl> _catchClauses = NodeListImpl._();
/// The token representing the 'finally' keyword, or `null` if the statement
/// does not contain a finally clause.
@override
final Token? finallyKeyword;
/// The finally block contained in the try statement, or `null` if the
/// statement does not contain a finally clause.
BlockImpl? _finallyBlock;
/// Initialize a newly created try statement. The list of [catchClauses] can
/// be`null` if there are no catch clauses. The [finallyKeyword] and
/// [finallyBlock] can be `null` if there is no finally clause.
TryStatementImpl({
required this.tryKeyword,
required BlockImpl body,
required List<CatchClauseImpl> catchClauses,
required this.finallyKeyword,
required BlockImpl? finallyBlock,
}) : _body = body,
_finallyBlock = finallyBlock {
_becomeParentOf(_body);
_catchClauses._initialize(this, catchClauses);
_becomeParentOf(_finallyBlock);
}
@override
Token get beginToken => tryKeyword;
@override
BlockImpl get body => _body;
set body(BlockImpl block) {
_body = _becomeParentOf(block);
}
@override
NodeListImpl<CatchClauseImpl> get catchClauses => _catchClauses;
@override
Token get endToken {
if (finallyBlock case final finallyBlock?) {
return finallyBlock.endToken;
} else if (finallyKeyword case final finallyKeyword?) {
return finallyKeyword;
} else if (_catchClauses case [..., final last]) {
return last.endToken;
}
return _body.endToken;
}
@override
BlockImpl? get finallyBlock => _finallyBlock;
set finallyBlock(BlockImpl? block) {
_finallyBlock = _becomeParentOf(block);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('tryKeyword', tryKeyword)
..addNode('body', body)
..addNodeList('catchClauses', catchClauses)
..addToken('finallyKeyword', finallyKeyword)
..addNode('finallyBlock', finallyBlock);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitTryStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_body.accept(visitor);
_catchClauses.accept(visitor);
_finallyBlock?.accept(visitor);
}
}
/// The declaration of a type alias.
///
/// typeAlias ::=
/// [ClassTypeAlias]
/// | [FunctionTypeAlias]
/// | [GenericTypeAlias]
abstract final class TypeAlias implements NamedCompilationUnitMember {
/// Return the semicolon terminating the declaration.
Token get semicolon;
/// Return the token representing the 'typedef' or 'class' keyword.
Token get typedefKeyword;
}
/// The declaration of a type alias.
///
/// typeAlias ::=
/// [ClassTypeAlias]
/// | [FunctionTypeAlias]
/// | [GenericTypeAlias]
sealed class TypeAliasImpl extends NamedCompilationUnitMemberImpl
implements TypeAlias {
/// The token representing the 'typedef' or 'class' keyword.
@override
final Token typedefKeyword;
/// The semicolon terminating the declaration.
@override
final Token semicolon;
/// Initialize a newly created type alias. Either or both of the [comment] and
/// [metadata] can be `null` if the declaration does not have the
/// corresponding attribute.
TypeAliasImpl({
required super.comment,
required super.metadata,
required this.typedefKeyword,
required super.name,
required this.semicolon,
});
@override
Token get endToken => semicolon;
@override
Token get firstTokenAfterCommentAndMetadata => typedefKeyword;
}
/// A type annotation.
///
/// type ::=
/// [NamedType]
/// | [GenericFunctionType]
/// | [RecordTypeAnnotation]
sealed class TypeAnnotation implements AstNode {
/// The question mark indicating that the type is nullable, or `null` if there
/// is no question mark.
Token? get question;
/// Return the type being named, or `null` if the AST structure has not been
/// resolved.
DartType? get type;
}
/// A type annotation.
///
/// type ::=
/// [NamedType]
/// | [GenericFunctionType]
sealed class TypeAnnotationImpl extends AstNodeImpl implements TypeAnnotation {}
/// A list of type arguments.
///
/// typeArguments ::=
/// '<' typeName (',' typeName)* '>'
abstract final class TypeArgumentList implements AstNode {
/// Return the type arguments associated with the type.
NodeList<TypeAnnotation> get arguments;
/// Return the left bracket.
Token get leftBracket;
/// Return the right bracket.
Token get rightBracket;
}
/// A list of type arguments.
///
/// typeArguments ::=
/// '<' typeName (',' typeName)* '>'
final class TypeArgumentListImpl extends AstNodeImpl
implements TypeArgumentList {
/// The left bracket.
@override
final Token leftBracket;
/// The type arguments associated with the type.
final NodeListImpl<TypeAnnotationImpl> _arguments = NodeListImpl._();
/// The right bracket.
@override
final Token rightBracket;
/// Initialize a newly created list of type arguments.
TypeArgumentListImpl({
required this.leftBracket,
required List<TypeAnnotationImpl> arguments,
required this.rightBracket,
}) {
_arguments._initialize(this, arguments);
}
@override
NodeListImpl<TypeAnnotationImpl> get arguments => _arguments;
@override
Token get beginToken => leftBracket;
@override
Token get endToken => rightBracket;
@override
// TODO(paulberry): Add commas.
ChildEntities get _childEntities => ChildEntities()
..addToken('leftBracket', leftBracket)
..addNodeList('arguments', arguments)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitTypeArgumentList(this);
@override
void visitChildren(AstVisitor visitor) {
_arguments.accept(visitor);
}
}
/// A literal that has a type associated with it.
///
/// typedLiteral ::=
/// [ListLiteral]
/// | [SetOrMapLiteral]
sealed class TypedLiteral implements Literal {
/// Return the token representing the 'const' keyword, or `null` if the
/// literal is not a constant.
Token? get constKeyword;
/// Return `true` if this literal is a constant expression, either because the
/// keyword `const` was explicitly provided or because no keyword was provided
/// and this expression is in a constant context.
bool get isConst;
/// Return the type argument associated with this literal, or `null` if no
/// type arguments were declared.
TypeArgumentList? get typeArguments;
}
/// A literal that has a type associated with it.
///
/// typedLiteral ::=
/// [ListLiteral]
/// | [MapLiteral]
sealed class TypedLiteralImpl extends LiteralImpl implements TypedLiteral {
/// The token representing the 'const' keyword, or `null` if the literal is
/// not a constant.
@override
Token? constKeyword;
/// The type argument associated with this literal, or `null` if no type
/// arguments were declared.
TypeArgumentListImpl? _typeArguments;
/// Initialize a newly created typed literal. The [constKeyword] can be
/// `null` if the literal is not a constant. The [typeArguments] can be `null`
/// if no type arguments were declared.
TypedLiteralImpl({
required this.constKeyword,
required TypeArgumentListImpl? typeArguments,
}) : _typeArguments = typeArguments {
_becomeParentOf(_typeArguments);
}
@override
bool get isConst {
return constKeyword != null || inConstantContext;
}
@override
TypeArgumentListImpl? get typeArguments => _typeArguments;
set typeArguments(TypeArgumentListImpl? typeArguments) {
_typeArguments = _becomeParentOf(typeArguments);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('constKeyword', constKeyword)
..addNode('typeArguments', typeArguments);
@override
void visitChildren(AstVisitor visitor) {
_typeArguments?.accept(visitor);
}
}
/// An expression representing a type, e.g. the expression `int` in
/// `var x = int;`.
///
/// Objects of this type are not produced directly by the parser (because the
/// parser cannot tell whether an identifier refers to a type); they are
/// produced at resolution time.
///
/// The `.staticType` getter returns the type of the expression (which will
/// always be the type `Type`). To see the type represented by the type literal
/// use `.typeName.type`.
abstract final class TypeLiteral
implements Expression, CommentReferableExpression {
/// The type represented by this literal.
NamedType get type;
}
/// An expression representing a type, e.g. the expression `int` in
/// `var x = int;`.
///
/// Objects of this type are not produced directly by the parser (because the
/// parser cannot tell whether an identifier refers to a type); they are
/// produced at resolution time.
///
/// The `.staticType` getter returns the type of the expression (which will
/// always be the type `Type`). To see the type represented by the type literal
/// use `.typeName.type`.
final class TypeLiteralImpl extends CommentReferableExpressionImpl
implements TypeLiteral {
NamedTypeImpl _typeName;
TypeLiteralImpl({
required NamedTypeImpl typeName,
}) : _typeName = typeName {
_becomeParentOf(_typeName);
}
@override
Token get beginToken => _typeName.beginToken;
@override
Token get endToken => _typeName.endToken;
@override
Precedence get precedence {
if (_typeName.typeArguments != null) {
return Precedence.postfix;
} else if (_typeName.importPrefix != null) {
return Precedence.postfix;
} else {
return Precedence.primary;
}
}
@override
NamedTypeImpl get type => _typeName;
set typeName(NamedTypeImpl value) {
_typeName = _becomeParentOf(value);
}
@override
ChildEntities get _childEntities => ChildEntities()..addNode('type', type);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitTypeLiteral(this);
@override
void resolveExpression(ResolverVisitor resolver, DartType contextType) {
resolver.visitTypeLiteral(this, contextType: contextType);
}
@override
void visitChildren(AstVisitor visitor) {
_typeName.accept(visitor);
}
}
/// A type parameter.
///
/// typeParameter ::=
/// name ('extends' [TypeAnnotation])?
abstract final class TypeParameter implements Declaration {
/// Return the upper bound for legal arguments, or `null` if there is no
/// explicit upper bound.
TypeAnnotation? get bound;
@override
TypeParameterElement? get declaredElement;
/// Return the token representing the 'extends' keyword, or `null` if there is
/// no explicit upper bound.
Token? get extendsKeyword;
/// Return the name of the type parameter.
Token get name;
}
/// A type parameter.
///
/// typeParameter ::=
/// typeParameterVariance? [SimpleIdentifier] ('extends' [NamedType])?
///
/// typeParameterVariance ::= 'out' | 'inout' | 'in'
final class TypeParameterImpl extends DeclarationImpl implements TypeParameter {
@override
final Token name;
/// The token representing the variance modifier keyword, or `null` if
/// there is no explicit variance modifier, meaning legacy covariance.
Token? varianceKeyword;
/// The token representing the 'extends' keyword, or `null` if there is no
/// explicit upper bound.
@override
Token? extendsKeyword;
/// The name of the upper bound for legal arguments, or `null` if there is no
/// explicit upper bound.
TypeAnnotationImpl? _bound;
@override
TypeParameterElementImpl? declaredElement;
/// Initialize a newly created type parameter. Either or both of the [comment]
/// and [metadata] can be `null` if the parameter does not have the
/// corresponding attribute. The [extendsKeyword] and [bound] can be `null` if
/// the parameter does not have an upper bound.
TypeParameterImpl({
required super.comment,
required super.metadata,
required this.name,
required this.extendsKeyword,
required TypeAnnotationImpl? bound,
this.varianceKeyword,
}) : _bound = bound {
_becomeParentOf(_bound);
}
@override
TypeAnnotationImpl? get bound => _bound;
set bound(TypeAnnotationImpl? type) {
_bound = _becomeParentOf(type);
}
@override
Token get endToken {
return _bound?.endToken ?? name;
}
@override
Token get firstTokenAfterCommentAndMetadata => varianceKeyword ?? name;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('name', name)
..addToken('extendsKeyword', extendsKeyword)
..addNode('bound', bound);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitTypeParameter(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_bound?.accept(visitor);
}
}
/// Type parameters within a declaration.
///
/// typeParameterList ::=
/// '<' [TypeParameter] (',' [TypeParameter])* '>'
abstract final class TypeParameterList implements AstNode {
/// Return the left angle bracket.
Token get leftBracket;
/// Return the right angle bracket.
Token get rightBracket;
/// Return the type parameters for the type.
NodeList<TypeParameter> get typeParameters;
}
/// Type parameters within a declaration.
///
/// typeParameterList ::=
/// '<' [TypeParameter] (',' [TypeParameter])* '>'
final class TypeParameterListImpl extends AstNodeImpl
implements TypeParameterList {
/// The left angle bracket.
@override
final Token leftBracket;
/// The type parameters in the list.
final NodeListImpl<TypeParameterImpl> _typeParameters = NodeListImpl._();
/// The right angle bracket.
@override
final Token rightBracket;
/// Initialize a newly created list of type parameters.
TypeParameterListImpl({
required this.leftBracket,
required List<TypeParameterImpl> typeParameters,
required this.rightBracket,
}) {
_typeParameters._initialize(this, typeParameters);
}
@override
Token get beginToken => leftBracket;
@override
Token get endToken => rightBracket;
@override
NodeListImpl<TypeParameterImpl> get typeParameters => _typeParameters;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('leftBracket', leftBracket)
..addNodeList('typeParameters', typeParameters)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitTypeParameterList(this);
@override
void visitChildren(AstVisitor visitor) {
_typeParameters.accept(visitor);
}
}
/// A directive that references a URI.
///
/// uriBasedDirective ::=
/// [LibraryAugmentationDirective]
/// [ExportDirective]
/// | [ImportDirective]
/// | [PartDirective]
sealed class UriBasedDirective implements Directive {
/// Return the URI referenced by this directive.
StringLiteral get uri;
}
/// A directive that references a URI.
///
/// uriBasedDirective ::=
/// [ExportDirective]
/// | [ImportDirective]
/// | [PartDirective]
sealed class UriBasedDirectiveImpl extends DirectiveImpl
implements UriBasedDirective {
/// The URI referenced by this directive.
StringLiteralImpl _uri;
/// Initialize a newly create URI-based directive. Either or both of the
/// [comment] and [metadata] can be `null` if the directive does not have the
/// corresponding attribute.
UriBasedDirectiveImpl({
required super.comment,
required super.metadata,
required StringLiteralImpl uri,
}) : _uri = uri {
_becomeParentOf(_uri);
}
@override
StringLiteralImpl get uri => _uri;
set uri(StringLiteralImpl uri) {
_uri = _becomeParentOf(uri);
}
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_uri.accept(visitor);
}
/// Validate this directive, but do not check for existence. Return a code
/// indicating the problem if there is one, or `null` no problem.
static UriValidationCode? validateUri(
bool isImport, StringLiteral uriLiteral, String? uriContent) {
if (uriLiteral is StringInterpolation) {
return UriValidationCode.URI_WITH_INTERPOLATION;
}
if (uriContent == null) {
return UriValidationCode.INVALID_URI;
}
if (uriContent.isEmpty) {
return null;
}
Uri uri;
try {
uri = Uri.parse(Uri.encodeFull(uriContent));
} on FormatException {
return UriValidationCode.INVALID_URI;
}
if (uri.path.isEmpty) {
return UriValidationCode.INVALID_URI;
}
return null;
}
}
/// Validation codes returned by [UriBasedDirective.validate].
class UriValidationCode {
static const UriValidationCode INVALID_URI = UriValidationCode('INVALID_URI');
static const UriValidationCode URI_WITH_INTERPOLATION =
UriValidationCode('URI_WITH_INTERPOLATION');
/// The name of the validation code.
final String name;
/// Initialize a newly created validation code to have the given [name].
const UriValidationCode(this.name);
@override
String toString() => name;
}
/// An identifier that has an initial value associated with it.
///
/// Instances of this class are always children of the class
/// [VariableDeclarationList].
///
/// variableDeclaration ::=
/// name ('=' [Expression])?
// TODO(paulberry): the grammar does not allow metadata to be associated with a
// VariableDeclaration, and currently we don't record comments for it either.
// Consider changing the class hierarchy so that [VariableDeclaration] does not
// extend [Declaration].
abstract final class VariableDeclaration implements Declaration {
@override
VariableElement? get declaredElement;
/// Return the equal sign separating the variable name from the initial value,
/// or `null` if the initial value was not specified.
Token? get equals;
/// Return the expression used to compute the initial value for the variable,
/// or `null` if the initial value was not specified.
Expression? get initializer;
/// Return `true` if this variable was declared with the 'const' modifier.
bool get isConst;
/// Return `true` if this variable was declared with the 'final' modifier.
///
/// Variables that are declared with the 'const' modifier will return `false`
/// even though they are implicitly final.
bool get isFinal;
/// Return `true` if this variable was declared with the 'late' modifier.
bool get isLate;
/// Return the name of the variable being declared.
Token get name;
}
/// An identifier that has an initial value associated with it. Instances of
/// this class are always children of the class [VariableDeclarationList].
///
/// variableDeclaration ::=
/// [SimpleIdentifier] ('=' [Expression])?
///
// TODO(paulberry): the grammar does not allow metadata to be associated with
// a VariableDeclaration, and currently we don't record comments for it either.
// Consider changing the class hierarchy so that [VariableDeclaration] does not
// extend [Declaration].
final class VariableDeclarationImpl extends DeclarationImpl
implements VariableDeclaration {
@override
final Token name;
@override
VariableElementImpl? declaredElement;
/// The equal sign separating the variable name from the initial value, or
/// `null` if the initial value was not specified.
@override
final Token? equals;
/// The expression used to compute the initial value for the variable, or
/// `null` if the initial value was not specified.
ExpressionImpl? _initializer;
/// When this node is read as a part of summaries, we usually don't want
/// to read the [initializer], but we need to know if there is one in
/// the code. So, this flag might be set to `true` even though
/// [initializer] is `null`.
bool hasInitializer = false;
/// Initialize a newly created variable declaration. The [equals] and
/// [initializer] can be `null` if there is no initializer.
VariableDeclarationImpl({
required this.name,
required this.equals,
required ExpressionImpl? initializer,
}) : _initializer = initializer,
super(comment: null, metadata: null) {
_becomeParentOf(_initializer);
}
/// This overridden implementation of [documentationComment] looks in the
/// grandparent node for Dartdoc comments if no documentation is specifically
/// available on the node.
@override
CommentImpl? get documentationComment {
var comment = super.documentationComment;
if (comment == null) {
var node = parent?.parent;
if (node is AnnotatedNodeImpl) {
return node.documentationComment;
}
}
return comment;
}
@override
Token get endToken {
if (initializer case final initializer?) {
return initializer.endToken;
}
return name;
}
@override
Token get firstTokenAfterCommentAndMetadata => name;
@override
ExpressionImpl? get initializer => _initializer;
set initializer(ExpressionImpl? expression) {
_initializer = _becomeParentOf(expression);
}
@override
bool get isConst {
final parent = this.parent;
return parent is VariableDeclarationList && parent.isConst;
}
@override
bool get isFinal {
final parent = this.parent;
return parent is VariableDeclarationList && parent.isFinal;
}
@override
bool get isLate {
final parent = this.parent;
return parent is VariableDeclarationList && parent.isLate;
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('name', name)
..addToken('equals', equals)
..addNode('initializer', initializer);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitVariableDeclaration(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_initializer?.accept(visitor);
}
}
/// The declaration of one or more variables of the same type.
///
/// variableDeclarationList ::=
/// finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
///
/// finalConstVarOrType ::=
/// 'final' 'late'? [TypeAnnotation]?
/// | 'const' [TypeAnnotation]?
/// | 'var'
/// | 'late'? [TypeAnnotation]
abstract final class VariableDeclarationList implements AnnotatedNode {
/// Return `true` if the variables in this list were declared with the 'const'
/// modifier.
bool get isConst;
/// Return `true` if the variables in this list were declared with the 'final'
/// modifier.
///
/// Variables that are declared with the 'const' modifier will return `false`
/// even though they are implicitly final. (In other words, this is a
/// syntactic check rather than a semantic check.)
bool get isFinal;
/// Return `true` if the variables in this list were declared with the 'late'
/// modifier.
bool get isLate;
/// Return the token representing the 'final', 'const' or 'var' keyword, or
/// `null` if no keyword was included.
Token? get keyword;
/// Return the token representing the 'late' keyword, or `null` if the late
/// modifier was not included.
Token? get lateKeyword;
/// Return the type of the variables being declared, or `null` if no type was
/// provided.
TypeAnnotation? get type;
/// Return a list containing the individual variables being declared.
NodeList<VariableDeclaration> get variables;
}
/// The declaration of one or more variables of the same type.
///
/// variableDeclarationList ::=
/// finalConstVarOrType [VariableDeclaration]
/// (',' [VariableDeclaration])*
///
/// finalConstVarOrType ::=
/// 'final' 'late'? [TypeAnnotation]?
/// | 'const' [TypeAnnotation]?
/// | 'var'
/// | 'late'? [TypeAnnotation]
final class VariableDeclarationListImpl extends AnnotatedNodeImpl
implements VariableDeclarationList {
/// The token representing the 'final', 'const' or 'var' keyword, or `null` if
/// no keyword was included.
@override
final Token? keyword;
/// The token representing the 'late' keyword, or `null` if the late modifier
/// was not included.
@override
final Token? lateKeyword;
/// The type of the variables being declared, or `null` if no type was
/// provided.
TypeAnnotationImpl? _type;
/// A list containing the individual variables being declared.
final NodeListImpl<VariableDeclarationImpl> _variables = NodeListImpl._();
/// Initialize a newly created variable declaration list. Either or both of
/// the [comment] and [metadata] can be `null` if the variable list does not
/// have the corresponding attribute. The [keyword] can be `null` if a type
/// was specified. The [type] must be `null` if the keyword is 'var'.
VariableDeclarationListImpl({
required super.comment,
required super.metadata,
required this.lateKeyword,
required this.keyword,
required TypeAnnotationImpl? type,
required List<VariableDeclarationImpl> variables,
}) : _type = type {
_becomeParentOf(_type);
_variables._initialize(this, variables);
}
@override
Token get endToken => _variables.endToken!;
@override
Token get firstTokenAfterCommentAndMetadata {
return Token.lexicallyFirst(lateKeyword, keyword) ??
_type?.beginToken ??
_variables.beginToken!;
}
@override
bool get isConst => keyword?.keyword == Keyword.CONST;
@override
bool get isFinal => keyword?.keyword == Keyword.FINAL;
@override
bool get isLate => lateKeyword != null;
@override
TypeAnnotationImpl? get type => _type;
set type(TypeAnnotationImpl? type) {
_type = _becomeParentOf(type);
}
@override
NodeListImpl<VariableDeclarationImpl> get variables => _variables;
@override
// TODO(paulberry): include commas.
ChildEntities get _childEntities => super._childEntities
..addToken('lateKeyword', lateKeyword)
..addToken('keyword', keyword)
..addNode('type', type)
..addNodeList('variables', variables);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitVariableDeclarationList(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_type?.accept(visitor);
_variables.accept(visitor);
}
}
/// A list of variables that are being declared in a context where a statement
/// is required.
///
/// variableDeclarationStatement ::=
/// [VariableDeclarationList] ';'
abstract final class VariableDeclarationStatement implements Statement {
/// Return the semicolon terminating the statement.
Token get semicolon;
/// Return the variables being declared.
VariableDeclarationList get variables;
}
/// A list of variables that are being declared in a context where a statement
/// is required.
///
/// variableDeclarationStatement ::=
/// [VariableDeclarationList] ';'
final class VariableDeclarationStatementImpl extends StatementImpl
implements VariableDeclarationStatement {
/// The variables being declared.
VariableDeclarationListImpl _variableList;
/// The semicolon terminating the statement.
@override
final Token semicolon;
/// Initialize a newly created variable declaration statement.
VariableDeclarationStatementImpl({
required VariableDeclarationListImpl variableList,
required this.semicolon,
}) : _variableList = variableList {
_becomeParentOf(_variableList);
}
@override
Token get beginToken => _variableList.beginToken;
@override
Token get endToken => semicolon;
@override
VariableDeclarationListImpl get variables => _variableList;
set variables(VariableDeclarationListImpl variables) {
_variableList = _becomeParentOf(variables);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addNode('variables', variables)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) =>
visitor.visitVariableDeclarationStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_variableList.accept(visitor);
}
}
/// The shared interface of [AssignedVariablePattern] and
/// [DeclaredVariablePattern].
sealed class VariablePattern implements DartPattern {
/// The name of the variable declared or referenced by the pattern.
Token get name;
}
sealed class VariablePatternImpl extends DartPatternImpl
implements VariablePattern {
@override
final Token name;
/// If this variable was used to resolve an implicitly named field, the
/// implicit name node is recorded here for a future use.
PatternFieldNameImpl? fieldNameWithImplicitName;
VariablePatternImpl({
required this.name,
});
@override
VariablePatternImpl? get variablePattern => this;
}
/// A guard in a pattern-based `case` in a `switch` statement, `switch`
/// expression, `if` statement, or `if` element.
///
/// switchCase ::=
/// 'when' [Expression]
abstract final class WhenClause implements AstNode {
/// Return the condition that is evaluated when the [pattern] matches, that
/// must evaluate to `true` in order for the [expression] to be executed.
Expression get expression;
/// Return the `when` keyword.
Token get whenKeyword;
}
/// A guard in a pattern-based `case` in a `switch` statement or `switch`
/// expression.
///
/// switchCase ::=
/// 'when' [Expression]
final class WhenClauseImpl extends AstNodeImpl implements WhenClause {
ExpressionImpl _expression;
@override
final Token whenKeyword;
WhenClauseImpl({
required this.whenKeyword,
required ExpressionImpl expression,
}) : _expression = expression {
_becomeParentOf(expression);
}
@override
Token get beginToken => whenKeyword;
@override
Token get endToken => expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('whenKeyword', whenKeyword)
..addNode('expression', expression);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitWhenClause(this);
@override
void visitChildren(AstVisitor visitor) {
expression.accept(visitor);
}
}
/// A while statement.
///
/// whileStatement ::=
/// 'while' '(' [Expression] ')' [Statement]
abstract final class WhileStatement implements Statement {
/// Return the body of the loop.
Statement get body;
/// Return the expression used to determine whether to execute the body of the
/// loop.
Expression get condition;
/// Return the left parenthesis.
Token get leftParenthesis;
/// Return the right parenthesis.
Token get rightParenthesis;
/// Return the token representing the 'while' keyword.
Token get whileKeyword;
}
/// A while statement.
///
/// whileStatement ::=
/// 'while' '(' [Expression] ')' [Statement]
final class WhileStatementImpl extends StatementImpl implements WhileStatement {
/// The token representing the 'while' keyword.
@override
final Token whileKeyword;
/// The left parenthesis.
@override
final Token leftParenthesis;
/// The expression used to determine whether to execute the body of the loop.
ExpressionImpl _condition;
/// The right parenthesis.
@override
final Token rightParenthesis;
/// The body of the loop.
StatementImpl _body;
/// Initialize a newly created while statement.
WhileStatementImpl({
required this.whileKeyword,
required this.leftParenthesis,
required ExpressionImpl condition,
required this.rightParenthesis,
required StatementImpl body,
}) : _condition = condition,
_body = body {
_becomeParentOf(_condition);
_becomeParentOf(_body);
}
@override
Token get beginToken => whileKeyword;
@override
StatementImpl get body => _body;
set body(StatementImpl statement) {
_body = _becomeParentOf(statement);
}
@override
ExpressionImpl get condition => _condition;
set condition(ExpressionImpl expression) {
_condition = _becomeParentOf(expression);
}
@override
Token get endToken => _body.endToken;
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('whileKeyword', whileKeyword)
..addToken('leftParenthesis', leftParenthesis)
..addNode('condition', condition)
..addToken('rightParenthesis', rightParenthesis)
..addNode('body', body);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitWhileStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_condition.accept(visitor);
_body.accept(visitor);
}
}
/// A wildcard pattern.
///
/// wildcardPattern ::=
/// ( 'var' | 'final' | 'final'? [TypeAnnotation])? '_'
abstract final class WildcardPattern implements DartPattern {
/// The 'var' or 'final' keyword.
Token? get keyword;
/// The `_` token.
Token get name;
/// The type that the pattern is required to match, or `null` if any type is
/// matched.
TypeAnnotation? get type;
}
/// A wildcard pattern.
///
/// variablePattern ::=
/// ( 'var' | 'final' | 'final'? [TypeAnnotation])? '_'
final class WildcardPatternImpl extends DartPatternImpl
implements WildcardPattern {
@override
final Token? keyword;
@override
final Token name;
@override
final TypeAnnotationImpl? type;
WildcardPatternImpl({
required this.name,
required this.keyword,
required this.type,
}) {
_becomeParentOf(type);
}
@override
Token get beginToken => type?.beginToken ?? name;
@override
Token get endToken => name;
/// If [keyword] is `final`, returns it.
Token? get finalKeyword {
final keyword = this.keyword;
if (keyword != null && keyword.keyword == Keyword.FINAL) {
return keyword;
}
return null;
}
@override
PatternPrecedence get precedence => PatternPrecedence.primary;
@override
ChildEntities get _childEntities => super._childEntities
..addToken('keyword', keyword)
..addNode('type', type)
..addToken('name', name);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitWildcardPattern(this);
@override
DartType computePatternSchema(ResolverVisitor resolverVisitor) {
return resolverVisitor
.analyzeDeclaredVariablePatternSchema(type?.typeOrThrow);
}
@override
void resolvePattern(
ResolverVisitor resolverVisitor,
SharedMatchContext context,
) {
final declaredType = type?.typeOrThrow;
resolverVisitor.analyzeWildcardPattern(
context: context,
node: this,
declaredType: declaredType,
);
if (declaredType != null) {
resolverVisitor.checkPatternNeverMatchesValueType(
context: context,
pattern: this,
requiredType: declaredType,
);
}
}
@override
void visitChildren(AstVisitor visitor) {
type?.accept(visitor);
}
}
/// The with clause in a class declaration.
///
/// withClause ::=
/// 'with' [NamedType] (',' [NamedType])*
abstract final class WithClause implements AstNode {
/// Return the names of the mixins that were specified.
NodeList<NamedType> get mixinTypes;
/// Return the token representing the 'with' keyword.
Token get withKeyword;
}
/// The with clause in a class declaration.
///
/// withClause ::=
/// 'with' [NamedType] (',' [NamedType])*
final class WithClauseImpl extends AstNodeImpl implements WithClause {
/// The token representing the 'with' keyword.
@override
final Token withKeyword;
/// The names of the mixins that were specified.
final NodeListImpl<NamedTypeImpl> _mixinTypes = NodeListImpl._();
/// Initialize a newly created with clause.
WithClauseImpl({
required this.withKeyword,
required List<NamedTypeImpl> mixinTypes,
}) {
_mixinTypes._initialize(this, mixinTypes);
}
@override
Token get beginToken => withKeyword;
@override
Token get endToken => _mixinTypes.endToken ?? withKeyword;
@override
NodeListImpl<NamedTypeImpl> get mixinTypes => _mixinTypes;
@override
// TODO(paulberry): add commas.
ChildEntities get _childEntities => ChildEntities()
..addToken('withKeyword', withKeyword)
..addNodeList('mixinTypes', mixinTypes);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitWithClause(this);
@override
void visitChildren(AstVisitor visitor) {
_mixinTypes.accept(visitor);
}
}
/// A yield statement.
///
/// yieldStatement ::=
/// 'yield' '*'? [Expression] ‘;’
abstract final class YieldStatement implements Statement {
/// Return the expression whose value will be yielded.
Expression get expression;
/// Return the semicolon following the expression.
Token get semicolon;
/// Return the star optionally following the 'yield' keyword.
Token? get star;
/// Return the 'yield' keyword.
Token get yieldKeyword;
}
/// A yield statement.
///
/// yieldStatement ::=
/// 'yield' '*'? [Expression] ‘;’
final class YieldStatementImpl extends StatementImpl implements YieldStatement {
/// The 'yield' keyword.
@override
final Token yieldKeyword;
/// The star optionally following the 'yield' keyword.
@override
final Token? star;
/// The expression whose value will be yielded.
ExpressionImpl _expression;
/// The semicolon following the expression.
@override
final Token semicolon;
/// Initialize a newly created yield expression. The [star] can be `null` if
/// no star was provided.
YieldStatementImpl({
required this.yieldKeyword,
required this.star,
required ExpressionImpl expression,
required this.semicolon,
}) : _expression = expression {
_becomeParentOf(_expression);
}
@override
Token get beginToken {
return yieldKeyword;
}
@override
Token get endToken {
return semicolon;
}
@override
ExpressionImpl get expression => _expression;
set expression(ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
ChildEntities get _childEntities => ChildEntities()
..addToken('yieldKeyword', yieldKeyword)
..addToken('star', star)
..addNode('expression', expression)
..addToken('semicolon', semicolon);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitYieldStatement(this);
@override
void visitChildren(AstVisitor visitor) {
_expression.accept(visitor);
}
}
/// An indication of the resolved kind of a [SetOrMapLiteral].
enum _SetOrMapKind {
/// Indicates that the literal represents a map.
map,
/// Indicates that the literal represents a set.
set,
/// Indicates that either
/// - the literal is syntactically ambiguous and resolution has not yet been
/// performed, or
/// - the literal is invalid because resolution was not able to resolve the
/// ambiguity.
unresolved
}