[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)));
   }