analyzer: Reduce redundant errors with invalid covariant use

Fixes https://github.com/dart-lang/sdk/issues/47248

Change-Id: I75c4a1e4fcb6cb26fbc8a6aa54e62b740e264783
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/218782
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index b53caa5..ffac3f2 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -4750,12 +4750,27 @@
 
   void _checkUseOfCovariantInParameters(FormalParameterList node) {
     var parent = node.parent;
-    if (_enclosingClass != null &&
-        parent is MethodDeclaration &&
-        !parent.isStatic) {
+    if (_enclosingClass != null && parent is MethodDeclaration) {
+      // Either [parent] is a static method, in which case `EXTRANEOUS_MODIFIER`
+      // is reported by the parser, or [parent] is an instance method, in which
+      // case any use of `covariant` is legal.
       return;
     }
 
+    if (_enclosingExtension != null) {
+      // `INVALID_USE_OF_COVARIANT_IN_EXTENSION` is reported by the parser.
+      return;
+    }
+
+    if (parent is FunctionExpression) {
+      var parent2 = parent.parent;
+      if (parent2 is FunctionDeclaration && parent2.parent is CompilationUnit) {
+        // `EXTRANEOUS_MODIFIER` is reported by the parser, for library-level
+        // functions.
+        return;
+      }
+    }
+
     NodeList<FormalParameter> parameters = node.parameters;
     int length = parameters.length;
     for (int i = 0; i < length; i++) {
@@ -4765,14 +4780,10 @@
       }
       var keyword = parameter.covariantKeyword;
       if (keyword != null) {
-        if (_enclosingExtension != null) {
-          // Reported by the parser.
-        } else {
-          errorReporter.reportErrorForToken(
-            CompileTimeErrorCode.INVALID_USE_OF_COVARIANT,
-            keyword,
-          );
-        }
+        errorReporter.reportErrorForToken(
+          CompileTimeErrorCode.INVALID_USE_OF_COVARIANT,
+          keyword,
+        );
       }
     }
   }
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_covariant_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_covariant_test.dart
new file mode 100644
index 0000000..20b7d5c
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_covariant_test.dart
@@ -0,0 +1,121 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/dart/error/hint_codes.g.dart';
+import 'package:analyzer/src/error/codes.g.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InvalidUseOfCovariantTest);
+  });
+}
+
+@reflectiveTest
+class InvalidUseOfCovariantTest extends PubPackageResolutionTest {
+  test_functionExpression() async {
+    await assertErrorsInCode('''
+Function f = (covariant int x) {};
+''', [
+      error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT, 14, 9),
+    ]);
+  }
+
+  test_functionType_inFunctionTypedParameterOfInstanceMethod() async {
+    await assertErrorsInCode('''
+class C {
+  void m(void p(covariant int)) {}
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT, 26, 9),
+    ]);
+  }
+
+  test_functionType_inParameterOfInstanceMethod() async {
+    await assertErrorsInCode('''
+class C {
+  void m(void Function(covariant int) p) {}
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT, 33, 9),
+    ]);
+  }
+
+  test_functionType_inTypeAlias() async {
+    await assertErrorsInCode('''
+typedef F = void Function(covariant int);
+''', [
+      error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT, 26, 9),
+    ]);
+  }
+
+  test_functionType_inTypeArgument() async {
+    await assertErrorsInCode('''
+List<void Function(covariant int)> a = [];
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT, 19, 9),
+      // TODO(srawlins): Recover better from this situation (`covariant` in
+      // parameter in type argument).
+      error(ParserErrorCode.EXPECTED_EXECUTABLE, 43, 1),
+    ]);
+  }
+
+  test_functionType_inTypeParameterBound() async {
+    await assertErrorsInCode('''
+void foo<T extends void Function(covariant int)>() {}
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT, 33, 9),
+      // TODO(srawlins): Recover better from this situation (`covariant` in
+      // parameter in bound).
+      error(ParserErrorCode.EXPECTED_EXECUTABLE, 54, 1),
+    ]);
+  }
+
+  test_localFunction() async {
+    await assertErrorsInCode('''
+void foo() {
+  void f(covariant int x) {}
+}
+''', [
+      error(HintCode.UNUSED_ELEMENT, 20, 1),
+      error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT, 22, 9),
+    ]);
+  }
+
+  test_staticFunction() async {
+    await assertErrorsInCode('''
+class C {
+  static void m(covariant int x) {}
+}
+''', [
+      // INVALID_USE_OF_COVARIANT is not reported here; it would be redundant.
+      error(ParserErrorCode.EXTRANEOUS_MODIFIER, 26, 9),
+    ]);
+  }
+
+  test_staticFunction_onMixin() async {
+    await assertErrorsInCode('''
+mixin M {
+  static void m(covariant int x) {}
+}
+''', [
+      // INVALID_USE_OF_COVARIANT is not reported here; it would be redundant.
+      error(ParserErrorCode.EXTRANEOUS_MODIFIER, 26, 9),
+    ]);
+  }
+
+  test_topLevelFunction() async {
+    await assertErrorsInCode('''
+void f(covariant int x) {}
+''', [
+      // INVALID_USE_OF_COVARIANT is not reported here; it would be redundant.
+      error(ParserErrorCode.EXTRANEOUS_MODIFIER, 7, 9),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 263958a..3d245fa 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -354,6 +354,7 @@
 import 'invalid_uri_test.dart' as invalid_uri;
 import 'invalid_use_of_covariant_in_extension_test.dart'
     as invalid_use_of_covariant_in_extension;
+import 'invalid_use_of_covariant_test.dart' as invalid_use_of_covariant;
 import 'invalid_use_of_internal_member_test.dart'
     as invalid_use_of_internal_member;
 import 'invalid_use_of_protected_member_test.dart'
@@ -951,6 +952,7 @@
     invalid_type_argument_in_const_map.main();
     invalid_type_argument_in_const_set.main();
     invalid_uri.main();
+    invalid_use_of_covariant.main();
     invalid_use_of_covariant_in_extension.main();
     invalid_use_of_internal_member.main();
     invalid_use_of_protected_member.main();