Fix reporting of INSTANCE_ACCESS_TO_STATIC_MEMBER from within an extension.

Previously, if a piece of code inside an extension tried erroneously
to refer to a static class member using instance access, the error
CompileTimeError.UNQUALIFIED_ACCESS_TO_STATIC_MEMBER_OF_EXTENDED_TYPE
would be reported.  This change corrects the error to
CompileTimeError.INSTANCE_ACCESS_TO_STATIC_MEMBER.

In addition, the responsibility to report the error
CompileTimeError.INSTANCE_ACCESS_TO_STATIC_MEMBER is shifted fully to
the resolver (previously, it was split between the resolver and the
error verifier).

Change-Id: Idcd1a3b8a1e226fed692900838c3d2d3c0585d4f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/217020
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@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 6ec3f7e..386da13 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart
@@ -149,19 +149,21 @@
     required bool implicitReceiver,
   }) {
     var enclosingElement = element.enclosingElement;
-    if (_resolver.enclosingExtension != null) {
-      _resolver.errorReporter.reportErrorForNode(
-        CompileTimeErrorCode
-            .UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
-        nameNode,
-        [enclosingElement.displayName],
-      );
-    } else if (implicitReceiver) {
-      _resolver.errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
-        nameNode,
-        [enclosingElement.displayName],
-      );
+    if (implicitReceiver) {
+      if (_resolver.enclosingExtension != null) {
+        _resolver.errorReporter.reportErrorForNode(
+          CompileTimeErrorCode
+              .UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
+          nameNode,
+          [enclosingElement.displayName],
+        );
+      } else {
+        _resolver.errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
+          nameNode,
+          [enclosingElement.displayName],
+        );
+      }
     } else {
       _resolver.errorReporter.reportErrorForNode(
         CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index 3d1d725..e75d2be 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -219,19 +219,21 @@
     bool nullReceiver,
   ) {
     var enclosingElement = element.enclosingElement;
-    if (_resolver.enclosingExtension != null) {
-      _resolver.errorReporter.reportErrorForNode(
-        CompileTimeErrorCode
-            .UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
-        nameNode,
-        [enclosingElement.displayName],
-      );
-    } else if (nullReceiver) {
-      _resolver.errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
-        nameNode,
-        [enclosingElement.displayName],
-      );
+    if (nullReceiver) {
+      if (_resolver.enclosingExtension != null) {
+        _resolver.errorReporter.reportErrorForNode(
+          CompileTimeErrorCode
+              .UNQUALIFIED_REFERENCE_TO_STATIC_MEMBER_OF_EXTENDED_TYPE,
+          nameNode,
+          [enclosingElement.displayName],
+        );
+      } else {
+        _resolver.errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNQUALIFIED_REFERENCE_TO_NON_LOCAL_STATIC_MEMBER,
+          nameNode,
+          [enclosingElement.displayName],
+        );
+      }
     } else {
       _resolver.errorReporter.reportErrorForNode(
         CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index e8f3c35..787d963 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -248,18 +248,6 @@
     );
   }
 
-  void _checkExtensionOverrideStaticMember(
-    SimpleIdentifier propertyName,
-    ExecutableElement? element,
-  ) {
-    if (element != null && element.isStatic) {
-      _errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
-        propertyName,
-      );
-    }
-  }
-
   /// If the [element] is not static, report the error on the [identifier].
   void _checkForStaticAccessToInstanceMember(
     SimpleIdentifier identifier,
@@ -274,6 +262,33 @@
     );
   }
 
+  void _checkForStaticMember(
+    Expression target,
+    SimpleIdentifier propertyName,
+    ExecutableElement? element,
+  ) {
+    if (element != null && element.isStatic) {
+      if (target is ExtensionOverride) {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
+          propertyName,
+        );
+      } else {
+        var enclosingElement = element.enclosingElement;
+        _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER,
+            propertyName, [
+          propertyName,
+          element.kind.displayName,
+          enclosingElement.name ?? '<unnamed>',
+          enclosingElement is ClassElement && enclosingElement.isMixin
+              ? 'mixin'
+              : enclosingElement.kind.displayName,
+        ]);
+      }
+    }
+  }
+
   DartType? _computeIndexContextType({
     required ExecutableElement? readElement,
     required ExecutableElement? writeElement,
@@ -417,21 +432,27 @@
         result.getter,
         result.getter?.returnType ?? _typeSystem.typeProvider.dynamicType);
 
-    if (hasRead && result.needsGetterError) {
-      _errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.UNDEFINED_GETTER,
-        propertyName,
-        [propertyName.name, targetType],
-      );
+    if (hasRead) {
+      _checkForStaticMember(target, propertyName, result.getter);
+      if (result.needsGetterError) {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNDEFINED_GETTER,
+          propertyName,
+          [propertyName.name, targetType],
+        );
+      }
     }
 
-    if (hasWrite && result.needsSetterError) {
-      AssignmentVerifier(_definingLibrary, _errorReporter).verify(
-        node: propertyName,
-        requested: null,
-        recovery: result.getter,
-        receiverTypeObject: targetType,
-      );
+    if (hasWrite) {
+      _checkForStaticMember(target, propertyName, result.setter);
+      if (result.needsSetterError) {
+        AssignmentVerifier(_definingLibrary, _errorReporter).verify(
+          node: propertyName,
+          requested: null,
+          recovery: result.getter,
+          receiverTypeObject: targetType,
+        );
+      }
     }
 
     return PropertyElementResolverResult(
@@ -591,7 +612,7 @@
           [memberName, element.name],
         );
       }
