[analyzer] Dot Shorthands: AST - DotShorthandInvocation and DotShorthandPropertyAccess.
This CL adds new nodes for the dot shorthands feature. These new nodes will be used, alongside a context type, to resolve to a method/constructor invocation or a static field/getter or tearoff.
Design decision for this CL made here: https://docs.google.com/document/d/1rJuwytXFyG9Ir9key146_hAa7uhEXk4Otqd_3RpSg8A/edit?usp=sharing&resourcekey=0-hRydkMfiTwDEwsX3fN4taQ
Bug: https://github.com/dart-lang/sdk/issues/59835
Change-Id: Iab78bd9e55e488656d1138b1d5d6fc5c9ed64bde
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/418201
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
diff --git a/pkg/analyzer/api.txt b/pkg/analyzer/api.txt
index 7672640..bacf86a 100644
--- a/pkg/analyzer/api.txt
+++ b/pkg/analyzer/api.txt
@@ -379,6 +379,8 @@
visitDeclaredVariablePattern (method: R? Function(DeclaredVariablePattern))
visitDefaultFormalParameter (method: R? Function(DefaultFormalParameter))
visitDoStatement (method: R? Function(DoStatement))
+ visitDotShorthandInvocation (method: R? Function(DotShorthandInvocation))
+ visitDotShorthandPropertyAccess (method: R? Function(DotShorthandPropertyAccess))
visitDottedName (method: R? Function(DottedName))
visitDoubleLiteral (method: R? Function(DoubleLiteral))
visitEmptyFunctionBody (method: R? Function(EmptyFunctionBody))
@@ -733,6 +735,12 @@
rightParenthesis (getter: Token)
semicolon (getter: Token)
whileKeyword (getter: Token)
+ DotShorthandInvocation (class extends InvocationExpression, experimental):
+ memberName (getter: SimpleIdentifier)
+ period (getter: Token)
+ DotShorthandPropertyAccess (class extends Expression, experimental):
+ period (getter: Token)
+ propertyName (getter: Token)
DottedName (class extends Object implements AstNode):
components (getter: NodeList<SimpleIdentifier>)
DoubleLiteral (class extends Object implements Literal):
@@ -1943,6 +1951,8 @@
visitDefaultFormalParameter (method: R? Function(DefaultFormalParameter))
visitDirective (method: R? Function(Directive))
visitDoStatement (method: R? Function(DoStatement))
+ visitDotShorthandInvocation (method: R? Function(DotShorthandInvocation))
+ visitDotShorthandPropertyAccess (method: R? Function(DotShorthandPropertyAccess))
visitDottedName (method: R? Function(DottedName))
visitDoubleLiteral (method: R? Function(DoubleLiteral))
visitEmptyFunctionBody (method: R? Function(EmptyFunctionBody))
@@ -2139,6 +2149,8 @@
visitDeclaredVariablePattern (method: R? Function(DeclaredVariablePattern))
visitDefaultFormalParameter (method: R? Function(DefaultFormalParameter))
visitDoStatement (method: R? Function(DoStatement))
+ visitDotShorthandInvocation (method: R? Function(DotShorthandInvocation))
+ visitDotShorthandPropertyAccess (method: R? Function(DotShorthandPropertyAccess))
visitDottedName (method: R? Function(DottedName))
visitDoubleLiteral (method: R? Function(DoubleLiteral))
visitEmptyFunctionBody (method: R? Function(EmptyFunctionBody))
@@ -2313,6 +2325,8 @@
visitDeclaredVariablePattern (method: R? Function(DeclaredVariablePattern))
visitDefaultFormalParameter (method: R? Function(DefaultFormalParameter))
visitDoStatement (method: R? Function(DoStatement))
+ visitDotShorthandInvocation (method: R? Function(DotShorthandInvocation))
+ visitDotShorthandPropertyAccess (method: R? Function(DotShorthandPropertyAccess))
visitDottedName (method: R? Function(DottedName))
visitDoubleLiteral (method: R? Function(DoubleLiteral))
visitEmptyFunctionBody (method: R? Function(EmptyFunctionBody))
@@ -2487,6 +2501,8 @@
visitDeclaredVariablePattern (method: R? Function(DeclaredVariablePattern))
visitDefaultFormalParameter (method: R? Function(DefaultFormalParameter))
visitDoStatement (method: R? Function(DoStatement))
+ visitDotShorthandInvocation (method: R? Function(DotShorthandInvocation))
+ visitDotShorthandPropertyAccess (method: R? Function(DotShorthandPropertyAccess))
visitDottedName (method: R? Function(DottedName))
visitDoubleLiteral (method: R? Function(DoubleLiteral))
visitEmptyFunctionBody (method: R? Function(EmptyFunctionBody))
@@ -2662,6 +2678,8 @@
visitDeclaredVariablePattern (method: T? Function(DeclaredVariablePattern))
visitDefaultFormalParameter (method: T? Function(DefaultFormalParameter))
visitDoStatement (method: T? Function(DoStatement))
+ visitDotShorthandInvocation (method: T? Function(DotShorthandInvocation))
+ visitDotShorthandPropertyAccess (method: T? Function(DotShorthandPropertyAccess))
visitDottedName (method: T? Function(DottedName))
visitDoubleLiteral (method: T? Function(DoubleLiteral))
visitEmptyFunctionBody (method: T? Function(EmptyFunctionBody))
@@ -2836,6 +2854,8 @@
visitDeclaredVariablePattern (method: R? Function(DeclaredVariablePattern))
visitDefaultFormalParameter (method: R? Function(DefaultFormalParameter))
visitDoStatement (method: R? Function(DoStatement))
+ visitDotShorthandInvocation (method: R? Function(DotShorthandInvocation))
+ visitDotShorthandPropertyAccess (method: R? Function(DotShorthandPropertyAccess))
visitDottedName (method: R? Function(DottedName))
visitDoubleLiteral (method: R? Function(DoubleLiteral))
visitEmptyFunctionBody (method: R? Function(EmptyFunctionBody))
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 3d23bac..4023f85 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -92,6 +92,8 @@
DefaultFormalParameter,
Directive,
DoStatement,
+ DotShorthandInvocation,
+ DotShorthandPropertyAccess,
DottedName,
DoubleLiteral,
EmptyFunctionBody,
diff --git a/pkg/analyzer/lib/dart/ast/visitor.dart b/pkg/analyzer/lib/dart/ast/visitor.dart
index f15903c..72bf01e 100644
--- a/pkg/analyzer/lib/dart/ast/visitor.dart
+++ b/pkg/analyzer/lib/dart/ast/visitor.dart
@@ -280,6 +280,14 @@
R? visitDoStatement(DoStatement node) => visitStatement(node);
@override
+ R? visitDotShorthandInvocation(DotShorthandInvocation node) =>
+ visitExpression(node);
+
+ @override
+ R? visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) =>
+ visitExpression(node);
+
+ @override
R? visitDottedName(DottedName node) => visitNode(node);
@override
@@ -1036,6 +1044,18 @@
}
@override
+ R? visitDotShorthandInvocation(DotShorthandInvocation node) {
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
+ R? visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) {
+ node.visitChildren(this);
+ return null;
+ }
+
+ @override
R? visitDottedName(DottedName node) {
node.visitChildren(this);
return null;
@@ -1966,6 +1986,12 @@
R? visitDoStatement(DoStatement node) => null;
@override
+ R? visitDotShorthandInvocation(DotShorthandInvocation node) => null;
+
+ @override
+ R? visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) => null;
+
+ @override
R? visitDottedName(DottedName node) => null;
@override
@@ -2509,6 +2535,13 @@
R? visitDoStatement(DoStatement node) => _throw(node);
@override
+ R? visitDotShorthandInvocation(DotShorthandInvocation node) => _throw(node);
+
+ @override
+ R? visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) =>
+ _throw(node);
+
+ @override
R? visitDottedName(DottedName node) => _throw(node);
@override
@@ -3267,6 +3300,22 @@
}
@override
+ T? visitDotShorthandInvocation(DotShorthandInvocation node) {
+ stopwatch.start();
+ T? result = _baseVisitor.visitDotShorthandInvocation(node);
+ stopwatch.stop();
+ return result;
+ }
+
+ @override
+ T? visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) {
+ stopwatch.start();
+ T? result = _baseVisitor.visitDotShorthandPropertyAccess(node);
+ stopwatch.stop();
+ return result;
+ }
+
+ @override
T? visitDottedName(DottedName node) {
stopwatch.start();
T? result = _baseVisitor.visitDottedName(node);
@@ -4473,6 +4522,14 @@
R? visitDoStatement(DoStatement node) => visitNode(node);
@override
+ R? visitDotShorthandInvocation(DotShorthandInvocation node) =>
+ visitNode(node);
+
+ @override
+ R? visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) =>
+ visitNode(node);
+
+ @override
R? visitDottedName(DottedName node) => visitNode(node);
@override
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index d332b3d..514e064 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -1283,6 +1283,10 @@
R? visitDoStatement(DoStatement node);
+ R? visitDotShorthandInvocation(DotShorthandInvocation node);
+
+ R? visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node);
+
R? visitDottedName(DottedName node);
R? visitDoubleLiteral(DoubleLiteral node);
@@ -5392,6 +5396,140 @@
}
}
+/// A node that represents a dot shorthand static method or constructor
+/// invocation.
+///
+/// For example, `.parse('42')`.
+///
+/// dotShorthandHead ::=
+/// '.' [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
+@experimental
+@AnalyzerPublicApi(message: 'exported by lib/dart/ast/ast.dart')
+abstract final class DotShorthandInvocation extends InvocationExpression {
+ /// The name of the constructor or static method invocation.
+ SimpleIdentifier get memberName;
+
+ /// The token representing the period.
+ Token get period;
+}
+
+final class DotShorthandInvocationImpl extends InvocationExpressionImpl
+ implements DotShorthandInvocation {
+ @override
+ final Token period;
+
+ SimpleIdentifierImpl _memberName;
+
+ /// Initializes a newly created dot shorthand invocation.
+ DotShorthandInvocationImpl({
+ required this.period,
+ required SimpleIdentifierImpl memberName,
+ required super.typeArguments,
+ required super.argumentList,
+ }) : _memberName = memberName {
+ _becomeParentOf(_memberName);
+ }
+
+ @override
+ Token get beginToken => period;
+
+ @override
+ Token get endToken => argumentList.endToken;
+
+ @override
+ ExpressionImpl get function => memberName;
+
+ @override
+ SimpleIdentifierImpl get memberName => _memberName;
+
+ set memberName(SimpleIdentifierImpl identifier) {
+ _memberName = _becomeParentOf(identifier);
+ }
+
+ @override
+ Precedence get precedence => Precedence.postfix;
+
+ @override
+ ChildEntities get _childEntities => ChildEntities()
+ ..addToken('period', period)
+ ..addNode('memberName', memberName)
+ ..addNode('typeArguments', typeArguments)
+ ..addNode('argumentList', argumentList);
+
+ @override
+ E? accept<E>(AstVisitor<E> visitor) =>
+ visitor.visitDotShorthandInvocation(this);
+
+ @override
+ void resolveExpression(ResolverVisitor resolver, TypeImpl contextType) {
+ resolver.visitDotShorthandInvocation(this, contextType: contextType);
+ }
+
+ @override
+ void visitChildren(AstVisitor visitor) {
+ memberName.accept(visitor);
+ typeArguments?.accept(visitor);
+ argumentList.accept(visitor);
+ }
+}
+
+/// A node that represents a dot shorthand property access of a field or a
+/// static getter.
+///
+/// For example, `.zero`.
+///
+/// dotShorthandHead ::= '.' [SimpleIdentifier]
+@experimental
+@AnalyzerPublicApi(message: 'exported by lib/dart/ast/ast.dart')
+abstract final class DotShorthandPropertyAccess extends Expression {
+ /// The token representing the period.
+ Token get period;
+
+ /// The name of the property being accessed.
+ Token get propertyName;
+}
+
+final class DotShorthandPropertyAccessImpl extends ExpressionImpl
+ implements DotShorthandPropertyAccess {
+ @override
+ final Token period;
+
+ @override
+ final Token propertyName;
+
+ /// Initializes a newly created dot shorthand property access.
+ DotShorthandPropertyAccessImpl({
+ required this.period,
+ required this.propertyName,
+ });
+
+ @override
+ Token get beginToken => period;
+
+ @override
+ Token get endToken => propertyName;
+
+ @override
+ Precedence get precedence => Precedence.postfix;
+
+ @override
+ ChildEntities get _childEntities => ChildEntities()
+ ..addToken('period', period)
+ ..addToken('propertyName', propertyName);
+
+ @override
+ E? accept<E>(AstVisitor<E> visitor) =>
+ visitor.visitDotShorthandPropertyAccess(this);
+
+ @override
+ void resolveExpression(ResolverVisitor resolver, TypeImpl contextType) {
+ resolver.visitDotShorthandPropertyAccess(this, contextType: contextType);
+ }
+
+ @override
+ void visitChildren(AstVisitor visitor) {}
+}
+
/// A dotted name, used in a configuration within an import or export directive.
///
/// dottedName ::=
@@ -10838,8 +10976,8 @@
/// The invocation of a function or method.
///
-/// This will either be a [FunctionExpressionInvocation] or a
-/// [MethodInvocation].
+/// This will either be a [FunctionExpressionInvocation], [MethodInvocation],
+/// or a [DotShorthandInvocation].
@AnalyzerPublicApi(message: 'exported by lib/dart/ast/ast.dart')
abstract final class InvocationExpression implements Expression {
/// The list of arguments to the method.
diff --git a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
index cc60b8f..e018ca7 100644
--- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
@@ -349,6 +349,20 @@
}
@override
+ void visitDotShorthandInvocation(DotShorthandInvocation node) {
+ _visitToken(node.period);
+ _visitNode(node.memberName);
+ _visitNode(node.typeArguments);
+ _visitNode(node.argumentList);
+ }
+
+ @override
+ void visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) {
+ _visitToken(node.period);
+ _visitToken(node.propertyName);
+ }
+
+ @override
void visitDottedName(DottedName node) {
_visitNodeList(node.components, separator: '.');
}
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index 3157ea6a..1bec881 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -450,6 +450,22 @@
}
@override
+ bool? visitDotShorthandInvocation(DotShorthandInvocation node) {
+ DotShorthandInvocation other = _other as DotShorthandInvocation;
+ return isEqualTokens(node.period, other.period) &&
+ isEqualNodes(node.memberName, other.memberName) &&
+ isEqualNodes(node.typeArguments, other.typeArguments) &&
+ isEqualNodes(node.argumentList, other.argumentList);
+ }
+
+ @override
+ bool? visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) {
+ DotShorthandPropertyAccess other = _other as DotShorthandPropertyAccess;
+ return isEqualTokens(node.period, other.period) &&
+ isEqualTokens(node.propertyName, other.propertyName);
+ }
+
+ @override
bool visitDottedName(DottedName node) {
DottedName other = _other as DottedName;
return _isEqualNodeLists(node.components, other.components);
@@ -2371,6 +2387,26 @@
}
@override
+ bool? visitDotShorthandInvocation(covariant DotShorthandInvocationImpl node) {
+ if (identical(node.memberName, _oldNode)) {
+ node.memberName = _newNode as SimpleIdentifierImpl;
+ return true;
+ } else if (identical(node.typeArguments, _oldNode)) {
+ node.typeArguments = _newNode as TypeArgumentListImpl;
+ return true;
+ } else if (identical(node.argumentList, _oldNode)) {
+ node.argumentList = _newNode as ArgumentListImpl;
+ return true;
+ }
+ return visitNode(node);
+ }
+
+ @override
+ bool? visitDotShorthandPropertyAccess(
+ covariant DotShorthandPropertyAccessImpl node) =>
+ visitNode(node);
+
+ @override
bool visitDottedName(covariant DottedNameImpl node) {
if (_replaceInList(node.components)) {
return true;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index ffb3167..0a8912c 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -2280,6 +2280,18 @@
}
@override
+ void visitDotShorthandInvocation(DotShorthandInvocation node,
+ {TypeImpl contextType = UnknownInferredType.instance}) {
+ throw UnimplementedError('TODO(kallentu)');
+ }
+
+ @override
+ void visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node,
+ {TypeImpl contextType = UnknownInferredType.instance}) {
+ throw UnimplementedError('TODO(kallentu)');
+ }
+
+ @override
void visitDoubleLiteral(DoubleLiteral node,
{TypeImpl contextType = UnknownInferredType.instance}) {
inferenceLogWriter?.enterExpression(node, contextType);
diff --git a/pkg/analyzer/lib/src/lint/linter_visitor.dart b/pkg/analyzer/lib/src/lint/linter_visitor.dart
index 20cbe37..ac77c44 100644
--- a/pkg/analyzer/lib/src/lint/linter_visitor.dart
+++ b/pkg/analyzer/lib/src/lint/linter_visitor.dart
@@ -259,6 +259,18 @@
}
@override
+ void visitDotShorthandInvocation(DotShorthandInvocation node) {
+ _runSubscriptions(node, _registry._forDotShorthandInvocation);
+ node.visitChildren(this);
+ }
+
+ @override
+ void visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) {
+ _runSubscriptions(node, _registry._forDotShorthandPropertyAccess);
+ node.visitChildren(this);
+ }
+
+ @override
void visitDottedName(DottedName node) {
_runSubscriptions(node, _registry._forDottedName);
node.visitChildren(this);
@@ -1159,6 +1171,10 @@
final List<_Subscription<DefaultFormalParameter>> _forDefaultFormalParameter =
[];
final List<_Subscription<DoStatement>> _forDoStatement = [];
+ final List<_Subscription<DotShorthandInvocation>> _forDotShorthandInvocation =
+ [];
+ final List<_Subscription<DotShorthandPropertyAccess>>
+ _forDotShorthandPropertyAccess = [];
final List<_Subscription<DottedName>> _forDottedName = [];
final List<_Subscription<DoubleLiteral>> _forDoubleLiteral = [];
final List<_Subscription<EmptyFunctionBody>> _forEmptyFunctionBody = [];
@@ -1487,6 +1503,16 @@
_forDoStatement.add(_Subscription(rule, visitor, _getTimer(rule)));
}
+ void addDotShorthandInvocation(AnalysisRule rule, AstVisitor visitor) {
+ _forDotShorthandInvocation
+ .add(_Subscription(rule, visitor, _getTimer(rule)));
+ }
+
+ void addDotShorthandPropertyAccess(AnalysisRule rule, AstVisitor visitor) {
+ _forDotShorthandInvocation
+ .add(_Subscription(rule, visitor, _getTimer(rule)));
+ }
+
void addDottedName(AnalysisRule rule, AstVisitor visitor) {
_forDottedName.add(_Subscription(rule, visitor, _getTimer(rule)));
}