[analyzer] Report errors for final class and mixin subtyping outside of its library.
Change-Id: I7fbd0d0e36d360ce1a02cf7c4ecd6ccd2a29c999
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/280206
Commit-Queue: Kallen Tu <kallentu@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index f2a042d..57ef619 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -500,8 +500,16 @@
status: needsEvaluation
CompileTimeErrorCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE:
status: needsEvaluation
+CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY:
+ status: needsEvaluation
+CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY:
+ status: needsEvaluation
CompileTimeErrorCode.FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR:
status: needsEvaluation
+CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY:
+ status: needsEvaluation
+CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY:
+ status: needsEvaluation
CompileTimeErrorCode.FINAL_NOT_INITIALIZED:
status: hasFix
CompileTimeErrorCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1:
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index baae8df..f18a0df 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -1663,6 +1663,26 @@
);
/// Parameters:
+ /// 0: the name of the final class being extended.
+ static const CompileTimeErrorCode FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY =
+ CompileTimeErrorCode(
+ 'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+ "The class '{0}' can't be extended outside of its library because it's a "
+ "final class.",
+ uniqueName: 'FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY',
+ );
+
+ /// Parameters:
+ /// 0: the name of the final class being implemented.
+ static const CompileTimeErrorCode FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY =
+ CompileTimeErrorCode(
+ 'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+ "The class '{0}' can't be implemented outside of its library because it's "
+ "a final class.",
+ uniqueName: 'FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY',
+ );
+
+ /// Parameters:
/// 0: the name of the field in question
static const CompileTimeErrorCode
FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR = CompileTimeErrorCode(
@@ -1674,6 +1694,26 @@
);
/// Parameters:
+ /// 0: the name of the final mixin being implemented.
+ static const CompileTimeErrorCode FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY =
+ CompileTimeErrorCode(
+ 'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+ "The mixin '{0}' can't be implemented outside of its library because it's "
+ "a final mixin.",
+ uniqueName: 'FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY',
+ );
+
+ /// Parameters:
+ /// 0: the name of the final mixin being mixed in.
+ static const CompileTimeErrorCode FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY =
+ CompileTimeErrorCode(
+ 'INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY',
+ "The mixin '{0}' can't be mixed-in outside of its library because it's a "
+ "final mixin.",
+ uniqueName: 'FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY',
+ );
+
+ /// Parameters:
/// 0: the name of the uninitialized final variable
static const CompileTimeErrorCode FINAL_NOT_INITIALIZED =
CompileTimeErrorCode(
diff --git a/pkg/analyzer/lib/src/error/error_code_values.g.dart b/pkg/analyzer/lib/src/error/error_code_values.g.dart
index 9b25033..4be8d2b 100644
--- a/pkg/analyzer/lib/src/error/error_code_values.g.dart
+++ b/pkg/analyzer/lib/src/error/error_code_values.g.dart
@@ -193,7 +193,11 @@
CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR,
CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR,
CompileTimeErrorCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE,
+ CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY,
+ CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY,
CompileTimeErrorCode.FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR,
+ CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY,
+ CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY,
CompileTimeErrorCode.FINAL_NOT_INITIALIZED,
CompileTimeErrorCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1,
CompileTimeErrorCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2,
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 608db1f..2951de1 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1397,6 +1397,8 @@
_checkForBaseClassOrMixinImplementedOutsideOfLibrary(implementsClause);
_checkForInterfaceClassOrMixinSuperclassOutsideOfLibrary(
superclass, withClause);
+ _checkForFinalSupertypeOutsideOfLibrary(
+ superclass, withClause, implementsClause);
_checkForClassUsedAsMixin(withClause);
_checkForSealedSupertypeOutsideOfLibrary(
superclass, withClause, implementsClause);
@@ -2845,6 +2847,69 @@
}
}
+ /// Check that if a direct supertype of a node is final, then it must be in
+ /// the same library.
+ ///
+ /// See [CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY],
+ /// [CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY],
+ /// [CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY],
+ /// [CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY].
+ void _checkForFinalSupertypeOutsideOfLibrary(NamedType? superclass,
+ WithClause? withClause, ImplementsClause? implementsClause) {
+ if (superclass != null) {
+ final type = superclass.type;
+ if (type is InterfaceType) {
+ final element = type.element;
+ if (element is ClassElementImpl &&
+ element.isFinal &&
+ element.library != _currentLibrary) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY,
+ superclass,
+ [element.name]);
+ }
+ }
+ }
+ if (withClause != null) {
+ for (NamedType namedType in withClause.mixinTypes) {
+ final type = namedType.type;
+ if (type is InterfaceType) {
+ final element = type.element;
+ if (element is MixinElementImpl &&
+ element.isFinal &&
+ element.library != _currentLibrary) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY,
+ namedType,
+ [element.name]);
+ }
+ }
+ }
+ }
+ if (implementsClause != null) {
+ for (NamedType namedType in implementsClause.interfaces) {
+ final type = namedType.type;
+ if (type is InterfaceType) {
+ final element = type.element;
+ if (element is ClassOrMixinElementImpl &&
+ element.isFinal &&
+ element.library != _currentLibrary) {
+ final ErrorCode errorCode;
+ if (element is ClassElement) {
+ errorCode = CompileTimeErrorCode
+ .FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY;
+ } else {
+ errorCode = CompileTimeErrorCode
+ .FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY;
+ }
+ errorReporter
+ .reportErrorForNode(errorCode, namedType, [element.name]);
+ }
+ }
+ }
+ }
+ }
+
void _checkForGenericFunctionType(TypeAnnotation? node) {
if (node == null) {
return;
@@ -5164,6 +5229,7 @@
);
_checkForConflictingGenerics(node);
_checkForBaseClassOrMixinImplementedOutsideOfLibrary(implementsClause);
+ _checkForFinalSupertypeOutsideOfLibrary(null, null, implementsClause);
_checkForSealedSupertypeOutsideOfLibrary(null, null, implementsClause);
}
}
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 13bae56..2e9a042 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -5018,6 +5018,18 @@
C(String s) : f = int.parse(s);
}
```
+ FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY:
+ sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+ problemMessage: "The class '{0}' can't be extended outside of its library because it's a final class."
+ comment: |-
+ Parameters:
+ 0: the name of the final class being extended.
+ FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY:
+ sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+ problemMessage: "The class '{0}' can't be implemented outside of its library because it's a final class."
+ comment: |-
+ Parameters:
+ 0: the name of the final class being implemented.
FINAL_INITIALIZED_IN_DECLARATION_AND_CONSTRUCTOR:
problemMessage: "'{0}' is final and was given a value when it was declared, so it can't be set to a new value."
correctionMessage: Try removing one of the initializations.
@@ -5067,6 +5079,18 @@
C(this.f);
}
```
+ FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY:
+ sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+ problemMessage: "The mixin '{0}' can't be implemented outside of its library because it's a final mixin."
+ comment: |-
+ Parameters:
+ 0: the name of the final mixin being implemented.
+ FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY:
+ sharedName: INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
+ problemMessage: "The mixin '{0}' can't be mixed-in outside of its library because it's a final mixin."
+ comment: |-
+ Parameters:
+ 0: the name of the final mixin being mixed in.
FINAL_NOT_INITIALIZED:
problemMessage: "The final variable '{0}' must be initialized."
correctionMessage: Try initializing the variable.
diff --git a/pkg/analyzer/test/src/diagnostics/final_class_extended_outside_of_library_test.dart b/pkg/analyzer/test/src/diagnostics/final_class_extended_outside_of_library_test.dart
new file mode 100644
index 0000000..7aa3298
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/final_class_extended_outside_of_library_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2023, 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/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(FinalClassExtendedOutsideOfLibraryTest);
+ });
+}
+
+@reflectiveTest
+class FinalClassExtendedOutsideOfLibraryTest extends PubPackageResolutionTest {
+ test_inside() async {
+ await assertNoErrorsInCode(r'''
+final class Foo {}
+class Bar extends Foo {}
+''');
+ }
+
+ test_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+class Bar extends Foo {}
+''', [
+ error(
+ CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY, 37, 3),
+ ]);
+ }
+
+ test_outside_viaTypedef_inside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+typedef FooTypedef = Foo;
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+class Bar extends FooTypedef {}
+''', [
+ error(
+ CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY, 37, 10),
+ ]);
+ }
+
+ test_outside_viaTypedef_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+typedef FooTypedef = Foo;
+class Bar extends FooTypedef {}
+''', [
+ error(
+ CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY, 63, 10),
+ ]);
+ }
+
+ test_subtypeOfBase_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+class Bar extends Foo {}
+''');
+
+ await assertNoErrorsInCode(r'''
+import 'foo.dart';
+class Bar2 extends Bar {}
+''');
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/final_class_implemented_outside_of_library_test.dart b/pkg/analyzer/test/src/diagnostics/final_class_implemented_outside_of_library_test.dart
new file mode 100644
index 0000000..0fda9fa
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/final_class_implemented_outside_of_library_test.dart
@@ -0,0 +1,207 @@
+// Copyright (c) 2023, 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/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(FinalClassImplementedOutsideOfLibraryTest);
+ });
+}
+
+@reflectiveTest
+class FinalClassImplementedOutsideOfLibraryTest
+ extends PubPackageResolutionTest {
+ test_class_inside() async {
+ await assertNoErrorsInCode(r'''
+final class Foo {}
+class Bar implements Foo {}
+''');
+ }
+
+ test_class_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+class Bar implements Foo {}
+''', [
+ error(CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 40,
+ 3),
+ ]);
+ }
+
+ test_class_outside_viaTypedef_inside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+typedef FooTypedef = Foo;
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+class Bar implements FooTypedef {}
+''', [
+ error(CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 40,
+ 10),
+ ]);
+ }
+
+ test_class_outside_viaTypedef_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+typedef FooTypedef = Foo;
+class Bar implements FooTypedef {}
+''', [
+ error(CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 66,
+ 10),
+ ]);
+ }
+
+ test_class_subtypeOfFinal_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+class Bar implements Foo {}
+''');
+
+ await assertNoErrorsInCode(r'''
+import 'foo.dart';
+class Bar2 implements Bar {}
+''');
+ }
+
+ test_enum_inside() async {
+ await assertNoErrorsInCode(r'''
+final class Foo {}
+enum Bar implements Foo { bar }
+''');
+ }
+
+ test_enum_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+enum Bar implements Foo { bar }
+''', [
+ error(CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 39,
+ 3),
+ ]);
+ }
+
+ test_enum_outside_viaTypedef_inside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+typedef FooTypedef = Foo;
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+enum Bar implements FooTypedef { bar }
+''', [
+ error(CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 39,
+ 10),
+ ]);
+ }
+
+ test_enum_outside_viaTypedef_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+typedef FooTypedef = Foo;
+enum Bar implements FooTypedef { bar }
+''', [
+ error(CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 65,
+ 10),
+ ]);
+ }
+
+ test_enum_subtypeOfFinal_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+class Bar implements Foo {}
+''');
+
+ await assertNoErrorsInCode(r'''
+import 'foo.dart';
+enum Bar2 implements Bar { bar }
+''');
+ }
+
+ test_mixin_inside() async {
+ await assertNoErrorsInCode(r'''
+final class Foo {}
+mixin Bar implements Foo {}
+''');
+ }
+
+ test_mixin_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+mixin Bar implements Foo {}
+''', [
+ error(CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 40,
+ 3),
+ ]);
+ }
+
+ test_mixin_outside_viaTypedef_inside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+typedef FooTypedef = Foo;
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+mixin Bar implements FooTypedef {}
+''', [
+ error(CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 40,
+ 10),
+ ]);
+ }
+
+ test_mixin_outside_viaTypedef_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+typedef FooTypedef = Foo;
+mixin Bar implements FooTypedef {}
+''', [
+ error(CompileTimeErrorCode.FINAL_CLASS_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 66,
+ 10),
+ ]);
+ }
+
+ test_mixin_subtypeOfFinal_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final class Foo {}
+class Bar implements Foo {}
+''');
+
+ await assertNoErrorsInCode(r'''
+import 'foo.dart';
+mixin Bar2 implements Bar {}
+''');
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/final_mixin_implemented_outside_of_library_test.dart b/pkg/analyzer/test/src/diagnostics/final_mixin_implemented_outside_of_library_test.dart
new file mode 100644
index 0000000..23a7bb7
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/final_mixin_implemented_outside_of_library_test.dart
@@ -0,0 +1,207 @@
+// Copyright (c) 2023, 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/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(FinalMixinImplementedOutsideOfLibraryTest);
+ });
+}
+
+@reflectiveTest
+class FinalMixinImplementedOutsideOfLibraryTest
+ extends PubPackageResolutionTest {
+ test_class_inside() async {
+ await assertNoErrorsInCode(r'''
+final mixin Foo {}
+class Bar implements Foo {}
+''');
+ }
+
+ test_class_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+class Bar implements Foo {}
+''', [
+ error(CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 40,
+ 3),
+ ]);
+ }
+
+ test_class_outside_viaTypedef_inside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+typedef FooTypedef = Foo;
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+class Bar implements FooTypedef {}
+''', [
+ error(CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 40,
+ 10),
+ ]);
+ }
+
+ test_class_outside_viaTypedef_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+typedef FooTypedef = Foo;
+class Bar implements FooTypedef {}
+''', [
+ error(CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 66,
+ 10),
+ ]);
+ }
+
+ test_class_subtypeOfFinal_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+class Bar implements Foo {}
+''');
+
+ await assertNoErrorsInCode(r'''
+import 'foo.dart';
+class Bar2 implements Bar {}
+''');
+ }
+
+ test_enum_inside() async {
+ await assertNoErrorsInCode(r'''
+final mixin Foo {}
+enum Bar implements Foo { bar }
+''');
+ }
+
+ test_enum_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+enum Bar implements Foo { bar }
+''', [
+ error(CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 39,
+ 3),
+ ]);
+ }
+
+ test_enum_outside_viaTypedef_inside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+typedef FooTypedef = Foo;
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+enum Bar implements FooTypedef { bar }
+''', [
+ error(CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 39,
+ 10),
+ ]);
+ }
+
+ test_enum_outside_viaTypedef_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+typedef FooTypedef = Foo;
+enum Bar implements FooTypedef { bar }
+''', [
+ error(CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 65,
+ 10),
+ ]);
+ }
+
+ test_enum_subtypeOfFinal_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+class Bar implements Foo {}
+''');
+
+ await assertNoErrorsInCode(r'''
+import 'foo.dart';
+enum Bar2 implements Bar { bar }
+''');
+ }
+
+ test_mixin_inside() async {
+ await assertNoErrorsInCode(r'''
+final mixin Foo {}
+mixin Bar implements Foo {}
+''');
+ }
+
+ test_mixin_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+mixin Bar implements Foo {}
+''', [
+ error(CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 40,
+ 3),
+ ]);
+ }
+
+ test_mixin_outside_viaTypedef_inside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+typedef FooTypedef = Foo;
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+mixin Bar implements FooTypedef {}
+''', [
+ error(CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 40,
+ 10),
+ ]);
+ }
+
+ test_mixin_outside_viaTypedef_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+typedef FooTypedef = Foo;
+mixin Bar implements FooTypedef {}
+''', [
+ error(CompileTimeErrorCode.FINAL_MIXIN_IMPLEMENTED_OUTSIDE_OF_LIBRARY, 66,
+ 10),
+ ]);
+ }
+
+ test_mixin_subtypeOfFinal_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+class Bar implements Foo {}
+''');
+
+ await assertNoErrorsInCode(r'''
+import 'foo.dart';
+mixin Bar2 implements Bar {}
+''');
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/final_mixin_mixed_in_outside_of_library_test.dart b/pkg/analyzer/test/src/diagnostics/final_mixin_mixed_in_outside_of_library_test.dart
new file mode 100644
index 0000000..3c3b0d8
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/final_mixin_mixed_in_outside_of_library_test.dart
@@ -0,0 +1,131 @@
+// Copyright (c) 2023, 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/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(FinalMixinMixedInOutsideOfLibraryTest);
+ });
+}
+
+@reflectiveTest
+class FinalMixinMixedInOutsideOfLibraryTest extends PubPackageResolutionTest {
+ test_class_inside() async {
+ await assertNoErrorsInCode(r'''
+final mixin Foo {}
+class Bar with Foo {}
+''');
+ }
+
+ test_class_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+class Bar with Foo {}
+''', [
+ error(
+ CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY, 34, 3),
+ ]);
+ }
+
+ test_class_outside_viaTypedef_inside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+typedef FooTypedef = Foo;
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+class Bar with FooTypedef {}
+''', [
+ error(
+ CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY, 34, 10),
+ ]);
+ }
+
+ test_class_outside_viaTypedef_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+typedef FooTypedef = Foo;
+class Bar with FooTypedef {}
+''', [
+ error(
+ CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY, 60, 10),
+ ]);
+ }
+
+ test_class_subtypeOfBase_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+class Bar with Foo {}
+''');
+
+ await assertNoErrorsInCode(r'''
+import 'foo.dart';
+class Bar2 extends Bar {}
+''');
+ }
+
+ test_enum_inside() async {
+ await assertNoErrorsInCode(r'''
+final mixin Foo {}
+enum Bar with Foo { bar }
+''');
+ }
+
+ test_enum_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+enum Bar with Foo { bar }
+''', [
+ error(
+ CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY, 33, 3),
+ ]);
+ }
+
+ test_enum_outside_viaTypedef_inside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+typedef FooTypedef = Foo;
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+enum Bar with FooTypedef { bar }
+''', [
+ error(
+ CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY, 33, 10),
+ ]);
+ }
+
+ test_enum_outside_viaTypedef_outside() async {
+ newFile('$testPackageLibPath/foo.dart', r'''
+final mixin Foo {}
+''');
+
+ await assertErrorsInCode(r'''
+import 'foo.dart';
+typedef FooTypedef = Foo;
+enum Bar with FooTypedef { bar }
+''', [
+ error(
+ CompileTimeErrorCode.FINAL_MIXIN_MIXED_IN_OUTSIDE_OF_LIBRARY, 59, 10),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 3436aee..d3808fe 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -265,8 +265,16 @@
as field_initializing_formal_not_assignable;
import 'field_must_be_external_in_struct_test.dart'
as field_must_be_external_in_struct;
+import 'final_class_extended_outside_of_library_test.dart'
+ as final_class_extended_outside_of_library;
+import 'final_class_implemented_outside_of_library_test.dart'
+ as final_class_implemented_outside_of_library;
import 'final_initialized_in_declaration_and_constructor_test.dart'
as final_initialized_in_declaration_and_constructor;
+import 'final_mixin_implemented_outside_of_library_test.dart'
+ as final_mixin_implemented_outside_of_library;
+import 'final_mixin_mixed_in_outside_of_library_test.dart'
+ as final_mixin_mixed_in_outside_of_library;
import 'final_not_initialized_constructor_test.dart'
as final_not_initialized_constructor;
import 'final_not_initialized_test.dart' as final_not_initialized;
@@ -1032,6 +1040,10 @@
field_initializer_redirecting_constructor.main();
field_initializing_formal_not_assignable.main();
field_must_be_external_in_struct.main();
+ final_class_extended_outside_of_library.main();
+ final_class_implemented_outside_of_library.main();
+ final_mixin_implemented_outside_of_library.main();
+ final_mixin_mixed_in_outside_of_library.main();
final_not_initialized_constructor.main();
final_not_initialized.main();
for_in_of_invalid_element_type.main();
diff --git a/tests/language/class_modifiers/final/final_class_extend_outside_error_test.dart b/tests/language/class_modifiers/final/final_class_extend_outside_error_test.dart
index 035e333..61b0cce 100644
--- a/tests/language/class_modifiers/final/final_class_extend_outside_error_test.dart
+++ b/tests/language/class_modifiers/final/final_class_extend_outside_error_test.dart
@@ -9,12 +9,12 @@
import 'final_class_extend_lib.dart';
abstract class AOutside extends FinalClass {}
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
class BOutside extends FinalClass {
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
}
diff --git a/tests/language/class_modifiers/final/final_class_implement_outside_error_test.dart b/tests/language/class_modifiers/final/final_class_implement_outside_error_test.dart
index a846b74..efa88a9 100644
--- a/tests/language/class_modifiers/final/final_class_implement_outside_error_test.dart
+++ b/tests/language/class_modifiers/final/final_class_implement_outside_error_test.dart
@@ -9,13 +9,13 @@
import 'final_class_implement_lib.dart';
abstract class AOutside implements FinalClass {}
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
class BOutside implements FinalClass {
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
@override
int foo = 1;
diff --git a/tests/language/class_modifiers/final/final_class_typedef_subtype_error_test.dart b/tests/language/class_modifiers/final/final_class_typedef_subtype_error_test.dart
index 6865fdb..0fe24de 100644
--- a/tests/language/class_modifiers/final/final_class_typedef_subtype_error_test.dart
+++ b/tests/language/class_modifiers/final/final_class_typedef_subtype_error_test.dart
@@ -10,13 +10,13 @@
import 'final_class_typedef_lib.dart';
class ATypeDef extends FinalClassTypeDef {}
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
class BTypeDef implements FinalClassTypeDef {
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
@override
int foo = 1;
diff --git a/tests/language/class_modifiers/final/final_class_typedef_used_outside_error_test.dart b/tests/language/class_modifiers/final/final_class_typedef_used_outside_error_test.dart
index bc74010..617e292 100644
--- a/tests/language/class_modifiers/final/final_class_typedef_used_outside_error_test.dart
+++ b/tests/language/class_modifiers/final/final_class_typedef_used_outside_error_test.dart
@@ -13,13 +13,13 @@
typedef ATypeDef = FinalClass;
class A extends ATypeDef {}
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
class B implements ATypeDef {
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
int foo = 1;
}
diff --git a/tests/language/class_modifiers/final/final_mixin_implement_outside_error_test.dart b/tests/language/class_modifiers/final/final_mixin_implement_outside_error_test.dart
index b75e021..5a74768 100644
--- a/tests/language/class_modifiers/final/final_mixin_implement_outside_error_test.dart
+++ b/tests/language/class_modifiers/final/final_mixin_implement_outside_error_test.dart
@@ -9,13 +9,13 @@
import 'final_mixin_implement_lib.dart';
abstract class AOutside implements FinalMixin {}
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
class BOutside implements FinalMixin {
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
@override
int foo = 1;
diff --git a/tests/language/class_modifiers/final/final_mixin_typedef_with_outside_error_test.dart b/tests/language/class_modifiers/final/final_mixin_typedef_with_outside_error_test.dart
index 92276ad..d4acf8b 100644
--- a/tests/language/class_modifiers/final/final_mixin_typedef_with_outside_error_test.dart
+++ b/tests/language/class_modifiers/final/final_mixin_typedef_with_outside_error_test.dart
@@ -9,11 +9,11 @@
import 'final_mixin_typedef_with_lib.dart';
abstract class AOutside with FinalMixinTypeDef {}
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
class BOutside with FinalMixinTypeDef {}
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
diff --git a/tests/language/class_modifiers/final/final_mixin_with_outside_error_test.dart b/tests/language/class_modifiers/final/final_mixin_with_outside_error_test.dart
index c526040..0eb6367 100644
--- a/tests/language/class_modifiers/final/final_mixin_with_outside_error_test.dart
+++ b/tests/language/class_modifiers/final/final_mixin_with_outside_error_test.dart
@@ -9,11 +9,11 @@
import 'final_mixin_with_lib.dart';
abstract class AOutside with FinalMixin {}
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified
class BOutside with FinalMixin {}
-// ^
-// [analyzer] unspecified
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_USE_OF_TYPE_OUTSIDE_LIBRARY
// [cfe] unspecified