-      _checkExtensionOverrideStaticMember(propertyName, readElement);
+      _checkForStaticMember(target, propertyName, readElement);
     }
 
     ExecutableElement? writeElement;
@@ -604,7 +625,7 @@
           [memberName, element.name],
         );
       }
-      _checkExtensionOverrideStaticMember(propertyName, writeElement);
+      _checkForStaticMember(target, propertyName, writeElement);
     }
 
     return PropertyElementResolverResult(
@@ -670,6 +691,7 @@
 
         if (readElement != null) {
           readElement = _resolver.toLegacyElement(readElement);
+          _checkForStaticMember(target, propertyName, readElement);
         } else {
           // We were not able to find the concrete dispatch target.
           // But we would like to give the user at least some resolution.
@@ -708,6 +730,7 @@
 
         if (writeElement != null) {
           writeElement = _resolver.toLegacyElement(writeElement);
+          _checkForStaticMember(target, propertyName, writeElement);
         } else {
           // We were not able to find the concrete dispatch target.
           // But we would like to give the user at least some resolution.
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index a4f8ff7..2b6b30d 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -2658,15 +2658,6 @@
           return;
         }
       }
-      errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, name, [
-        name.name,
-        _getKind(element),
-        enclosingElement.name ?? '<unnamed>',
-        enclosingElement is ClassElement && enclosingElement.isMixin
-            ? 'mixin'
-            : enclosingElement.kind.displayName
-      ]);
     }
   }
 
@@ -4856,30 +4847,6 @@
     return null;
   }
 
-  /// Return a human-readable representation of the kind of the [element].
-  String _getKind(ExecutableElement element) {
-    if (element is MethodElement) {
-      return 'method';
-    } else if (element is PropertyAccessorElement) {
-      if (element.isSynthetic) {
-        PropertyInducingElement variable = element.variable;
-        if (variable is FieldElement) {
-          return 'field';
-        }
-        return 'variable';
-      } else if (element.isGetter) {
-        return 'getter';
-      } else {
-        return 'setter';
-      }
-    } else if (element is ConstructorElement) {
-      return 'constructor';
-    } else if (element is FunctionElement) {
-      return 'function';
-    }
-    return 'member';
-  }
-
   /// Return the name of the library that defines given [element].
   String _getLibraryName(Element? element) {
     if (element == null) {
diff --git a/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart b/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
index 470dbc7..1142a36 100644
--- a/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/instance_access_to_static_member_test.dart
@@ -98,6 +98,25 @@
     );
   }
 
+  test_extension_referring_to_class_member() async {
+    await assertErrorsInCode('''
+class C {
+  static void m() {}
+}
+extension on int {
+  foo(C c) {
+    c.m(); // ERROR
+  }
+}
+test(int i) {
+  i.foo(C());
+}
+''', [
+      error(CompileTimeErrorCode.INSTANCE_ACCESS_TO_STATIC_MEMBER, 71, 1,
+          correctionContains: "class 'C'"),
+    ]);
+  }
+
   test_extension_setter() async {
     await assertErrorsInCode('''
 class C {}
diff --git a/tests/language/getter/no_setter_test.dart b/tests/language/getter/no_setter_test.dart
index 260b5fc..6fa7014 100644
--- a/tests/language/getter/no_setter_test.dart
+++ b/tests/language/getter/no_setter_test.dart
@@ -15,7 +15,6 @@
 // [cfe] Setter not found: 'nextVar'.
     this.nextVar = 1;
     //   ^^^^^^^
-    // [analyzer] COMPILE_TIME_ERROR.INSTANCE_ACCESS_TO_STATIC_MEMBER
     // [cfe] The setter 'nextVar' isn't defined for the class 'Example'.
     //   ^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_NO_SETTER
@@ -30,8 +29,6 @@
 // [analyzer] COMPILE_TIME_ERROR.INVALID_REFERENCE_TO_THIS
 // [cfe] Expected identifier, but got 'this'.
 //       ^^^^^^^
-// [analyzer] COMPILE_TIME_ERROR.INSTANCE_ACCESS_TO_STATIC_MEMBER
-//       ^^^^^^^
 // [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_NO_SETTER
   }
 }
diff --git a/tests/language_2/getter/no_setter_test.dart b/tests/language_2/getter/no_setter_test.dart
index 02bc833..9690f56 100644
--- a/tests/language_2/getter/no_setter_test.dart
+++ b/tests/language_2/getter/no_setter_test.dart
@@ -17,7 +17,6 @@
 // [cfe] Setter not found: 'nextVar'.
     this.nextVar = 1;
     //   ^^^^^^^
-    // [analyzer] COMPILE_TIME_ERROR.INSTANCE_ACCESS_TO_STATIC_MEMBER
     // [cfe] The setter 'nextVar' isn't defined for the class 'Example'.
     //   ^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_NO_SETTER
@@ -32,8 +31,6 @@
 // [analyzer] COMPILE_TIME_ERROR.INVALID_REFERENCE_TO_THIS
 // [cfe] Expected identifier, but got 'this'.
 //       ^^^^^^^
-// [analyzer] COMPILE_TIME_ERROR.INSTANCE_ACCESS_TO_STATIC_MEMBER
-//       ^^^^^^^
 // [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_FINAL_NO_SETTER
   }
 }