Resolve Class.staticGetter<A> as ImplicitCallReference.

Change-Id: I66e6f4005d4adc24355da5a17089c98032552d39
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/233961
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
index cf14dd4..0aa5a1e 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
@@ -453,22 +453,26 @@
       return;
     }
 
-    var functionType = _resolveTypeProperty(
+    var propertyType = _resolveTypeProperty(
       receiver: function.prefix,
       name: function.identifier,
       nameErrorEntity: function,
     );
 
-    if (functionType != null) {
-      if (functionType is FunctionType) {
-        function.staticType = functionType;
-        _resolve(
-          node: node,
-          rawType: functionType,
-          name: functionName,
-        );
-        return;
-      }
+    var callMethod = _getCallMethod(node, propertyType);
+    if (callMethod is MethodElement) {
+      _resolveAsImplicitCallReference(node, callMethod);
+      return;
+    }
+
+    if (propertyType is FunctionType) {
+      function.staticType = propertyType;
+      _resolve(
+        node: node,
+        rawType: propertyType,
+        name: functionName,
+      );
+      return;
     }
 
     function.accept(_resolver);
@@ -823,17 +827,13 @@
       if (receiverElement is ClassElement) {
         var element = _resolveStaticElement(receiverElement, name);
         name.staticElement = element;
-        // TODO(srawlins): Should this use referenceType? E.g. if `element`
-        // is a function-typed static getter.
-        return element?.type;
+        return element?.referenceType;
       } else if (receiverElement is TypeAliasElement) {
         var aliasedType = receiverElement.aliasedType;
         if (aliasedType is InterfaceType) {
           var element = _resolveStaticElement(aliasedType.element, name);
           name.staticElement = element;
-          // TODO(srawlins): Should this use referenceType? E.g. if `element`
-          // is a function-typed static getter.
-          return element?.type;
+          return element?.referenceType;
         } else {
           return null;
         }
diff --git a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
index 3456bd6..a5d8a32 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
@@ -1723,6 +1723,51 @@
         findElement.method('call'), 'int Function(int)');
   }
 
+  test_implicitCallTearoff_class_staticGetter() async {
+    await assertNoErrorsInCode('''
+class C {
+  static const v = C();
+  const C();
+  T call<T>(T t) => t;
+}
+
+void f() {
+  C.v<int>;
+}
+''');
+
+    var node = findNode.implicitCallReference('C.v<int>');
+    assertResolvedNodeText(node, r'''
+ImplicitCallReference
+  expression: PrefixedIdentifier
+    prefix: SimpleIdentifier
+      token: C
+      staticElement: self::@class::C
+      staticType: null
+    period: .
+    identifier: SimpleIdentifier
+      token: v
+      staticElement: self::@class::C::@getter::v
+      staticType: null
+    staticElement: self::@class::C::@getter::v
+    staticType: null
+  typeArguments: TypeArgumentList
+    leftBracket: <
+    arguments
+      NamedType
+        name: SimpleIdentifier
+          token: int
+          staticElement: dart:core::@class::int
+          staticType: null
+        type: int
+    rightBracket: >
+  staticElement: self::@class::C::@method::call
+  staticType: int Function(int)
+  typeArgumentTypes
+    int
+''');
+  }
+
   test_implicitCallTearoff_extensionOnNullable() async {
     await assertNoErrorsInCode('''
 Object? v = null;
@@ -1741,6 +1786,62 @@
         'void Function(int, String)');
   }
 
+  test_implicitCallTearoff_prefix_class_staticGetter() async {
+    newFile('$testPackageLibPath/a.dart', content: r'''
+class C {
+  static const v = C();
+  const C();
+  T call<T>(T t) => t;
+}
+''');
+
+    await assertNoErrorsInCode('''
+import 'a.dart' as prefix;
+
+void f() {
+  prefix.C.v<int>;
+}
+''');
+
+    var node = findNode.implicitCallReference('C.v<int>');
+    assertResolvedNodeText(node, r'''
+ImplicitCallReference
+  expression: PropertyAccess
+    target: PrefixedIdentifier
+      prefix: SimpleIdentifier
+        token: prefix
+        staticElement: self::@prefix::prefix
+        staticType: null
+      period: .
+      identifier: SimpleIdentifier
+        token: C
+        staticElement: package:test/a.dart::@class::C
+        staticType: null
+      staticElement: package:test/a.dart::@class::C
+      staticType: null
+    operator: .
+    propertyName: SimpleIdentifier
+      token: v
+      staticElement: package:test/a.dart::@class::C::@getter::v
+      staticType: C
+    staticType: C
+  typeArguments: TypeArgumentList
+    leftBracket: <
+    arguments
+      NamedType
+        name: SimpleIdentifier
+          token: int
+          staticElement: dart:core::@class::int
+          staticType: null
+        type: int
+    rightBracket: >
+  staticElement: package:test/a.dart::@class::C::@method::call
+  staticType: int Function(int)
+  typeArgumentTypes
+    int
+''');
+  }
+
   test_implicitCallTearoff_prefixed() async {
     newFile('$testPackageLibPath/a.dart', content: '''
 class C {
diff --git a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
index 8978bb1..107d0d6 100644
--- a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
+++ b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
@@ -684,6 +684,7 @@
     _writeln('ImplicitCallReference');
     _withIndent(() {
       _writeNamedChildEntities(node);
+      _writeElement('staticElement', node.staticElement);
       _writeType('staticType', node.staticType);
       _writeTypeList('typeArgumentTypes', node.typeArgumentTypes);
     });
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index bc151cc..9e41564 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -21963,6 +21963,7 @@
                         token: c @68
                         staticElement: c@52
                         staticType: C
+                      staticElement: self::@class::C::@method::call
                       staticType: void Function()
                   rightParenthesis: ) @69
                 staticElement: self::@class::D::@constructor::named