Version 2.14.0-281.0.dev

Merge commit '519786cc37d6fbc3eeebd7a1a8a770dbeae0d8c1' into 'dev'
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 802fa11..84260a2 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -12,7 +13,6 @@
 import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/dart/resolver/resolution_result.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 
@@ -83,35 +83,46 @@
     if (function is PrefixedIdentifierImpl) {
       var prefixElement =
           _resolver.nameScope.lookup(function.prefix.name).getter;
-      if (prefixElement is PrefixElement) {
-        _resolveReceiverPrefix(node, prefixElement, function);
-        return;
-      }
-
-      ResolutionResult resolveTypeProperty(DartType prefixType) {
-        return _resolver.typePropertyResolver.resolve(
-          receiver: function.prefix,
-          receiverType: prefixType,
-          name: function.identifier.name,
-          propertyErrorEntity: function.identifier,
-          nameErrorEntity: function,
-        );
-      }
-
       function.prefix.staticElement = prefixElement;
-      ExecutableElement? methodElement;
-      if (prefixElement is VariableElement) {
-        var prefixType = prefixElement.type;
-        function.prefix.staticType = prefixType;
-        methodElement = resolveTypeProperty(prefixType).getter;
+      if (prefixElement is PrefixElement) {
+        var functionName = function.identifier.name;
+        var functionElement = prefixElement.scope.lookup(functionName).getter;
+        if (functionElement == null) {
+          _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
+            function.identifier,
+            [function.identifier.name, function.prefix.name],
+          );
+          function.staticType = DynamicTypeImpl.instance;
+          node.staticType = DynamicTypeImpl.instance;
+          return;
+        } else {
+          functionElement = _resolver.toLegacyElement(functionElement);
+          _resolveReceiverPrefix(
+              node, prefixElement, function, functionElement);
+          return;
+        }
+      } else if (prefixElement is VariableElement) {
+        function.prefix.staticType = prefixElement.type;
       } else if (prefixElement is PropertyAccessorElement) {
-        var prefixType = prefixElement.returnType;
-        function.prefix.staticType = prefixType;
-        methodElement = resolveTypeProperty(prefixType).getter;
+        function.prefix.staticType = prefixElement.returnType;
       }
+
+      var methodElement = _resolveTypeProperty(
+        receiver: function.prefix,
+        receiverElement: prefixElement,
+        name: function.identifier,
+        nameErrorEntity: function,
+      );
+
       if (methodElement is MethodElement) {
-        _resolveFunctionReferenceMethod(
-            node: node, function: function, element: methodElement);
+        function.identifier.staticElement = methodElement;
+        function.staticType = methodElement.type;
+        _resolve(
+          node: node,
+          name: function.identifier.name,
+          rawType: methodElement.type,
+        );
         return;
       }
 
@@ -143,11 +154,39 @@
           node.staticType = DynamicTypeImpl.instance;
           return;
         }
+      } else if (target is PrefixedIdentifierImpl) {
+        var prefixElement =
+            _resolver.nameScope.lookup(target.prefix.name).getter;
+        if (prefixElement is PrefixElement) {
+          var prefixName = target.identifier.name;
+          var targetElement = prefixElement.scope.lookup(prefixName).getter;
+
+          var methodElement = _resolveTypeProperty(
+            receiver: target,
+            receiverElement: targetElement,
+            name: function.propertyName,
+            nameErrorEntity: function,
+          );
+
+          if (methodElement == null) {
+            // TODO(srawlins): Can we get here?
+            node.staticType = DynamicTypeImpl.instance;
+            return;
+          } else {
+            _resolveReceiverPrefix(node, prefixElement, target, methodElement);
+            return;
+          }
+        } else {
+          // TODO(srawlins): Can we get here?
+          node.staticType = DynamicTypeImpl.instance;
+          return;
+        }
       } else {
-        // TODO(srawlins): Can we get here? PrefixedIdentifier?
+        // TODO(srawlins): Can we get here?
         node.staticType = DynamicTypeImpl.instance;
         return;
       }
