blob: b3de9e44645ffea97b9cb015006fbaadf5c6aae6 [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/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/type.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/constant/constant_verifier.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/fasta/token_utils.dart' as util show findPrevious;
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart' show LineInfo, Source;
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:pub_semver/src/version.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.
NodeList<StringLiteral> _strings;
/// Initialize a newly created list of adjacent strings. To be syntactically
/// valid, the list of [strings] must contain at least two elements.
AdjacentStringsImpl(List<StringLiteral> strings) {
_strings = new NodeListImpl<StringLiteral>(this, strings);
}
@override
Token get beginToken => _strings.beginToken;
@override
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..addAll(_strings);
@override
Token get endToken => _strings.endToken;
@override
NodeList<StringLiteral> get strings => _strings;
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitAdjacentStrings(this);
@override
void visitChildren(AstVisitor visitor) {
_strings.accept(visitor);
}
@override
void _appendStringValue(StringBuffer buffer) {
int length = strings.length;
for (int i = 0; i < length; i++) {
StringLiteralImpl stringLiteral = strings[i];
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.
NodeList<Annotation> _metadata;
/// 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(CommentImpl comment, List<Annotation> metadata) {
_comment = _becomeParentOf(comment);
_metadata = new NodeListImpl<Annotation>(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
Comment get documentationComment => _comment;
@override
void set documentationComment(Comment comment) {
_comment = _becomeParentOf(comment as CommentImpl);
}
@override
NodeList<Annotation> get metadata => _metadata;
@override
List<AstNode> get sortedCommentAndAnnotations {
return <AstNode>[]
..add(_comment)
..addAll(_metadata)
..sort(AstNode.LEXICAL_ORDER);
}
/// Return a holder of child entities that subclasses can add to.
ChildEntities get _childEntities {
ChildEntities result = new ChildEntities();
if (_commentIsBeforeAnnotations()) {
result
..add(_comment)
..addAll(_metadata);
} else {
result.addAll(sortedCommentAndAnnotations);
}
return result;
}
@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 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.
AnnotationImpl(this.atSign, IdentifierImpl name, this.period,
SimpleIdentifierImpl constructorName, ArgumentListImpl arguments) {
_name = _becomeParentOf(name);
_constructorName = _becomeParentOf(constructorName);
_arguments = _becomeParentOf(arguments);
}
@override
ArgumentList get arguments => _arguments;
@override
void set arguments(ArgumentList arguments) {
_arguments = _becomeParentOf(arguments as ArgumentListImpl);
}
@override
Token get beginToken => atSign;
@override
Iterable<SyntacticEntity> get childEntities => new ChildEntities()
..add(atSign)
..add(_name)
..add(period)
..add(_constructorName)
..add(_arguments);
@override
SimpleIdentifier get constructorName => _constructorName;
@override
void set constructorName(SimpleIdentifier name) {
_constructorName = _becomeParentOf(name as SimpleIdentifierImpl);
}
@override
Element get element {
if (_element != null) {
return _element;
} else if (_constructorName == null && _name != null) {
return _name.staticElement;
}
return null;
}
@override
void 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
Identifier get name => _name;
@override
void set name(Identifier name) {
_name = _becomeParentOf(name as IdentifierImpl);
}
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitAnnotation(this);
@override
void visitChildren(AstVisitor visitor) {
_name?.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.
NodeList<Expression> _arguments;
/// 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(
this.leftParenthesis, List<Expression> arguments, this.rightParenthesis) {
_arguments = new NodeListImpl<Expression>(this, arguments);
}
@override
NodeList<Expression> get arguments => _arguments;
@override
Token get beginToken => leftParenthesis;
@override
// TODO(paulberry): Add commas.
Iterable<SyntacticEntity> get childEntities => new ChildEntities()
..add(leftParenthesis)
..addAll(_arguments)
..add(rightParenthesis);
@deprecated
List<ParameterElement> get correspondingPropagatedParameters => null;
@deprecated
@override
void set correspondingPropagatedParameters(
List<ParameterElement> parameters) {
if (parameters != null && parameters.length != _arguments.length) {
throw new ArgumentError(
"Expected ${_arguments.length} parameters, not ${parameters.length}");
}
}
List<ParameterElement> get correspondingStaticParameters =>
_correspondingStaticParameters;
@override
void set correspondingStaticParameters(List<ParameterElement> parameters) {
if (parameters != null && parameters.length != _arguments.length) {
throw new ArgumentError(
"Expected ${_arguments.length} parameters, not ${parameters.length}");
}
_correspondingStaticParameters = parameters;
}
@override
Token get endToken => 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(
ExpressionImpl expression, this.asOperator, TypeAnnotationImpl type) {
_expression = _becomeParentOf(expression);
_type = _becomeParentOf(type);
}
@override
Token get beginToken => _expression.beginToken;
@override
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..add(_expression)..add(asOperator)..add(_type);
@override
Token get endToken => _type.endToken;
@override
Expression get expression => _expression;
@override
void set expression(Expression expression) {
_expression = _becomeParentOf(expression as ExpressionImpl);
}
@override
Precedence get precedence => Precedence.relational;
@override
TypeAnnotation get type => _type;
@override
void set type(TypeAnnotation type) {
_type = _becomeParentOf(type as TypeAnnotationImpl);
}
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitAsExpression(this);
@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(
this.assertKeyword,
this.leftParenthesis,
ExpressionImpl condition,
this.comma,
ExpressionImpl message,
this.rightParenthesis) {
_condition = _becomeParentOf(condition);
_message = _becomeParentOf(message);
}
@override
Token get beginToken => assertKeyword;
@override
Iterable<SyntacticEntity> get childEntities => new ChildEntities()
..add(assertKeyword)
..add(leftParenthesis)
..add(_condition)
..add(comma)
..add(_message)
..add(rightParenthesis);
@override
Expression get condition => _condition;
@override
void set condition(Expression condition) {
_condition = _becomeParentOf(condition as ExpressionImpl);
}
@override
Token get endToken => rightParenthesis;
@override
Expression get message => _message;
@override
void set message(Expression expression) {
_message = _becomeParentOf(expression as ExpressionImpl);
}
@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(
this.assertKeyword,
this.leftParenthesis,
ExpressionImpl condition,
this.comma,
ExpressionImpl message,
this.rightParenthesis,
this.semicolon) {
_condition = _becomeParentOf(condition);
_message = _becomeParentOf(message);
}
@override
Token get beginToken => assertKeyword;
@override
Iterable<SyntacticEntity> get childEntities => new ChildEntities()
..add(assertKeyword)
..add(leftParenthesis)
..add(_condition)
..add(comma)
..add(_message)
..add(rightParenthesis)
..add(semicolon);
@override
Expression get condition => _condition;
@override
void set condition(Expression condition) {
_condition = _becomeParentOf(condition as ExpressionImpl);
}
@override
Token get endToken => semicolon;
@override
Expression get message => _message;
@override
void set message(Expression expression) {
_message = _becomeParentOf(expression as ExpressionImpl);
}
@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
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(ExpressionImpl leftHandSide, this.operator,
ExpressionImpl rightHandSide) {
if (leftHandSide == null || rightHandSide == null) {
String message;
if (leftHandSide == null) {
if (rightHandSide == null) {
message = "Both the left-hand and right-hand sides are null";
} else {
message = "The left-hand size is null";
}
} else {
message = "The right-hand size is null";
}
AnalysisEngine.instance.logger.logError(
message, new CaughtException(new AnalysisException(message), null));
}
_leftHandSide = _becomeParentOf(leftHandSide);
_rightHandSide = _becomeParentOf(rightHandSide);
}
@override
Token get beginToken => _leftHandSide.beginToken;
@override
@deprecated
MethodElement get bestElement => staticElement;
@override
Iterable<SyntacticEntity> get childEntities => new ChildEntities()
..add(_leftHandSide)
..add(operator)
..add(_rightHandSide);
@override
Token get endToken => _rightHandSide.endToken;
@override
Expression get leftHandSide => _leftHandSide;
@override
void set leftHandSide(Expression expression) {
_leftHandSide = _becomeParentOf(expression as ExpressionImpl);
}
@override
Precedence get precedence => Precedence.assignment;
@deprecated
@override
MethodElement get propagatedElement => null;
@deprecated
@override
set propagatedElement(MethodElement element) {}
@override
Expression get rightHandSide => _rightHandSide;
@override
void set rightHandSide(Expression expression) {
_rightHandSide = _becomeParentOf(expression as ExpressionImpl);
}
/// 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 {
ExecutableElement executableElement = null;
if (staticElement != null) {
executableElement = staticElement;
} else {
Expression left = _leftHandSide;
if (left is Identifier) {
Element leftElement = left.staticElement;
if (leftElement is ExecutableElement) {
executableElement = leftElement;
}
} else if (left is PropertyAccess) {
Element leftElement = left.propertyName.staticElement;
if (leftElement is ExecutableElement) {
executableElement = leftElement;
}
}
}
if (executableElement == null) {
return null;
}
List<ParameterElement> parameters = executableElement.parameters;
if (parameters.length < 1) {
return null;
}
return parameters[0];
}
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitAssignmentExpression(this);
@override
void visitChildren(AstVisitor visitor) {
_leftHandSide?.accept(visitor);
_rightHandSide?.accept(visitor);
}
}
/// 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
int get end => offset + length;
@override
bool get isSynthetic => false;
@override
int get length {
Token beginToken = this.beginToken;
Token endToken = this.endToken;
if (beginToken == null || endToken == null) {
return -1;
}
return endToken.offset + endToken.length - beginToken.offset;
}
@override
int get offset {
Token beginToken = this.beginToken;
if (beginToken == null) {
return -1;
}
return beginToken.offset;
}
@override
AstNode get parent => _parent;
@override
AstNode get root {
AstNode root = this;
AstNode parent = this.parent;
while (parent != null) {
root = parent;
parent = root.parent;
}
return root;
}
Token findPrevious(Token target) =>
util.findPrevious(beginToken, target) ?? parent?.findPrevious(target);
@override
@deprecated
E getAncestor<E extends AstNode>(Predicate<AstNode> predicate) =>
thisOrAncestorMatching(predicate);
@override
E getProperty<E>(String name) {
if (_propertyMap == null) {
return null;
}
return _propertyMap[name] as E;
}
@override
void setProperty(String name, Object value) {
if (value == null) {
if (_propertyMap != null) {
_propertyMap.remove(name);
if (_propertyMap.isEmpty) {
_propertyMap = null;
}
}
} else {
if (_propertyMap == null) {
_propertyMap = new HashMap<String, Object>();
}
_propertyMap[name] = value;
}
}
@override
E thisOrAncestorMatching<E extends AstNode>(Predicate<AstNode> predicate) {
// TODO(brianwilkerson) It is a bug that this method can return `this`.
AstNode node = this;
while (node != null && !predicate(node)) {
node = node.parent;
}
return node as E;
}
@override
T thisOrAncestorOfType<T extends AstNode>() {
AstNode node = this;
while (node != null && node is! T) {
node = node.parent;
}
return node as T;
}
@override
String toSource() {
StringBuffer buffer = new StringBuffer();
accept(new ToSourceVisitor2(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) {
if (child != null) {
child._parent = this;
}
return child;
}
}
/// 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(this.awaitKeyword, ExpressionImpl expression) {
_expression = _becomeParentOf(expression);
}
@override
Token get beginToken {
if (awaitKeyword != null) {
return awaitKeyword;
}
return _expression.beginToken;
}
@override
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..add(awaitKeyword)..add(_expression);
@override
Token get endToken => _expression.endToken;
@override
Expression get expression => _expression;
@override
void set expression(Expression expression) {
_expression = _becomeParentOf(expression as ExpressionImpl);
}
@override
Precedence get precedence => Precedence.prefix;
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitAwaitExpression(this);
@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(
ExpressionImpl leftOperand, this.operator, ExpressionImpl rightOperand) {
_leftOperand = _becomeParentOf(leftOperand);
_rightOperand = _becomeParentOf(rightOperand);
}
@override
Token get beginToken => _leftOperand.beginToken;
@override
@deprecated
MethodElement get bestElement => staticElement;
@override
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..add(_leftOperand)..add(operator)..add(_rightOperand);
@override
Token get endToken => _rightOperand.endToken;
@override
Expression get leftOperand => _leftOperand;
@override
void set leftOperand(Expression expression) {
_leftOperand = _becomeParentOf(expression as ExpressionImpl);
}
@override
Precedence get precedence => Precedence.forTokenType(operator.type);
@deprecated
@override
MethodElement get propagatedElement => null;
@deprecated
@override
set propagatedElement(MethodElement element) {}
@override
Expression get rightOperand => _rightOperand;
@override
void set rightOperand(Expression expression) {
_rightOperand = _becomeParentOf(expression as ExpressionImpl);
}
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitBinaryExpression(this);
@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, BlockImpl block) {
_block = _becomeParentOf(block);
}
@override
Token get beginToken {
if (keyword != null) {
return keyword;
}
return _block.beginToken;
}
@override
Block get block => _block;
@override
void set block(Block block) {
_block = _becomeParentOf(block as BlockImpl);
}
@override
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..add(keyword)..add(star)..add(_block);
@override
Token get endToken => _block.endToken;
@override
bool get isAsynchronous => keyword != null && keyword.lexeme == Parser.ASYNC;
@override
bool get isGenerator => star != null;
@override
bool get isSynchronous => keyword == null || keyword.lexeme != Parser.ASYNC;
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitBlockFunctionBody(this);
@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.
NodeList<Statement> _statements;
/// The right curly bracket.
@override
Token rightBracket;
/// Initialize a newly created block of code.
BlockImpl(this.leftBracket, List<Statement> statements, this.rightBracket) {
_statements = new NodeListImpl<Statement>(this, statements);
}
@override
Token get beginToken => leftBracket;
@override
Iterable<SyntacticEntity> get childEntities => new ChildEntities()
..add(leftBracket)
..addAll(_statements)
..add(rightBracket);
@override
Token get endToken => rightBracket;
@override
NodeList<Statement> get statements => _statements;
@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
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..add(literal);
@override
Token get endToken => literal;
@override
bool get isSynthetic => literal.isSynthetic;
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitBooleanLiteral(this);
@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, SimpleIdentifierImpl label, this.semicolon) {
_label = _becomeParentOf(label);
}
@override
Token get beginToken => breakKeyword;
@override
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..add(breakKeyword)..add(_label)..add(semicolon);
@override
Token get endToken => semicolon;
@override
SimpleIdentifier get label => _label;
@override
void set label(SimpleIdentifier identifier) {
_label = _becomeParentOf(identifier as SimpleIdentifierImpl);
}
@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
implements CascadeExpression {
/// The target of the cascade sections.
ExpressionImpl _target;
/// The cascade sections sharing the common target.
NodeList<Expression> _cascadeSections;
/// Initialize a newly created cascade expression. The list of
/// [cascadeSections] must contain at least one element.
CascadeExpressionImpl(
ExpressionImpl target, List<Expression> cascadeSections) {
_target = _becomeParentOf(target);
_cascadeSections = new NodeListImpl<Expression>(this, cascadeSections);
}
@override
Token get beginToken => _target.beginToken;
@override
NodeList<Expression> get cascadeSections => _cascadeSections;
@override
Iterable<SyntacticEntity> get childEntities => new ChildEntities()
..add(_target)
..addAll(_cascadeSections);
@override
Token get endToken => _cascadeSections.endToken;
@override
Precedence get precedence => Precedence.cascade;
@override
Expression get target => _target;
@override
void set target(Expression target) {
_target = _becomeParentOf(target as ExpressionImpl);
}
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitCascadeExpression(this);
@override
void visitChildren(AstVisitor visitor) {
_target?.accept(visitor);
_cascadeSections.accept(visitor);
}
}
/// 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,
TypeAnnotationImpl exceptionType,
this.catchKeyword,
this.leftParenthesis,
SimpleIdentifierImpl exceptionParameter,
this.comma,
SimpleIdentifierImpl stackTraceParameter,
this.rightParenthesis,
BlockImpl body) {
_exceptionType = _becomeParentOf(exceptionType);
_exceptionParameter = _becomeParentOf(exceptionParameter);
_stackTraceParameter = _becomeParentOf(stackTraceParameter);
_body = _becomeParentOf(body);
}
@override
Token get beginToken {
if (onKeyword != null) {
return onKeyword;
}
return catchKeyword;
}
@override
Block get body => _body;
@override
void set body(Block block) {
_body = _becomeParentOf(block as BlockImpl);
}
@override
Iterable<SyntacticEntity> get childEntities => new ChildEntities()
..add(onKeyword)
..add(_exceptionType)
..add(catchKeyword)
..add(leftParenthesis)
..add(_exceptionParameter)
..add(comma)
..add(_stackTraceParameter)
..add(rightParenthesis)
..add(_body);
@override
Token get endToken => _body.endToken;
@override
SimpleIdentifier get exceptionParameter => _exceptionParameter;
@override
void set exceptionParameter(SimpleIdentifier parameter) {
_exceptionParameter = _becomeParentOf(parameter as SimpleIdentifierImpl);
}
@override
TypeAnnotation get exceptionType => _exceptionType;
@override
void set exceptionType(TypeAnnotation exceptionType) {
_exceptionType = _becomeParentOf(exceptionType as TypeAnnotationImpl);
}
@override
SimpleIdentifier get stackTraceParameter => _stackTraceParameter;
@override
void set stackTraceParameter(SimpleIdentifier parameter) {
_stackTraceParameter = _becomeParentOf(parameter as SimpleIdentifierImpl);
}
@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
with IterableMixin<SyntacticEntity>
implements Iterable<SyntacticEntity> {
/// The list of child entities to be iterated over.
List<SyntacticEntity> _entities = [];
@override
Iterator<SyntacticEntity> get iterator => _entities.iterator;
/// Add an AST node or token as the next child entity, if it is not null.
void add(SyntacticEntity entity) {
if (entity != null) {
_entities.add(entity);
}
}
/// Add the given items as the next child entities, if [items] is not null.
void addAll(Iterable<SyntacticEntity> items) {
if (items != null) {
_entities.addAll(items);
}
}
}
/// 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 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.classKeyword,
SimpleIdentifierImpl name,
TypeParameterListImpl typeParameters,
ExtendsClauseImpl extendsClause,
WithClauseImpl withClause,
ImplementsClauseImpl implementsClause,
Token leftBracket,
List<ClassMember> members,
Token rightBracket)
: super(comment, metadata, name, typeParameters, implementsClause,
leftBracket, members, rightBracket) {
_extendsClause = _becomeParentOf(extendsClause);
_withClause = _becomeParentOf(withClause);
}
@override
Iterable<SyntacticEntity> get childEntities => super._childEntities
..add(abstractKeyword)
..add(classKeyword)
..add(_name)
..add(_typeParameters)
..add(_extendsClause)
..add(_withClause)
..add(_implementsClause)
..add(_nativeClause)
..add(leftBracket)
..addAll(members)
..add(rightBracket);
@override
ClassElement get declaredElement => _name?.staticElement as ClassElement;
@deprecated
@override
ClassElement get element => declaredElement;
@override
ExtendsClause get extendsClause => _extendsClause;
@override
void set extendsClause(ExtendsClause extendsClause) {
_extendsClause = _becomeParentOf(extendsClause as ExtendsClauseImpl);
}
@override
Token get firstTokenAfterCommentAndMetadata {
if (abstractKeyword != null) {
return abstractKeyword;
}
return classKeyword;
}
@override
bool get isAbstract => abstractKeyword != null;
@override
NativeClause get nativeClause => _nativeClause;
@override
void set nativeClause(NativeClause nativeClause) {
_nativeClause = _becomeParentOf(nativeClause as NativeClauseImpl);
}
@override
WithClause get withClause => _withClause;
@override
void set withClause(WithClause withClause) {
_withClause = _becomeParentOf(withClause as WithClauseImpl);
}
@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(CommentImpl comment, List<Annotation> metadata)
: super(comment, 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.
Token leftBracket;
/// The members defined by the class or mixin.
NodeList<ClassMember> _members;
/// The right curly bracket.
Token rightBracket;
ClassOrMixinDeclarationImpl(
CommentImpl comment,
List<Annotation> metadata,
SimpleIdentifierImpl name,
TypeParameterListImpl typeParameters,
ImplementsClauseImpl implementsClause,
this.leftBracket,
List<ClassMember> members,
this.rightBracket)
: super(comment, metadata, name) {
_typeParameters = _becomeParentOf(typeParameters);
_implementsClause = _becomeParentOf(implementsClause);
_members = new NodeListImpl<ClassMember>(this, members);
}
Token get endToken => rightBracket;
ImplementsClause get implementsClause => _implementsClause;
void set implementsClause(ImplementsClause implementsClause) {
_implementsClause =
_becomeParentOf(implementsClause as ImplementsClauseImpl);
}
NodeList<ClassMember> get members => _members;
TypeParameterList get typeParameters => _typeParameters;
void set typeParameters(TypeParameterList typeParameters) {
_typeParameters = _becomeParentOf(typeParameters as TypeParameterListImpl);
}
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];
SimpleIdentifier fieldName = field.name;
if (fieldName != null && name == fieldName.name) {
return field;
}
}
}
}
return null;
}
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;
SimpleIdentifier methodName = method.name;
if (methodName != null && name == methodName.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 name of the superclass of the class being declared.
TypeNameImpl _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,
TypeParameterListImpl typeParameters,
this.equals,
this.abstractKeyword,
TypeNameImpl superclass,
WithClauseImpl withClause,
ImplementsClauseImpl implementsClause,
Token semicolon)
: super(comment, metadata, keyword, name, semicolon) {
_typeParameters = _becomeParentOf(typeParameters);
_superclass = _becomeParentOf(superclass);
_withClause = _becomeParentOf(withClause);
_implementsClause = _becomeParentOf(implementsClause);
}
@override
Iterable<SyntacticEntity> get childEntities => super._childEntities
..add(typedefKeyword)
..add(_name)
..add(_typeParameters)
..add(equals)
..add(abstractKeyword)
..add(_superclass)
..add(_withClause)
..add(_implementsClause)
..add(semicolon);
@override
ClassElement get declaredElement => _name?.staticElement as ClassElement;
@deprecated
@override
ClassElement get element => declaredElement;
@override
Token get firstTokenAfterCommentAndMetadata {
if (abstractKeyword != null) {
return abstractKeyword;
}
return typedefKeyword;
}
@override
ImplementsClause get implementsClause => _implementsClause;
@override
void set implementsClause(ImplementsClause implementsClause) {
_implementsClause =
_becomeParentOf(implementsClause as ImplementsClauseImpl);
}
@override
bool get isAbstract => abstractKeyword != null;
@override
TypeName get superclass => _superclass;
@override
void set superclass(TypeName superclass) {
_superclass = _becomeParentOf(superclass as TypeNameImpl);
}
@override
TypeParameterList get typeParameters => _typeParameters;
@override
void set typeParameters(TypeParameterList typeParameters) {
_typeParameters = _becomeParentOf(typeParameters as TypeParameterListImpl);
}
@override
WithClause get withClause => _withClause;
@override
void set withClause(WithClause withClause) {
_withClause = _becomeParentOf(withClause as WithClauseImpl);
}
@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 {}
/// 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.
NodeList<CommentReference> _references;
/// 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 = new NodeListImpl<CommentReference>(this, references);
}
@override
Token get beginToken => tokens[0];
@override
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..addAll(tokens);
@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
NodeList<CommentReference> get references => _references;
@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 Comment createBlockComment(List<Token> tokens) =>
new CommentImpl(tokens, CommentType.BLOCK, null);
/// Create a documentation comment consisting of the given [tokens].
static Comment createDocumentationComment(List<Token> tokens) =>
new CommentImpl(
tokens, CommentType.DOCUMENTATION, new List<CommentReference>());
/// Create a documentation comment consisting of the given [tokens] and having
/// the given [references] embedded within it.
static Comment createDocumentationCommentWithReferences(
List<Token> tokens, List<CommentReference> references) =>
new CommentImpl(tokens, CommentType.DOCUMENTATION, references);
/// Create an end-of-line comment consisting of the given [tokens].
static Comment createEndOfLineComment(List<Token> tokens) =>
new CommentImpl(tokens, CommentType.END_OF_LINE, null);
}
/// 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 identifier being referenced.
IdentifierImpl _identifier;
/// 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, IdentifierImpl identifier) {
_identifier = _becomeParentOf(identifier);
}
@override
Token get beginToken => newKeyword ?? _identifier.beginToken;
@override
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..add(newKeyword)..add(_identifier);
@override
Token get endToken => _identifier.endToken;
@override
Identifier get identifier => _identifier;
@override
void set identifier(Identifier identifier) {
_identifier = _becomeParentOf(identifier as IdentifierImpl);
}
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitCommentReference(this);
@override
void visitChildren(AstVisitor visitor) {
_identifier?.accept(visitor);
}
}
/// The possible types of comments that are recognized by the parser.
class CommentType {
/// A block comment.
static const CommentType BLOCK = const CommentType('BLOCK');
/// A documentation comment.
static const CommentType DOCUMENTATION = const CommentType('DOCUMENTATION');
/// An end-of-line comment.
static const CommentType END_OF_LINE = const 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.
NodeList<Directive> _directives;
/// The declarations contained in this compilation unit.
NodeList<CompilationUnitMember> _declarations;
/// 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;
Version languageVersion;
/// The line information for this compilation unit.
@override
LineInfo lineInfo;
/// ?
// TODO(brianwilkerson) Remove this field. It is never read, only written.
Map<int, AstNode> localDeclarations;
/// Additional information about local variables that are declared within this
/// compilation unit but outside any function body, or `null` if resolution
/// has not yet been performed.
LocalVariableInfo localVariableInfo = new LocalVariableInfo();
/// Is `true` if this unit has been parsed as non-nullable.
bool isNonNullable = false;
/// 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,
ScriptTagImpl scriptTag,
List<Directive> directives,
List<CompilationUnitMember> declarations,
this.endToken) {
_scriptTag = _becomeParentOf(scriptTag);
_directives = new NodeListImpl<Directive>(this, directives);
_declarations = new NodeListImpl<CompilationUnitMember>(this, declarations);
}
@override
Iterable<SyntacticEntity> get childEntities {
ChildEntities result = new ChildEntities()..add(_scriptTag);
if (_directivesAreBeforeDeclarations) {
result..addAll(_directives)..addAll(_declarations);
} else {
result.addAll(sortedDirectivesAndDeclarations);
}
return result;
}
@override
NodeList<CompilationUnitMember> get declarations => _declarations;
@override
NodeList<Directive> get directives => _directives;
@deprecated
@override
CompilationUnitElement get element => declaredElement;
@override
set element(CompilationUnitElement element) {
declaredElement = element;
}
@override
int get length {
Token endToken = this.endToken;
if (endToken == null) {
return 0;
}
return endToken.offset + endToken.length;
}
@override
int get offset => 0;
@override
ScriptTag get scriptTag => _scriptTag;
@override
void set scriptTag(ScriptTag scriptTag) {
_scriptTag = _becomeParentOf(scriptTag as ScriptTagImpl);
}
@override
List<AstNode> get sortedDirectivesAndDeclarations {
return <AstNode>[]
..addAll(_directives)
..addAll(_declarations)
..sort(AstNode.LEXICAL_ORDER);
}
/// 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);
bool isPotentiallyMutatedInClosure(VariableElement variable) {
if (localVariableInfo == null) {
throw new StateError('Resolution has not yet been performed');
}
return localVariableInfo.potentiallyMutatedInClosure.contains(variable);
}
bool isPotentiallyMutatedInScope(VariableElement variable) {
if (localVariableInfo == null) {
throw new StateError('Resolution has not yet been performed');
}
return localVariableInfo.potentiallyMutatedInScope.contains(variable);
}
@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]
/// | [TypeAlias]
/// | [FunctionDeclaration]
/// | [MethodDeclaration]
/// | [VariableDeclaration]
/// | [VariableDeclaration]
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(CommentImpl comment, List<Annotation> metadata)
: super(comment, metadata);
}
/// 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(
ExpressionImpl condition,
this.question,
ExpressionImpl thenExpression,
this.colon,
ExpressionImpl elseExpression) {
_condition = _becomeParentOf(condition);
_thenExpression = _becomeParentOf(thenExpression);
_elseExpression = _becomeParentOf(elseExpression);
}
@override
Token get beginToken => _condition.beginToken;
@override
Iterable<SyntacticEntity> get childEntities => new ChildEntities()
..add(_condition)
..add(question)
..add(_thenExpression)
..add(colon)
..add(_elseExpression);
@override
Expression get condition => _condition;
@override
void set condition(Expression expression) {
_condition = _becomeParentOf(expression as ExpressionImpl);
}
@override
Expression get elseExpression => _elseExpression;
@override
void set elseExpression(Expression expression) {
_elseExpression = _becomeParentOf(expression as ExpressionImpl);
}
@override
Token get endToken => _elseExpression.endToken;
@override
Precedence get precedence => Precedence.conditional;
@override
Expression get thenExpression => _thenExpression;
@override
void set thenExpression(Expression expression) {
_thenExpression = _becomeParentOf(expression as ExpressionImpl);
}
@override
E accept<E>(AstVisitor<E> visitor) =>
visitor.visitConditionalExpression(this);
@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,
DottedNameImpl name,
this.equalToken,
StringLiteralImpl value,
this.rightParenthesis,
StringLiteralImpl libraryUri) {
_name = _becomeParentOf(name);
_value = _becomeParentOf(value);
_uri = _becomeParentOf(libraryUri);
}
@override
Token get beginToken => ifKeyword;
@override
Iterable<SyntacticEntity> get childEntities => new ChildEntities()
..add(ifKeyword)
..add(leftParenthesis)
..add(_name)
..add(equalToken)
..add(_value)
..add(rightParenthesis)
..add(_uri);
@override
Token get endToken => _uri.endToken;
@deprecated
@override
StringLiteral get libraryUri => _uri;
@deprecated
@override
void set libraryUri(StringLiteral libraryUri) {
_uri = _becomeParentOf(libraryUri as StringLiteralImpl);
}
@override
DottedName get name => _name;
@override
void set name(DottedName name) {
_name = _becomeParentOf(name as DottedNameImpl);
}
@override
StringLiteral get uri => _uri;
@override
void set uri(StringLiteral uri) {
_uri = _becomeParentOf(uri as StringLiteralImpl);
}
@override
StringLiteral get value => _value;
@override
void set value(StringLiteral value) {
_value = _becomeParentOf(value as StringLiteralImpl);
}
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitConfiguration(this);
@override
void visitChildren(AstVisitor visitor) {
_name?.accept(visitor);
_value?.accept(visitor);
_uri?.accept(visitor);
}
}
/// An error listener that only records whether any constant related errors have
/// been reported.
class ConstantAnalysisErrorListener extends AnalysisErrorListener {
/// A flag indicating whether any constant related errors have been reported
/// to this listener.
bool hasConstError = false;
@override
void onError(AnalysisError error) {
ErrorCode errorCode = error.errorCode;
if (errorCode is CompileTimeErrorCode) {
switch (errorCode) {
case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL:
case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT:
case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING:
case CompileTimeErrorCode.CONST_EVAL_TYPE_INT:
case CompileTimeErrorCode.CONST_EVAL_TYPE_NUM:
case CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION:
case CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE:
case CompileTimeErrorCode.CONST_WITH_NON_CONST:
case CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT:
case CompileTimeErrorCode
.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST:
case CompileTimeErrorCode.INVALID_CONSTANT:
case CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL:
case CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL:
case CompileTimeErrorCode.MISSING_CONST_IN_SET_LITERAL:
hasConstError = true;
}
}
}
}
/// 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.
NodeList<ConstructorInitializer> _initializers;
/// 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, or `null` if the constructor does not have a
/// body.
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(
CommentImpl comment,
List<Annotation> metadata,
this.externalKeyword,
this.constKeyword,
this.factoryKeyword,
IdentifierImpl returnType,
this.period,
SimpleIdentifierImpl name,
FormalParameterListImpl parameters,
this.separator,
List<ConstructorInitializer> initializers,
ConstructorNameImpl redirectedConstructor,
FunctionBodyImpl body)
: super(comment, metadata) {
_returnType = _becomeParentOf(returnType);
_name = _becomeParentOf(name);
_parameters = _becomeParentOf(parameters);
_initializers =
new NodeListImpl<ConstructorInitializer>(this, initializers);
_redirectedConstructor = _becomeParentOf(redirectedConstructor);
_body = _becomeParentOf(body);
}
@override
FunctionBody get body => _body;
@override
void set body(FunctionBody functionBody) {
_body = _becomeParentOf(functionBody as FunctionBodyImpl);
}
@override
Iterable<SyntacticEntity> get childEntities => super._childEntities
..add(externalKeyword)
..add(constKeyword)
..add(factoryKeyword)
..add(_returnType)
..add(period)
..add(_name)
..add(_parameters)
..add(separator)
..addAll(initializers)
..add(_redirectedConstructor)
..add(_body);
@deprecated
@override
ConstructorElement get element => declaredElement;
@deprecated
@override
set element(ConstructorElement element) {
declaredElement = element;
}
@override
Token get endToken {
if (_body != null) {
return _body.endToken;
} else if (!_initializers.isEmpty) {
return _initializers.endToken;
}
return _parameters.endToken;
}
@override
Token get firstTokenAfterCommentAndMetadata {
Token leftMost =
Token.lexicallyFirst([externalKeyword, constKeyword, factoryKeyword]);
if (leftMost != null) {
return leftMost;
}
return _returnType.beginToken;
}
@override
NodeList<ConstructorInitializer> get initializers => _initializers;
@override
SimpleIdentifier get name => _name;
@override
void set name(SimpleIdentifier identifier) {
_name = _becomeParentOf(identifier as SimpleIdentifierImpl);
}
@override
FormalParameterList get parameters => _parameters;
@override
void set parameters(FormalParameterList parameters) {
_parameters = _becomeParentOf(parameters as FormalParameterListImpl);
}
@override
ConstructorName get redirectedConstructor => _redirectedConstructor;
@override
void set redirectedConstructor(ConstructorName redirectedConstructor) {
_redirectedConstructor =
_becomeParentOf(redirectedConstructor as ConstructorNameImpl);
}
@override
Identifier get returnType => _returnType;
@override
void set returnType(Identifier typeName) {
_returnType = _becomeParentOf(typeName as IdentifierImpl);
}
@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,
SimpleIdentifierImpl fieldName, this.equals, ExpressionImpl expression) {
_fieldName = _becomeParentOf(fieldName);
_expression = _becomeParentOf(expression);
}
@override
Token get beginToken {
if (thisKeyword != null) {
return thisKeyword;
}
return _fieldName.beginToken;
}
@override
Iterable<SyntacticEntity> get childEntities => new ChildEntities()
..add(thisKeyword)
..add(period)
..add(_fieldName)
..add(equals)
..add(_expression);
@override
Token get endToken => _expression.endToken;
@override
Expression get expression => _expression;
@override
void set expression(Expression expression) {
_expression = _becomeParentOf(expression as ExpressionImpl);
}
@override
SimpleIdentifier get fieldName => _fieldName;
@override
void set fieldName(SimpleIdentifier identifier) {
_fieldName = _becomeParentOf(identifier as SimpleIdentifierImpl);
}
@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.
TypeNameImpl _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(
TypeNameImpl type, this.period, SimpleIdentifierImpl name) {
_type = _becomeParentOf(type);
_name = _becomeParentOf(name);
}
@override
Token get beginToken => _type.beginToken;
@override
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..add(_type)..add(period)..add(_name);
@override
Token get endToken {
if (_name != null) {
return _name.endToken;
}
return _type.endToken;
}
@override
SimpleIdentifier get name => _name;
@override
void set name(SimpleIdentifier name) {
_name = _becomeParentOf(name as SimpleIdentifierImpl);
}
@override
TypeName get type => _type;
@override
void set type(TypeName type) {
_type = _becomeParentOf(type as TypeNameImpl);
}
@override
E accept<E>(AstVisitor<E> visitor) => visitor.visitConstructorName(this);
@override
void visitChildren(AstVisitor visitor) {
_type?.accept(visitor);
_name?.accept(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).
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, SimpleIdentifierImpl label, this.semicolon) {
_label = _becomeParentOf(label);
}
@override
Token get beginToken => continueKeyword;
@override
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..add(continueKeyword)..add(_label)..add(semicolon);
@override
Token get endToken => semicolon;
@override
SimpleIdentifier get label => _label;
@override
void set label(SimpleIdentifier identifier) {
_label = _becomeParentOf(identifier as SimpleIdentifierImpl);
}
@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(CommentImpl comment, List<Annotation> metadata)
: super(comment, 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(CommentImpl comment, List<Annotation> metadata,
this.keyword, TypeAnnotationImpl type, SimpleIdentifierImpl identifier)
: super(comment, metadata) {
_type = _becomeParentOf(type);
_identifier = _becomeParentOf(identifier);
}
@override
Iterable<SyntacticEntity> get childEntities =>
super._childEntities..add(keyword)..add(_type)..add(_identifier);
@override
LocalVariableElement get declaredElement {
if (_identifier == null) {
return null;
}
return _identifier.staticElement as LocalVariableElement;
}
@override
LocalVariableElement get element => declaredElement;
@override
Token get endToken => _identifier.endToken;
@override
Token get firstTokenAfterCommentAndMetadata {
if (keyword != null) {
return keyword;
} else if (_type != null) {
return _type.beginToken;
}
return _identifier.beginToken;
}
@override
SimpleIdentifier get identifier => _identifier;
@override
void 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
TypeAnnotation get type => _type;
@override
void set type(TypeAnnotation type) {
_type = _becomeParentOf(type as TypeAnnotationImpl);
}
@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(Token token) : 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(NormalFormalParameterImpl parameter, this.kind,
this.separator, ExpressionImpl defaultValue) {
_parameter = _becomeParentOf(parameter);
_defaultValue = _becomeParentOf(defaultValue);
}
@override
Token get beginToken => _parameter.beginToken;
@override
Iterable<SyntacticEntity> get childEntities =>
new ChildEntities()..add(_parameter)..add(separator)..add(_defaultValue);
@override
Token get covariantKeyword => null;
@override
ParameterElement get declaredElement => _parameter.declaredElement;
@override
Expression get defaultValue => _defaultValue;
@override
void set defaultValue(Expression expression) {
_defaultValue = _becomeParentOf(expression as ExpressionImpl);
}
@override
Token get endToken {
if (_defaultValue != null) {
return _defaultValue.endToken;
}
return _parameter.endToken;
}
@override
SimpleIdentifier get identifier => _parameter.identifier