blob: b8d68c148c34f15af7a9e692030a9b0bce3e41ae [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:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.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/src/dart/ast/to_source_visitor.dart';
import 'package:analyzer/src/dart/ast/token.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/source.dart' show LineInfo, Source;
import 'package:analyzer/src/generated/utilities_dart.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]+
class AdjacentStringsImpl extends StringLiteralImpl implements AdjacentStrings {
/// The strings that are implicitly concatenated.
final NodeListImpl<StringLiteral> _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<StringLiteral> strings,
}) {
_strings._initialize(this, strings);
}
@override
Token get beginToken => _strings.beginToken!;
@override
Token get endToken => _strings.endToken!;
@override
NodeListImpl<StringLiteral> 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++) {
var stringLiteral = strings[i] as StringLiteralImpl;
stringLiteral._appendStringValue(buffer);
}
}
}
/// An AST node that can be annotated with both a documentation comment and a
/// list of annotations.
abstract 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<Annotation> _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(this._comment, List<Annotation>? metadata) {
_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(Comment? comment) {
_comment = _becomeParentOf(comment as CommentImpl?);
}
@override
NodeListImpl<Annotation> 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 ::=
/// '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
class AnnotationImpl extends AstNodeImpl implements Annotation {
/// The at sign that introduced the annotation.
@override
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
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(this.atSign, this._name, this._typeArguments, this.period,
this._constructorName, this._arguments) {
_becomeParentOf(_name);
_becomeParentOf(_typeArguments);
_becomeParentOf(_constructorName);
_becomeParentOf(_arguments);
}
@override
ArgumentListImpl? get arguments => _arguments;
set arguments(ArgumentList? arguments) {
_arguments = _becomeParentOf(arguments as ArgumentListImpl?);
}
@override
Token get beginToken => atSign;
@override
SimpleIdentifierImpl? get constructorName => _constructorName;
set constructorName(SimpleIdentifier? name) {
_constructorName = _becomeParentOf(name as SimpleIdentifierImpl?);
}
@override
Element? get element {
if (_element != null) {
return _element!;
} else if (_constructorName == null) {
return _name.staticElement;
}
return null;
}
set element(Element? element) {
_element = element;
}
@override
Token get endToken {
if (_arguments != null) {
return _arguments!.endToken;
} else if (_constructorName != null) {
return _constructorName!.endToken;
}
return _name.endToken;
}
@override
IdentifierImpl get name => _name;
set name(Identifier name) {
_name = _becomeParentOf(name as IdentifierImpl)!;
}
@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(TypeArgumentList? typeArguments) {
_typeArguments = _becomeParentOf(typeArguments as TypeArgumentListImpl?);
}
@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])*
class ArgumentListImpl extends AstNodeImpl implements ArgumentList {
/// The left parenthesis.
@override
Token leftParenthesis;
/// The expressions producing the values of the arguments.
final NodeListImpl<Expression> _arguments = NodeListImpl._();
/// The right parenthesis.
@override
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<Expression> arguments,
required this.rightParenthesis,
}) {
_arguments._initialize(this, arguments);
}
@override
NodeListImpl<Expression> 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' [TypeName]
class AsExpressionImpl extends ExpressionImpl implements AsExpression {
/// The expression used to compute the value being cast.
ExpressionImpl _expression;
/// The 'as' operator.
@override
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(Expression expression) {
_expression = _becomeParentOf(expression as ExpressionImpl);
}
@override
Precedence get precedence => Precedence.relational;
@override
TypeAnnotationImpl get type => _type;
set type(TypeAnnotation type) {
_type = _becomeParentOf(type as TypeAnnotationImpl);
}
@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])? ')'
class AssertInitializerImpl extends ConstructorInitializerImpl
implements AssertInitializer {
@override
Token assertKeyword;
@override
Token leftParenthesis;
/// The condition that is being asserted to be `true`.
ExpressionImpl _condition;
@override
Token? comma;
/// The message to report if the assertion fails, or `null` if no message was
/// supplied.
ExpressionImpl? _message;
@override
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(Expression condition) {
_condition = _becomeParentOf(condition as ExpressionImpl);
}
@override
Token get endToken => rightParenthesis;
@override
ExpressionImpl? get message => _message;
set message(Expression? 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);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitAssertInitializer(this);
@override
void visitChildren(AstVisitor visitor) {
_condition.accept(visitor);
message?.accept(visitor);
}
}
/// An assert statement.
///
/// assertStatement ::=
/// 'assert' '(' [Expression] ')' ';'
class AssertStatementImpl extends StatementImpl implements AssertStatement {
@override
Token assertKeyword;
@override
Token leftParenthesis;
/// The condition that is being asserted to be `true`.
ExpressionImpl _condition;
@override
Token? comma;
/// The message to report if the assertion fails, or `null` if no message was
/// supplied.
ExpressionImpl? _message;
@override
Token rightParenthesis;
@override
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(Expression condition) {
_condition = _becomeParentOf(condition as ExpressionImpl);
}
@override
Token get endToken => semicolon;
@override
ExpressionImpl? get message => _message;
set message(Expression? 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);
}
}
/// An assignment expression.
///
/// assignmentExpression ::=
/// [Expression] operator [Expression]
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
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(Expression expression) {
_leftHandSide = _becomeParentOf(expression as ExpressionImpl);
}
@override
Precedence get precedence => Precedence.assignment;
@override
ExpressionImpl get rightHandSide => _rightHandSide;
set rightHandSide(Expression expression) {
_rightHandSide = _becomeParentOf(expression as ExpressionImpl);
}
@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 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 augmentation import directive.
///
/// importDirective ::=
/// [Annotation] 'import' 'augment' [StringLiteral] ';'
class AugmentationImportDirectiveImpl extends UriBasedDirectiveImpl
implements AugmentationImportDirective {
@override
Token importKeyword;
@override
Token augmentKeyword;
@override
Token semicolon;
AugmentationImportDirectiveImpl({
required CommentImpl? comment,
required List<Annotation>? metadata,
required this.importKeyword,
required this.augmentKeyword,
required this.semicolon,
required StringLiteralImpl uri,
}) : super(comment, metadata, uri) {
_becomeParentOf(_uri);
}
@override
AugmentationImportElement? get element {
return super.element as AugmentationImportElement?;
}
@override
Token get endToken => semicolon;
@override
Token get firstTokenAfterCommentAndMetadata => importKeyword;
@Deprecated('Use specific xyzToken instead')
@override
Token get keyword => importKeyword;
@override
LibraryAugmentationElement? get uriElement {
return element?.augmentation;
}
@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]
class AwaitExpressionImpl extends ExpressionImpl implements AwaitExpression {
/// The 'await' keyword.
@override
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(Expression expression) {
_expression = _becomeParentOf(expression as ExpressionImpl);
}
@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]
class BinaryExpressionImpl extends ExpressionImpl implements BinaryExpression {
/// The expression used to compute the left operand.
ExpressionImpl _leftOperand;
/// The binary operator being applied.
@override
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(Expression expression) {
_leftOperand = _becomeParentOf(expression as ExpressionImpl);
}
@override
Precedence get precedence => Precedence.forTokenType(operator.type);
@override
ExpressionImpl get rightOperand => _rightOperand;
set rightOperand(Expression expression) {
_rightOperand = _becomeParentOf(expression as ExpressionImpl);
}
@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 function body that consists of a block of statements.
///
/// blockFunctionBody ::=
/// ('async' | 'async' '*' | 'sync' '*')? [Block]
class BlockFunctionBodyImpl extends FunctionBodyImpl
implements BlockFunctionBody {
/// The token representing the 'async' or 'sync' keyword, or `null` if there
/// is no such keyword.
@override
Token? keyword;
/// The star optionally following the 'async' or 'sync' keyword, or `null` if
/// there is wither no such keyword or no star.
@override
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(this.keyword, this.star, this._block) {
_becomeParentOf(_block);
}
@override
Token get beginToken {
if (keyword != null) {
return keyword!;
}
return _block.beginToken;
}
@override
BlockImpl get block => _block;
set block(Block block) {
_block = _becomeParentOf(block as BlockImpl);
}
@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* '}'
class BlockImpl extends StatementImpl implements Block {
/// The left curly bracket.
@override
Token leftBracket;
/// The statements contained in the block.
final NodeListImpl<Statement> _statements = NodeListImpl._();
/// The right curly bracket.
@override
Token rightBracket;
/// Initialize a newly created block of code.
BlockImpl(this.leftBracket, List<Statement> statements, this.rightBracket) {
_statements._initialize(this, statements);
}
@override
Token get beginToken => leftBracket;
@override
Token get endToken => rightBracket;
@override
NodeListImpl<Statement> 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'
class BooleanLiteralImpl extends LiteralImpl implements BooleanLiteral {
/// The token representing the literal.
@override
Token literal;
/// The value of the literal.
@override
bool value = false;
/// Initialize a newly created boolean literal.
BooleanLiteralImpl(this.literal, 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]? ';'
class BreakStatementImpl extends StatementImpl implements BreakStatement {
/// The token representing the 'break' keyword.
@override
Token breakKeyword;
/// The label associated with the statement, or `null` if there is no label.
SimpleIdentifierImpl? _label;
/// The semicolon terminating the statement.
@override
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(this.breakKeyword, this._label, this.semicolon) {
_becomeParentOf(_label);
}
@override
Token get beginToken => breakKeyword;
@override
Token get endToken => semicolon;
@override
SimpleIdentifierImpl? get label => _label;
set label(SimpleIdentifier? identifier) {
_label = _becomeParentOf(identifier as SimpleIdentifierImpl?);
}
@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
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<Expression> _cascadeSections = NodeListImpl._();
/// Initialize a newly created cascade expression. The list of
/// [cascadeSections] must contain at least one element.
CascadeExpressionImpl(this._target, List<Expression> cascadeSections) {
_becomeParentOf(_target);
_cascadeSections._initialize(this, cascadeSections);
}
@override
Token get beginToken => _target.beginToken;
@override
NodeListImpl<Expression> 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(Expression target) {
_target = _becomeParentOf(target as ExpressionImpl);
}
@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);
}
}
/// A catch clause within a try statement.
///
/// onPart ::=
/// catchPart [Block]
/// | 'on' type catchPart? [Block]
///
/// catchPart ::=
/// 'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
class CatchClauseImpl extends AstNodeImpl implements CatchClause {
/// The token representing the 'on' keyword, or `null` if there is no 'on'
/// keyword.
@override
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
Token? catchKeyword;
/// The left parenthesis, or `null` if there is no 'catch' keyword.
@override
Token? leftParenthesis;
/// The parameter whose value will be the exception that was thrown, or `null`
/// if there is no 'catch' keyword.
SimpleIdentifierImpl? _exceptionParameter;
/// The comma separating the exception parameter from the stack trace
/// parameter, or `null` if there is no stack trace parameter.
@override
Token? comma;
/// The parameter whose value will be the stack trace associated with the
/// exception, or `null` if there is no stack trace parameter.
SimpleIdentifierImpl? _stackTraceParameter;
/// The right parenthesis, or `null` if there is no 'catch' keyword.
@override
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(
this.onKeyword,
this._exceptionType,
this.catchKeyword,
this.leftParenthesis,
this._exceptionParameter,
this.comma,
this._stackTraceParameter,
this.rightParenthesis,
this._body)
: assert(onKeyword != null || catchKeyword != null) {
_becomeParentOf(_exceptionType);
_becomeParentOf(_exceptionParameter);
_becomeParentOf(_stackTraceParameter);
_becomeParentOf(_body);
}
@override
Token get beginToken {
if (onKeyword != null) {
return onKeyword!;
}
return catchKeyword!;
}
@override
BlockImpl get body => _body;
set body(Block block) {
_body = _becomeParentOf(block as BlockImpl);
}
@override
Token get endToken => _body.endToken;
@override
SimpleIdentifierImpl? get exceptionParameter => _exceptionParameter;
set exceptionParameter(SimpleIdentifier? parameter) {
_exceptionParameter = _becomeParentOf(parameter as SimpleIdentifierImpl?);
}
@override
TypeAnnotationImpl? get exceptionType => _exceptionType;
set exceptionType(TypeAnnotation? exceptionType) {
_exceptionType = _becomeParentOf(exceptionType as TypeAnnotationImpl?);
}
@override
SimpleIdentifierImpl? get stackTraceParameter => _stackTraceParameter;
set stackTraceParameter(SimpleIdentifier? parameter) {
_stackTraceParameter = _becomeParentOf(parameter as SimpleIdentifierImpl?);
}
@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);
}
}
/// 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 ::=
/// 'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
/// ([ExtendsClause] [WithClause]?)?
/// [ImplementsClause]?
/// '{' [ClassMember]* '}'
class ClassDeclarationImpl extends ClassOrMixinDeclarationImpl
implements ClassDeclaration {
/// The 'abstract' keyword, or `null` if the keyword was absent.
@override
Token? abstractKeyword;
/// The 'macro' keyword, or `null` if the keyword was absent.
Token? macroKeyword;
/// The 'augment' keyword, or `null` if the keyword was absent.
Token? augmentKeyword;
/// The token representing the 'class' keyword.
@override
Token classKeyword;
/// The extends clause for the class, or `null` if the class does not extend
/// any other class.
ExtendsClauseImpl? _extendsClause;
/// The with clause for the class, or `null` if the class does not have a with
/// clause.
WithClauseImpl? _withClause;
/// The native clause for the class, or `null` if the class does not have a
/// native clause.
NativeClauseImpl? _nativeClause;
/// Initialize a newly created class declaration. Either or both of the
/// [comment] and [metadata] can be `null` if the class does not have the
/// corresponding attribute. The [abstractKeyword] can be `null` if the class
/// is not abstract. The [typeParameters] can be `null` if the class does not
/// have any type parameters. Any or all of the [extendsClause], [withClause],
/// and [implementsClause] can be `null` if the class does not have the
/// corresponding clause. The list of [members] can be `null` if the class
/// does not have any members.
ClassDeclarationImpl(
CommentImpl? comment,
List<Annotation>? metadata,
this.abstractKeyword,
this.macroKeyword,
this.augmentKeyword,
this.classKeyword,
SimpleIdentifierImpl name,
TypeParameterListImpl? typeParameters,
this._extendsClause,
this._withClause,
ImplementsClauseImpl? implementsClause,
Token leftBracket,
List<ClassMember> members,
Token rightBracket)
: super(comment, metadata, name, typeParameters, implementsClause,
leftBracket, members, rightBracket) {
_becomeParentOf(_extendsClause);
_becomeParentOf(_withClause);
}
@override
ClassElement? get declaredElement => _name.staticElement as ClassElement?;
@override
ExtendsClauseImpl? get extendsClause => _extendsClause;
set extendsClause(ExtendsClause? extendsClause) {
_extendsClause = _becomeParentOf(extendsClause as ExtendsClauseImpl?);
}
@override
Token get firstTokenAfterCommentAndMetadata {
return abstractKeyword ?? macroKeyword ?? augmentKeyword ?? classKeyword;
}
@override
bool get isAbstract => abstractKeyword != null;
@override
NativeClauseImpl? get nativeClause => _nativeClause;
set nativeClause(NativeClause? nativeClause) {
_nativeClause = _becomeParentOf(nativeClause as NativeClauseImpl?);
}
@override
WithClauseImpl? get withClause => _withClause;
set withClause(WithClause? withClause) {
_withClause = _becomeParentOf(withClause as WithClauseImpl?);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('abstractKeyword', abstractKeyword)
..addToken('macroKeyword', macroKeyword)
..addToken('augmentKeyword', augmentKeyword)
..addToken('classKeyword', classKeyword)
..addNode('name', name)
..addNode('typeParameters', typeParameters)
..addNode('extendsClause', extendsClause)
..addNode('withClause', withClause)
..addNode('implementsClause', implementsClause)
..addNode('nativeClause', nativeClause)
..addToken('leftBracket', leftBracket)
..addNodeList('members', members)
..addToken('rightBracket', rightBracket);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitClassDeclaration(this);
@override
ConstructorDeclaration? getConstructor(String? name) {
int length = _members.length;
for (int i = 0; i < length; i++) {
ClassMember classMember = _members[i];
if (classMember is ConstructorDeclaration) {
ConstructorDeclaration constructor = classMember;
SimpleIdentifier? constructorName = constructor.name;
if (name == null && constructorName == null) {
return constructor;
}
if (constructorName != null && constructorName.name == name) {
return constructor;
}
}
}
return null;
}
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_name.accept(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.
abstract 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(super.comment, super.metadata);
}
abstract class ClassOrMixinDeclarationImpl
extends NamedCompilationUnitMemberImpl implements ClassOrMixinDeclaration {
/// The type parameters for the class or mixin,
/// or `null` if the declaration does not have any type parameters.
TypeParameterListImpl? _typeParameters;
/// The implements clause for the class or mixin,
/// or `null` if the declaration does not implement any interfaces.
ImplementsClauseImpl? _implementsClause;
/// The left curly bracket.
@override
Token leftBracket;
/// The members defined by the class or mixin.
final NodeListImpl<ClassMember> _members = NodeListImpl._();
/// The right curly bracket.
@override
Token rightBracket;
ClassOrMixinDeclarationImpl(
super.comment,
super.metadata,
super.name,
this._typeParameters,
this._implementsClause,
this.leftBracket,
List<ClassMember> members,
this.rightBracket) {
_becomeParentOf(_typeParameters);
_becomeParentOf(_implementsClause);
_members._initialize(this, members);
}
@override
Token get endToken => rightBracket;
@override
ImplementsClauseImpl? get implementsClause => _implementsClause;
set implementsClause(ImplementsClause? implementsClause) {
_implementsClause =
_becomeParentOf(implementsClause as ImplementsClauseImpl?);
}
@override
NodeListImpl<ClassMember> get members => _members;
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
set typeParameters(TypeParameterList? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters as TypeParameterListImpl?);
}
@override
VariableDeclaration? getField(String name) {
int memberLength = _members.length;
for (int i = 0; i < memberLength; i++) {
ClassMember classMember = _members[i];
if (classMember is FieldDeclaration) {
FieldDeclaration fieldDeclaration = classMember;
NodeList<VariableDeclaration> fields =
fieldDeclaration.fields.variables;
int fieldLength = fields.length;
for (int i = 0; i < fieldLength; i++) {
VariableDeclaration field = fields[i];
if (name == field.name.name) {
return field;
}
}
}
}
return null;
}
@override
MethodDeclaration? getMethod(String name) {
int length = _members.length;
for (int i = 0; i < length; i++) {
ClassMember classMember = _members[i];
if (classMember is MethodDeclaration) {
MethodDeclaration method = classMember;
if (name == method.name.name) {
return method;
}
}
}
return null;
}
}
/// A class type alias.
///
/// classTypeAlias ::=
/// [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'?
/// mixinApplication
///
/// mixinApplication ::=
/// [TypeName] [WithClause] [ImplementsClause]? ';'
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
Token equals;
/// The token for the 'abstract' keyword, or `null` if this is not defining an
/// abstract class.
@override
Token? abstractKeyword;
/// The token for the 'macro' keyword, or `null` if this is not defining a
/// macro class.
Token? macroKeyword;
/// The token for the 'augment' keyword, or `null` if this is not defining an
/// augmentation class.
Token? augmentKeyword;
/// 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;
/// 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(
CommentImpl? comment,
List<Annotation>? metadata,
Token keyword,
SimpleIdentifierImpl name,
this._typeParameters,
this.equals,
this.abstractKeyword,
this.macroKeyword,
this.augmentKeyword,
this._superclass,
this._withClause,
this._implementsClause,
Token semicolon)
: super(comment, metadata, keyword, name, semicolon) {
_becomeParentOf(_typeParameters);
_becomeParentOf(_superclass);
_becomeParentOf(_withClause);
_becomeParentOf(_implementsClause);
}
@override
ClassElement? get declaredElement => _name.staticElement as ClassElement?;
@override
Token get firstTokenAfterCommentAndMetadata {
return abstractKeyword ?? macroKeyword ?? augmentKeyword ?? typedefKeyword;
}
@override
ImplementsClauseImpl? get implementsClause => _implementsClause;
set implementsClause(ImplementsClause? implementsClause) {
_implementsClause =
_becomeParentOf(implementsClause as ImplementsClauseImpl?);
}
@override
bool get isAbstract => abstractKeyword != null;
@override
NamedTypeImpl get superclass => _superclass;
set superclass(NamedType superclass) {
_superclass = _becomeParentOf(superclass as NamedTypeImpl);
}
@Deprecated('Use superclass instead')
@override
NamedTypeImpl get superclass2 => _superclass;
@override
TypeParameterListImpl? get typeParameters => _typeParameters;
set typeParameters(TypeParameterList? typeParameters) {
_typeParameters = _becomeParentOf(typeParameters as TypeParameterListImpl);
}
@override
WithClauseImpl get withClause => _withClause;
set withClause(WithClause withClause) {
_withClause = _becomeParentOf(withClause as WithClauseImpl);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('typedefKeyword', typedefKeyword)
..addNode('name', name)
..addNode('typeParameters', typeParameters)
..addToken('equals', equals)
..addToken('abstractKeyword', abstractKeyword)
..addToken('macroKeyword', macroKeyword)
..addToken('augmentKeyword', augmentKeyword)
..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);
_name.accept(visitor);
_typeParameters?.accept(visitor);
_superclass.accept(visitor);
_withClause.accept(visitor);
_implementsClause?.accept(visitor);
}
}
abstract 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]
abstract class CombinatorImpl extends AstNodeImpl implements Combinator {
/// The 'hide' or 'show' keyword specifying what kind of processing is to be
/// done on the names.
@override
Token keyword;
/// Initialize a newly created combinator.
CombinatorImpl(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)+
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<CommentReference> _references = NodeListImpl._();
/// 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(this.tokens, this._type, List<CommentReference> references) {
_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<CommentReference> get references => _references;
@override
ChildEntities get _childEntities =>
ChildEntities()..addTokenList('tokens', tokens);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitComment(this);
@override
void visitChildren(AstVisitor visitor) {
_references.accept(visitor);
}
/// Create a block comment consisting of the given [tokens].
static CommentImpl createBlockComment(List<Token> tokens) =>
CommentImpl(tokens, CommentType.BLOCK, const <CommentReference>[]);
/// Create a documentation comment consisting of the given [tokens].
static CommentImpl createDocumentationComment(List<Token> tokens) =>
CommentImpl(
tokens, CommentType.DOCUMENTATION, const <CommentReference>[]);
/// Create a documentation comment consisting of the given [tokens] and having
/// the given [references] embedded within it.
static CommentImpl createDocumentationCommentWithReferences(
List<Token> tokens, List<CommentReference> references) =>
CommentImpl(tokens, CommentType.DOCUMENTATION, references);
/// Create an end-of-line comment consisting of the given [tokens].
static CommentImpl createEndOfLineComment(List<Token> tokens) =>
CommentImpl(tokens, CommentType.END_OF_LINE, const <CommentReference>[]);
}
abstract class CommentReferableExpressionImpl extends ExpressionImpl
implements CommentReferableExpression {}
/// A reference to a Dart element that is found within a documentation comment.
///
/// commentReference ::=
/// '[' 'new'? [Identifier] ']'
class CommentReferenceImpl extends AstNodeImpl implements CommentReference {
/// The token representing the 'new' keyword, or `null` if there was no 'new'
/// keyword.
@override
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(this.newKeyword, this._expression) {
_becomeParentOf(_expression);
}
@override
Token get beginToken => newKeyword ?? _expression.beginToken;
@override
Token get endToken => _expression.endToken;
@override
CommentReferableExpression get expression => _expression;
set expression(CommentReferableExpression expression) {
_expression = _becomeParentOf(expression as CommentReferableExpressionImpl);
}
@override
@Deprecated('Use expression instead')
IdentifierImpl get identifier => _expression as IdentifierImpl;
@Deprecated('Use expression= instead')
set identifier(Identifier identifier) {
_expression = _becomeParentOf(identifier as CommentReferableExpressionImpl);
}
@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]*
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<Directive> _directives = NodeListImpl._();
/// The declarations contained in this compilation unit.
final NodeListImpl<CompilationUnitMember> _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
Token endToken;
/// The element associated with this compilation unit, or `null` if the AST
/// structure has not been resolved.
@override
CompilationUnitElement? declaredElement;
/// The line information for this compilation unit.
@override
final LineInfo lineInfo;
/// The language version information.
LibraryLanguageVersion? languageVersion;
@override
final FeatureSet featureSet;
/// 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(
this.beginToken,
this._scriptTag,
List<Directive>? directives,
List<CompilationUnitMember>? declarations,
this.endToken,
this.featureSet,
this.lineInfo) {
_becomeParentOf(_scriptTag);
_directives._initialize(this, directives);
_declarations._initialize(this, declarations);
}
@override
NodeListImpl<CompilationUnitMember> get declarations => _declarations;
@override
NodeListImpl<Directive> get directives => _directives;
set element(CompilationUnitElement? element) {
declaredElement = element;
}
@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
ScriptTag? get scriptTag => _scriptTag;
set scriptTag(ScriptTag? scriptTag) {
_scriptTag = _becomeParentOf(scriptTag as ScriptTagImpl?);
}
@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 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(super.comment, super.metadata);
}
mixin CompoundAssignmentExpressionImpl implements CompoundAssignmentExpression {
@override
Element? readElement;
@override
Element? writeElement;
@override
DartType? readType;
@override
DartType? writeType;
}
/// A conditional expression.
///
/// conditionalExpression ::=
/// [Expression] '?' [Expression] ':' [Expression]
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
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
Token colon;
/// The expression that is executed if the condition evaluates to `false`.
ExpressionImpl _elseExpression;
/// Initialize a newly created conditional expression.
ConditionalExpressionImpl(this._condition, this.question,
this._thenExpression, this.colon, this._elseExpression) {
_becomeParentOf(_condition);
_becomeParentOf(_thenExpression);
_becomeParentOf(_elseExpression);
}
@override
Token get beginToken => _condition.beginToken;
@override
ExpressionImpl get condition => _condition;
set condition(Expression expression) {
_condition = _becomeParentOf(expression as ExpressionImpl);
}
@override
ExpressionImpl get elseExpression => _elseExpression;
set elseExpression(Expression expression) {
_elseExpression = _becomeParentOf(expression as ExpressionImpl);
}
@override
Token get endToken => _elseExpression.endToken;
@override
Precedence get precedence => Precedence.conditional;
@override
ExpressionImpl get thenExpression => _thenExpression;
set thenExpression(Expression expression) {
_thenExpression = _becomeParentOf(expression as ExpressionImpl);
}
@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)*
class ConfigurationImpl extends AstNodeImpl implements Configuration {
@override
Token ifKeyword;
@override
Token leftParenthesis;
DottedNameImpl _name;
@override
Token? equalToken;
StringLiteralImpl? _value;
@override
Token rightParenthesis;
StringLiteralImpl _uri;
@override
Source? uriSource;
ConfigurationImpl(this.ifKeyword, this.leftParenthesis, this._name,
this.equalToken, this._value, this.rightParenthesis, this._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(DottedName name) {
_name = _becomeParentOf(name as DottedNameImpl);
}
@override
StringLiteralImpl get uri => _uri;
set uri(StringLiteral uri) {
_uri = _becomeParentOf(uri as StringLiteralImpl);
}
@override
StringLiteralImpl? get value => _value;
set value(StringLiteral? 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.
class ConstantContextForExpressionImpl extends AstNodeImpl {
final ExpressionImpl expression;
ConstantContextForExpressionImpl(this.expression) {
_becomeParentOf(expression);
}
@override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
/// 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])*
class ConstructorDeclarationImpl extends ClassMemberImpl
implements ConstructorDeclaration {
/// The token for the 'external' keyword, or `null` if the constructor is not
/// external.
@override
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
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
Token? period;
/// The name of the constructor, or `null` if the constructor being declared
/// is unnamed.
SimpleIdentifierImpl? _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<ConstructorInitializer> _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
ConstructorElement? 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(
super.comment,
super.metadata,
this.externalKeyword,
this.constKeyword,
this.factoryKeyword,
this._returnType,
this.period,
this._name,
this._parameters,
this.separator,
List<ConstructorInitializer>? initializers,
this._redirectedConstructor,
this._body) {
_becomeParentOf(_returnType);
_becomeParentOf(_name);
_becomeParentOf(_parameters);
_initializers._initialize(this, initializers);
_becomeParentOf(_redirectedConstructor);
_becomeParentOf(_body);
}
@override
FunctionBodyImpl get body => _body;
set body(FunctionBody functionBody) {
_body = _becomeParentOf(functionBody as FunctionBodyImpl);
}
@override
Token get endToken {
return _body.endToken;
}
@override
Token get firstTokenAfterCommentAndMetadata {
return Token.lexicallyFirst(
externalKeyword, constKeyword, factoryKeyword) ??
_returnType.beginToken;
}
@override
NodeListImpl<ConstructorInitializer> get initializers => _initializers;
@override
SimpleIdentifierImpl? get name => _name;
set name(SimpleIdentifier? identifier) {
_name = _becomeParentOf(identifier as SimpleIdentifierImpl?);
}
@override
FormalParameterListImpl get parameters => _parameters;
set parameters(FormalParameterList parameters) {
_parameters = _becomeParentOf(parameters as FormalParameterListImpl);
}
@override
ConstructorNameImpl? get redirectedConstructor => _redirectedConstructor;
set redirectedConstructor(ConstructorName? redirectedConstructor) {
_redirectedConstructor =
_becomeParentOf(redirectedConstructor as ConstructorNameImpl);
}
@override
IdentifierImpl get returnType => _returnType;
set returnType(Identifier typeName) {
_returnType = _becomeParentOf(typeName as IdentifierImpl);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('externalKeyword', externalKeyword)
..addToken('constKeyword', constKeyword)
..addToken('factoryKeyword', factoryKeyword)
..addNode('returnType', returnType)
..addToken('period', period)
..addNode('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);
_name?.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]
class ConstructorFieldInitializerImpl extends ConstructorInitializerImpl
implements ConstructorFieldInitializer {
/// The token for the 'this' keyword, or `null` if there is no 'this' keyword.
@override
Token? thisKeyword;
/// The token for the period after the 'this' keyword, or `null` if there is
/// no 'this' keyword.
@override
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
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(this.thisKeyword, this.period,
this._fieldName, this.equals, this._expression) {
_becomeParentOf(_fieldName);
_becomeParentOf(_expression);
}
@override
Token get beginToken {
if (thisKeyword != null) {
return thisKeyword!;
}
return _fieldName.beginToken;
}
@override
Token get endToken => _expression.endToken;
@override
ExpressionImpl get expression => _expression;
set expression(Expression expression) {
_expression = _becomeParentOf(expression as ExpressionImpl);
}
@override
SimpleIdentifierImpl get fieldName => _fieldName;
set fieldName(SimpleIdentifier identifier) {
_fieldName = _becomeParentOf(identifier as SimpleIdentifierImpl);
}
@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]
abstract class ConstructorInitializerImpl extends AstNodeImpl
implements ConstructorInitializer {}
/// The name of the constructor.
///
/// constructorName ::=
/// type ('.' identifier)?
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(this._type, this.period, this._name) {
_becomeParentOf(_type);
_becomeParentOf(_name);
}
@override
Token get beginToken => _type.beginToken;
@override
Token get endToken {
if (_name != null) {
return _name!.endToken;
}
return _type.endToken;
}
@override
SimpleIdentifierImpl? get name => _name;
set name(SimpleIdentifier? name) {
_name = _becomeParentOf(name as SimpleIdentifierImpl?);
}
@override
NamedTypeImpl get type => _type;
set type(NamedType type) {
_type = _becomeParentOf(type as NamedTypeImpl);
}
@Deprecated('Use type instead')
@override
NamedTypeImpl get type2 => _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.
class ConstructorReferenceImpl extends CommentReferableExpressionImpl
implements ConstructorReference {
ConstructorNameImpl _constructorName;
ConstructorReferenceImpl(this._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);
}
}
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]? ';'
class ContinueStatementImpl extends StatementImpl implements ContinueStatement {
/// The token representing the 'continue' keyword.
@override
Token continueKeyword;
/// The label associated with the statement, or `null` if there is no label.
SimpleIdentifierImpl? _label;
/// The semicolon terminating the statement.
@override
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(this.continueKeyword, this._label, this.semicolon) {
_becomeParentOf(_label);
}
@override
Token get beginToken => continueKeyword;
@override
Token get endToken => semicolon;
@override
SimpleIdentifierImpl? get label => _label;
set label(SimpleIdentifier? identifier) {
_label = _becomeParentOf(identifier as SimpleIdentifierImpl?);
}
@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 node that represents the declaration of one or more names. Each declared
/// name is visible within a name scope.
abstract 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(super.comment, super.metadata);
}
/// The declaration of a single identifier.
///
/// declaredIdentifier ::=
/// [Annotation] finalConstVarOrType [SimpleIdentifier]
class DeclaredIdentifierImpl extends DeclarationImpl
implements DeclaredIdentifier {
/// The token representing either the 'final', 'const' or 'var' keyword, or
/// `null` if no keyword was used.
@override
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 name of the variable being declared.
SimpleIdentifierImpl _identifier;
/// 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(super.comment, super.metadata, this.keyword,
this._type, this._identifier) {
_becomeParentOf(_type);
_becomeParentOf(_identifier);
}
@override
LocalVariableElement? get declaredElement {
return _identifier.staticElement as LocalVariableElement;
}
@override
Token get endToken => _identifier.endToken;
@override
Token get firstTokenAfterCommentAndMetadata {
return keyword ?? _type?.beginToken ?? _identifier.beginToken;
}
@override
SimpleIdentifierImpl get identifier => _identifier;
set identifier(SimpleIdentifier identifier) {
_identifier = _becomeParentOf(identifier as SimpleIdentifierImpl);
}
@override
bool get isConst => keyword?.keyword == Keyword.CONST;
@override
bool get isFinal => keyword?.keyword == Keyword.FINAL;
@override
TypeAnnotationImpl? get type => _type;
set type(TypeAnnotation? type) {
_type = _becomeParentOf(type as TypeAnnotationImpl?);
}
@override
ChildEntities get _childEntities => super._childEntities
..addToken('keyword', keyword)
..addNode('type', type)
..addNode('identifier', identifier);
@override
E? accept<E>(AstVisitor<E> visitor) => visitor.visitDeclaredIdentifier(this);
@override
void visitChildren(AstVisitor visitor) {
super.visitChildren(visitor);
_type?.accept(visitor);
_identifier.accept(visitor);
}
}
/// A simple identifier that declares a name.
// TODO(rnystrom): Consider making this distinct from [SimpleIdentifier] and
// get rid of all of the:
//
// if (node.inDeclarationContext()) { ... }
//
// code and instead visit this separately. A declaration is semantically pretty
// different from a use, so using the same node type doesn't seem to buy us
// much.
class DeclaredSimpleIdentifier extends SimpleIdentifierImpl {
DeclaredSimpleIdentifier(super.token);
@override
bool inDeclarationContext() => true;
}
/// 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])?
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
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(
this._parameter, this.kind, this.separator, this._defaultValue) {
_becomeParentOf(_parameter);
_becomeParentOf(_defaultValue);
}
@override
Token get beginToken => _parameter.beginToken;
@override
Token? get covariantKeyword => null;
@override
ParameterElement? get declaredElement => _parameter.declaredElement;
@override
ExpressionImpl? get defaultValue => _defaultValue;
set defaultValue(Expression? expression) {
_defaultValue = _becomeParentOf(expression as ExpressionImpl?);
}
@override
Token get endToken {
if (_defaultValue != null) {
return _defaultValue!.endToken;
}
return _parameter.endToken;
}
@override
SimpleIdentifierImpl? get identifier => _parameter.identifier;
@override
bool get isConst => _parameter.isConst;
@override
bool get isExplicitlyTyped => _parameter.isExplicitlyTyped;
@override
bool get isFinal => _parameter.isFinal;
@override
NodeListImpl<Annotation> get metadata => _parameter.metadata;
@override
NormalFormalParameterImpl get parameter => _parameter;
set parameter(NormalFormalParameter formalParameter) {
_parameter = _becomeParentOf(formalParameter as NormalFormalParameterImpl);
}
@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 ::=
/// [AugmentationImportDirective]
/// | [ExportDirective]
/// | [ImportDirective]
/// | [LibraryDirective]
/// | [PartDirective]
/// | [PartOfDirective]
abstract 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(super.comment, 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] ')' ';'
class DoStatementImpl extends StatementImpl implements DoStatement {
/// The token representing the 'do' keyword.
@override
Token doKeyword;
/// The body of the loop.
StatementImpl _body;
/// The token representing the 'while' keyword.
@override
Token whileKeyword;
/// The left parenthesis.
@override
Token leftParenthesis;
/// The condition that determines when the loop will terminate.
ExpressionImpl _condition;
/// The right parenthesis.
@override
Token rightParenthesis;
/// The semicolon terminating the statement.
@override
Token semicolon;
/// Initialize a newly created do loop.
DoStatementImpl(
this.doKeyword,
this._body,
this.whileKeyword,
this.leftParenthesis,
this._condition,
this.rightParenthesis,
this.semicolon) {
_becomeParentOf(_body);
_becomeParentOf(_condition);
}
@override
Token get beginToken => doKeyword;
@override
StatementImpl get body => _body;
set body(Statement statement) {
_body = _becomeParentOf(statement as StatementImpl);
}
@override
ExpressionImpl get condition => _condition;
set condition(Expression expression) {
_condition = _becomeParentOf(expression as ExpressionImpl);
}
@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])*
class DottedNameImpl extends AstNodeImpl implements DottedName {
/// The components of the identifier.
final NodeListImpl<SimpleIdentifier> _components = NodeListImpl._();
/// Initialize a newly created dotted name.
DottedNameImpl(List<SimpleIdentifier> components) {
_components._initialize(this, components);
}
@override
Token get beginToken => _components.beginToken!;
@override
NodeListImpl<SimpleIdentifier> 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 ::=