+
       var propertyElement = _resolver.typePropertyResolver
           .resolve(
             receiver: function.realTarget,
@@ -238,55 +277,14 @@
     _resolveTypeLiteral(node: node, instantiatedType: type, name: name);
   }
 
-  void _resolveFunctionReferenceMethod({
-    required FunctionReferenceImpl node,
-    required PrefixedIdentifier function,
-    required MethodElement element,
-  }) {
-    function.accept(_resolver);
-    var receiver = function.prefix;
-    var receiverType = receiver.staticType;
-    if (receiverType == null) {
-      // TODO(srawlins): Handle this situation; see
-      //  `test_staticMethod_explicitReceiver` test case.
-      node.staticType = DynamicTypeImpl.instance;
-      return;
-    }
-    var nameNode = function.identifier;
-    var name = nameNode.name;
-    var result = _resolver.typePropertyResolver.resolve(
-      receiver: receiver,
-      receiverType: receiverType,
-      name: name,
-      propertyErrorEntity: nameNode,
-      nameErrorEntity: nameNode,
-    );
-
-    var target = result.getter;
-    if (target != null) {
-      // TODO(srawlins): Set static type on `nameNode`?
-
-      _resolve(node: node, name: name, rawType: element.type);
-      return;
-    }
-
-    // TODO(srawlins): Report unresolved identifier.
-    node.function.accept(_resolver);
-    node.staticType = DynamicTypeImpl.instance;
-  }
-
   void _resolveReceiverPrefix(
     FunctionReferenceImpl node,
     PrefixElement prefixElement,
     PrefixedIdentifier prefix,
+    Element element,
   ) {
     // TODO(srawlins): Handle `loadLibrary`, as in `p.loadLibrary<int>;`.
 
-    var nameNode = prefix.identifier;
-    var name = nameNode.name;
-    var element = prefixElement.scope.lookup(name).getter;
-    element = _resolver.toLegacyElement(element);
-
     if (element is MultiplyDefinedElement) {
       MultiplyDefinedElement multiply = element;
       element = multiply.conflictingElements[0];
@@ -310,7 +308,6 @@
         return;
       } else if (element is TypeAliasElement) {
         prefix.accept(_resolver);
-        (nameNode as SimpleIdentifierImpl).staticElement = element;
         _resolveTypeAlias(node: node, element: element, typeAlias: prefix);
         return;
       }
@@ -326,10 +323,26 @@
 
     // TODO(srawlins): Report undefined prefixed identifier.
 
-    node.function.accept(_resolver);
     node.staticType = DynamicTypeImpl.instance;
   }
 
+  /// Returns the element that represents the property named [propertyName] on
+  /// [classElement].
+  ExecutableElement? _resolveStaticElement(
+      ClassElement classElement, SimpleIdentifier propertyName) {
+    String name = propertyName.name;
+    ExecutableElement? element;
+    if (propertyName.inSetterContext()) {
+      element = classElement.getSetter(name);
+    }
+    element ??= classElement.getGetter(name);
+    element ??= classElement.getMethod(name);
+    if (element != null && element.isAccessibleIn(_resolver.definingLibrary)) {
+      return element;
+    }
+    return null;
+  }
+
   void _resolveTypeAlias({
     required FunctionReferenceImpl node,
     required TypeAliasElement element,
@@ -358,4 +371,53 @@
     typeLiteral.staticType = _typeType;
     NodeReplacer.replace(node, typeLiteral);
   }
+
+  /// Resolves [name] as a property on [receiver] (with element
+  /// [receiverElement]).
+  ///
+  /// Returns `null` if [receiverElement] is `null`, a [TypeParameterElement],
+  /// or a [TypeAliasElement] for a non-interface type.
+  ExecutableElement? _resolveTypeProperty({
+    required Expression receiver,
+    required Element? receiverElement,
+    required SimpleIdentifier name,
+    required SyntacticEntity nameErrorEntity,
+  }) {
+    if (receiverElement == null) {
+      return null;
+    }
+    if (receiverElement is TypeParameterElement) {
+      return null;
+    }
+    if (receiverElement is ClassElement) {
+      return _resolveStaticElement(receiverElement, name);
+    } else if (receiverElement is TypeAliasElement) {
+      var aliasedType = receiverElement.aliasedType;
+      if (aliasedType is InterfaceType) {
+        return _resolveStaticElement(aliasedType.element, name);
+      } else {
+        return null;
+      }
+    }
+
+    DartType receiverType;
+    if (receiverElement is VariableElement) {
+      receiverType = receiverElement.type;
+    } else if (receiverElement is PropertyAccessorElement) {
+      receiverType = receiverElement.returnType;
+    } else {
+      assert(false,
+          'Unexpected receiverElement type: ${receiverElement.runtimeType}');
+      return null;
+    }
+    return _resolver.typePropertyResolver
+        .resolve(
+          receiver: receiver,
+          receiverType: receiverType,
+          name: name.name,
+          propertyErrorEntity: name,
+          nameErrorEntity: nameErrorEntity,
+        )
+        .getter;
+  }
 }
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 19e9a10..9922d73 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
@@ -142,16 +142,69 @@
         reference, findElement.method('foo'), 'void Function(int)');
   }
 
+  test_instanceMethod_explicitReceiver_topLevelVariable() async {
+    await assertNoErrorsInCode('''
+class A {
+  void foo<T>(T a) {}
+}
+var a = A();
+
+void bar() {
+  a.foo<int>;
+}
+''');
+
+    assertIdentifierTopGetRef(findNode.simple('a.'), 'a');
+    var reference = findNode.functionReference('foo<int>;');
+    assertFunctionReference(
+        reference, findElement.method('foo'), 'void Function(int)');
+  }
+
+  test_instanceMethod_explicitReceiver_topLevelVariable_prefix() async {
+    newFile('$testPackageLibPath/a.dart', content: '''
+class A {
+  void foo<T>(T a) {}
+}
+var a = A();
+''');
+    await assertNoErrorsInCode('''
+import 'a.dart' as prefix;
+
+bar() {
+  prefix.a.foo<int>;
+}
+''');
+
+    assertImportPrefix(
+        findNode.simple('prefix.'), findElement.prefix('prefix'));
+    var reference = findNode.functionReference('foo<int>;');
+    assertFunctionReference(
+        reference,
+        findElement.importFind('package:test/a.dart').method('foo'),
+        'void Function(int)');
+  }
+
+  test_instanceMethod_explicitReceiver_typeParameter() async {
+    await assertErrorsInCode('''
+bar<T>() {
+  T.foo<int>;
+}
+''', [
+      error(CompileTimeErrorCode.UNDEFINED_GETTER, 15, 3),
+    ]);
+
+    var reference = findNode.functionReference('foo<int>;');
+    assertType(reference, 'dynamic');
+  }
+
   test_instanceMethod_explicitReceiver_variable() async {
     await assertNoErrorsInCode('''
 class A {
   void foo<T>(T a) {}
 }
 
-class B {
-  bar(A a) {
-    a.foo<int>;
-  }
+bar(A a) {
+  a.foo<int>;
 }
 ''');
 
@@ -221,24 +274,23 @@
         reference, findElement.method('foo'), 'void Function(int)');
   }
 
-  @FailingTest(reason: 'Unresolved TODO in FunctionReferenceResolver')
   test_staticMethod_explicitReceiver() async {
     await assertNoErrorsInCode('''
 class A {
   static void foo<T>(T a) {}
+}
 
-  bar() {
-    A.foo<int>;
-  }
+bar() {
+  A.foo<int>;
 }
 ''');
 
+    assertClassRef(findNode.simple('A.'), findElement.class_('A'));
     var reference = findNode.functionReference('foo<int>;');
     assertElement(reference, findElement.method('foo'));
     assertType(reference, 'void Function(int)');
   }
 
-  @FailingTest(reason: 'Unresolved TODO in FunctionReferenceResolver')
   test_staticMethod_explicitReceiver_importPrefix() async {
     newFile('$testPackageLibPath/a.dart', content: '''
 class A {
@@ -253,9 +305,79 @@
 }
 ''');
 
+    assertImportPrefix(findNode.simple('a.A'), findElement.prefix('a'));
+    assertClassRef(findNode.simple('A.'),
+        findElement.importFind('package:test/a.dart').class_('A'));
     var reference = findNode.functionReference('foo<int>;');
-    assertElement(reference, findElement.method('foo'));
-    assertType(reference, 'void Function(int)');
+    assertFunctionReference(
+        reference,
+        findElement.importFind('package:test/a.dart').method('foo'),
+        'void Function(int)');
+  }
+
+  test_staticMethod_explicitReceiver_prefix_typeAlias() async {
+    newFile('$testPackageLibPath/a.dart', content: '''
+class A {
+  static void foo<T>(T a) {}
+}
+typedef TA = A;
+''');
+    await assertNoErrorsInCode('''
+import 'a.dart' as prefix;
+
+bar() {
+  prefix.TA.foo<int>;
+}
+''');
+
+    assertImportPrefix(
+        findNode.simple('prefix.'), findElement.prefix('prefix'));
+    var reference = findNode.functionReference('foo<int>;');
+    assertFunctionReference(
+        reference,
+        findElement.importFind('package:test/a.dart').method('foo'),
+        'void Function(int)');
+  }
+
+  test_staticMethod_explicitReceiver_typeAlias() async {
+    await assertNoErrorsInCode('''
+class A {
+  static void foo<T>(T a) {}
+}
+typedef TA = A;
+
+bar() {
+  TA.foo<int>;
+}
+''');
+
+    assertTypeAliasRef(findNode.simple('TA.'), findElement.typeAlias('TA'));
+    var reference = findNode.functionReference('foo<int>;');
+    assertFunctionReference(
+        reference, findElement.method('foo'), 'void Function(int)');
+  }
+
+  test_staticMethod_explicitReciver_prefix() async {
+    newFile('$testPackageLibPath/a.dart', content: '''
+class A {
+  static void foo<T>(T a) {}
+}
+''');
+    await assertNoErrorsInCode('''
+import 'a.dart' as prefix;
+
+bar() {
+  prefix.A.foo<int>;
+}
+''');
+
+    assertImportPrefix(
+        findNode.simple('prefix.'), findElement.prefix('prefix'));
+    var reference = findNode.functionReference('foo<int>;');
+    assertFunctionReference(
+        reference,
+        findElement.importFind('package:test/a.dart').method('foo'),
+        'void Function(int)');
   }
 
   test_tooFewTypeArguments() async {
@@ -322,6 +444,7 @@
 }
 ''');
 
+    assertImportPrefix(findNode.simple('a.f'), findElement.prefix('a'));
     var reference = findNode.functionReference('foo<int>;');
     assertFunctionReference(
       reference,
@@ -330,6 +453,32 @@
     );
   }
 
+  test_typeAlias_function_unknownProperty() async {
+    await assertErrorsInCode('''
+typedef Cb = void Function();
+
+var a = Cb.foo<int>;
+''', [
+      error(CompileTimeErrorCode.UNDEFINED_GETTER, 42, 3),
+    ]);
+
+    var reference = findNode.functionReference('foo<int>;');
+    assertType(reference, 'dynamic');
+  }
+
+  test_typeAlias_typeVariable_unknownProperty() async {
+    await assertErrorsInCode('''
+typedef T<E> = E;
+
+var a = T.foo<int>;
+''', [
+      error(CompileTimeErrorCode.UNDEFINED_GETTER, 29, 3),
+    ]);
+
+    var reference = findNode.functionReference('foo<int>;');
+    assertType(reference, 'dynamic');
+  }
+
   test_unknownIdentifier() async {
     await assertErrorsInCode('''
 void bar() {
diff --git a/tools/VERSION b/tools/VERSION
index 4c7f6cd..b582d9b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 280
+PRERELEASE 281
 PRERELEASE_PATCH 0
\ No newline at end of file