From 919eb05b27970ce993677f326fddf8bb8d9cc024 Mon Sep 17 00:00:00 2001 From: Kallen Tu Date: Thu, 9 Mar 2023 18:09:34 +0000 Subject: [PATCH] [analyzer] Avoid reporting subtype modifier errors on final supertypes outside of library. Change-Id: If4fba1c08d7dc9d4f65ea56760298e47c65742fa Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287340 Reviewed-by: Konstantin Shcheglov Reviewed-by: Brian Wilkerson Commit-Queue: Kallen Tu --- .../services/correction/error_fix_status.yaml | 4 +- ...ove_name_from_declaration_clause_test.dart | 33 +- .../error/base_or_final_type_verifier.dart | 77 ++- pkg/analyzer/lib/src/error/codes.g.dart | 20 +- .../lib/src/error/error_code_values.g.dart | 3 +- pkg/analyzer/messages.yaml | 15 +- .../extends_disallowed_class_test.dart | 25 - .../implements_disallowed_class_test.dart | 35 -- .../mixin_of_disallowed_class_test.dart | 25 - ...lass_constraint_disallowed_class_test.dart | 7 +- ...base_is_not_base_final_or_sealed_test.dart | 352 +++++++++++ ...inal_is_not_base_final_or_sealed_test.dart | 572 ------------------ ...inal_is_not_base_final_or_sealed_test.dart | 241 ++++++++ .../test/src/diagnostics/test_all.dart | 9 +- 14 files changed, 691 insertions(+), 727 deletions(-) create mode 100644 pkg/analyzer/test/src/diagnostics/subtype_of_base_is_not_base_final_or_sealed_test.dart delete mode 100644 pkg/analyzer/test/src/diagnostics/subtype_of_base_or_final_is_not_base_final_or_sealed_test.dart create mode 100644 pkg/analyzer/test/src/diagnostics/subtype_of_final_is_not_base_final_or_sealed_test.dart 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 2768abf3a99..5b879f8f094 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 @@ -1059,7 +1059,9 @@ CompileTimeErrorCode.SPREAD_EXPRESSION_FROM_DEFERRED_LIBRARY: status: needsEvaluation CompileTimeErrorCode.STATIC_ACCESS_TO_INSTANCE_MEMBER: status: needsEvaluation -CompileTimeErrorCode.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED: +CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED: + status: needsEvaluation +CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED: status: needsEvaluation CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_TYPE_IS_NOT_SUBTYPE_OF_ASSOCIATED: status: hasFix diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_name_from_declaration_clause_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_name_from_declaration_clause_test.dart index c5a5374ce5b..39a06b37dcf 100644 --- a/pkg/analysis_server/test/src/services/correction/fix/remove_name_from_declaration_clause_test.dart +++ b/pkg/analysis_server/test/src/services/correction/fix/remove_name_from_declaration_clause_test.dart @@ -4,7 +4,6 @@ import 'package:analysis_server/src/services/correction/fix.dart'; import 'package:analyzer/src/dart/error/ffi_code.g.dart'; -import 'package:analyzer/src/error/codes.dart'; import 'package:analyzer_plugin/utilities/fixes/fixes.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; @@ -55,13 +54,9 @@ class ExtendsDisallowedClassTest extends FixProcessorTest { await resolveTestCode(''' class C extends String {} '''); - await assertHasFix( - ''' + await assertHasFix(''' class C {} -''', - errorFilter: (error) => - error.errorCode == CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS, - ); +'''); } } @@ -106,26 +101,18 @@ class ImplementsDisallowedClassTest extends FixProcessorTest { await resolveTestCode(''' class C implements String {} '''); - await assertHasFix( - ''' + await assertHasFix(''' class C {} -''', - errorFilter: (error) => - error.errorCode == CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, - ); +'''); } Future test_twoNames() async { await resolveTestCode(''' abstract class C implements String, List {} '''); - await assertHasFix( - ''' + await assertHasFix(''' abstract class C implements List {} -''', - errorFilter: (error) => - error.errorCode == CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, - ); +'''); } } @@ -189,13 +176,9 @@ class MixinOfDisallowedClassTest extends FixProcessorTest { await resolveTestCode(''' abstract class C with String {} '''); - await assertHasFix( - ''' + await assertHasFix(''' abstract class C {} -''', - errorFilter: (error) => - error.errorCode == CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, - ); +'''); } } diff --git a/pkg/analyzer/lib/src/error/base_or_final_type_verifier.dart b/pkg/analyzer/lib/src/error/base_or_final_type_verifier.dart index 0fd681b7291..07bbd55ff95 100644 --- a/pkg/analyzer/lib/src/error/base_or_final_type_verifier.dart +++ b/pkg/analyzer/lib/src/error/base_or_final_type_verifier.dart @@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'package:analyzer/dart/analysis/features.dart'; -import 'package:analyzer/dart/ast/token.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/diagnostic/diagnostic.dart'; @@ -11,7 +10,6 @@ import 'package:analyzer/error/listener.dart'; import 'package:analyzer/src/dart/element/element.dart'; import 'package:analyzer/src/diagnostic/diagnostic.dart'; import 'package:analyzer/src/error/codes.dart'; -import 'package:analyzer/src/utilities/extensions/collection.dart'; /// Helper for verifying that subelements of a base or final element must be /// base, final, or sealed. @@ -33,8 +31,8 @@ class BaseOrFinalTypeVerifier { /// Check to ensure the subelement of a base or final element must be base, /// final, or sealed. Otherwise, an error is reported on that element. /// - /// See [CompileTimeErrorCode. - /// SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED] + /// See [CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED], + /// [CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED] void checkElement(ClassOrMixinElementImpl element) { if (_elementToBaseOrFinalSuperElement.containsKey(element)) { // We've already visited this element. Don't check it again. @@ -43,14 +41,29 @@ class BaseOrFinalTypeVerifier { _elementToBaseOrFinalSuperElement[element] = null; } - List supertypes = []; - supertypes.addIfNotNull(element.supertype); - supertypes.addAll(element.interfaces); - supertypes.addAll(element.mixins); - if (element is MixinElementImpl) { - supertypes.addAll(element.superclassConstraints); + final supertype = element.supertype; + if (supertype != null && _checkSupertypes([supertype], element)) { + return; } + if (_checkSupertypes(element.interfaces, element)) { + return; + } + if (_checkSupertypes(element.mixins, element)) { + return; + } + if (_checkSupertypes(element.interfaces, element)) { + return; + } + if (element is MixinElementImpl && + _checkSupertypes(element.superclassConstraints, element, + areSuperclassConstraints: true)) { + return; + } + } + bool _checkSupertypes( + List supertypes, ClassOrMixinElementImpl subElement, + {bool areSuperclassConstraints = false}) { for (final supertype in supertypes) { final supertypeElement = supertype.element; if (supertypeElement is ClassOrMixinElementImpl) { @@ -60,11 +73,13 @@ class BaseOrFinalTypeVerifier { // Return early if an error has been reported to prevent reporting // multiple errors on one element. - if (_reportRestrictionError(element, supertypeElement)) { - return; + if (_reportRestrictionError(subElement, supertypeElement, + isSuperclassConstraint: areSuperclassConstraints)) { + return true; } } } + return false; } /// Checks whether a `final`, `base` or `interface` modifier can be ignored. @@ -91,7 +106,8 @@ class BaseOrFinalTypeVerifier { /// /// Reports an error based on the modifier of the superElement. bool _reportRestrictionError( - ClassOrMixinElementImpl element, ClassOrMixinElementImpl superElement) { + ClassOrMixinElementImpl element, ClassOrMixinElementImpl superElement, + {bool isSuperclassConstraint = false}) { final cachedBaseOrFinalSuperElement = _elementToBaseOrFinalSuperElement[superElement]; final hasCachedBaseOrFinalSuperElement = @@ -133,19 +149,28 @@ class BaseOrFinalTypeVerifier { ) ]; - _errorReporter.reportErrorForElement( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - element, - [ - element.displayName, - baseOrFinalSuperElement.displayName, - baseOrFinalSuperElement.isBase - ? Keyword.BASE.lexeme - : Keyword.FINAL.lexeme - ], - hasCachedBaseOrFinalSuperElement ? contextMessage : null); - return true; + if (baseOrFinalSuperElement.isFinal) { + if (!isSuperclassConstraint && + baseOrFinalSuperElement.library != element.library) { + // If you can't extend, implement or mix in a final element outside of + // its library anyways, it's not helpful to report a subelement + // modifier error. + return false; + } + _errorReporter.reportErrorForElement( + CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + element, + [element.displayName, baseOrFinalSuperElement.displayName], + hasCachedBaseOrFinalSuperElement ? contextMessage : null); + return true; + } else if (baseOrFinalSuperElement.isBase) { + _errorReporter.reportErrorForElement( + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + element, + [element.displayName, baseOrFinalSuperElement.displayName], + hasCachedBaseOrFinalSuperElement ? contextMessage : null); + return true; + } } return false; diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart index c2e023a802a..995adf9f1aa 100644 --- a/pkg/analyzer/lib/src/error/codes.g.dart +++ b/pkg/analyzer/lib/src/error/codes.g.dart @@ -4449,14 +4449,24 @@ class CompileTimeErrorCode extends AnalyzerErrorCode { /// Parameters: /// 0: the name of the subtype that is not 'base', 'final', or 'sealed' - /// 1: the name of the supertype which is 'base' or 'final' - /// 2: the modifier on the supertype + /// 1: the name of the 'base' supertype static const CompileTimeErrorCode - SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED = - CompileTimeErrorCode( + SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED = CompileTimeErrorCode( 'SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED', "The type '{0}' must be 'base', 'final' or 'sealed' because the supertype " - "'{1}' is '{2}'.", + "'{1}' is 'base'.", + uniqueName: 'SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED', + ); + + /// Parameters: + /// 0: the name of the subtype that is not 'base', 'final', or 'sealed' + /// 1: the name of the 'final' supertype + static const CompileTimeErrorCode + SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED = CompileTimeErrorCode( + 'SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED', + "The type '{0}' must be 'base', 'final' or 'sealed' because the supertype " + "'{1}' is 'final'.", + uniqueName: 'SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED', ); /// Parameters: 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 b34542a0528..67325cb8c5b 100644 --- a/pkg/analyzer/lib/src/error/error_code_values.g.dart +++ b/pkg/analyzer/lib/src/error/error_code_values.g.dart @@ -451,7 +451,8 @@ const List errorCodeValues = [ CompileTimeErrorCode.SHARED_DEFERRED_PREFIX, CompileTimeErrorCode.SPREAD_EXPRESSION_FROM_DEFERRED_LIBRARY, CompileTimeErrorCode.STATIC_ACCESS_TO_INSTANCE_MEMBER, - CompileTimeErrorCode.SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_TYPE_IS_NOT_SUBTYPE_OF_ASSOCIATED, CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_NAMED, CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_POSITIONAL, diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml index 49eff931bbb..9ada969e96b 100644 --- a/pkg/analyzer/messages.yaml +++ b/pkg/analyzer/messages.yaml @@ -12902,13 +12902,20 @@ CompileTimeErrorCode: int f(C c) => c.b; ``` - SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED: - problemMessage: "The type '{0}' must be 'base', 'final' or 'sealed' because the supertype '{1}' is '{2}'." + SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED: + sharedName: SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED + problemMessage: "The type '{0}' must be 'base', 'final' or 'sealed' because the supertype '{1}' is 'base'." comment: |- Parameters: 0: the name of the subtype that is not 'base', 'final', or 'sealed' - 1: the name of the supertype which is 'base' or 'final' - 2: the modifier on the supertype + 1: the name of the 'base' supertype + SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED: + sharedName: SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED + problemMessage: "The type '{0}' must be 'base', 'final' or 'sealed' because the supertype '{1}' is 'final'." + comment: |- + Parameters: + 0: the name of the subtype that is not 'base', 'final', or 'sealed' + 1: the name of the 'final' supertype SUPER_FORMAL_PARAMETER_TYPE_IS_NOT_SUBTYPE_OF_ASSOCIATED: problemMessage: The type '{0}' of this parameter isn't a subtype of the type '{1}' of the associated super constructor parameter. correctionMessage: Try removing the explicit type annotation from the parameter. diff --git a/pkg/analyzer/test/src/diagnostics/extends_disallowed_class_test.dart b/pkg/analyzer/test/src/diagnostics/extends_disallowed_class_test.dart index e8ec26d79b7..9a3968f085e 100644 --- a/pkg/analyzer/test/src/diagnostics/extends_disallowed_class_test.dart +++ b/pkg/analyzer/test/src/diagnostics/extends_disallowed_class_test.dart @@ -19,11 +19,6 @@ class ExtendsDisallowedClassTest extends PubPackageResolutionTest { await assertErrorsInCode(''' class A extends bool {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS, 16, 4), ]); } @@ -32,11 +27,6 @@ class A extends bool {} await assertErrorsInCode(''' class A extends double {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS, 16, 6), ]); } @@ -82,11 +72,6 @@ class A extends FutureOr {} await assertErrorsInCode(''' class A extends int {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS, 16, 3), ]); } @@ -111,11 +96,6 @@ class A extends num {} await assertErrorsInCode(''' class A extends Record {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS, 16, 6), ]); } @@ -124,11 +104,6 @@ class A extends Record {} await assertErrorsInCode(''' class A extends String {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS, 16, 6), ]); } diff --git a/pkg/analyzer/test/src/diagnostics/implements_disallowed_class_test.dart b/pkg/analyzer/test/src/diagnostics/implements_disallowed_class_test.dart index 975a629cc42..9b05544fabe 100644 --- a/pkg/analyzer/test/src/diagnostics/implements_disallowed_class_test.dart +++ b/pkg/analyzer/test/src/diagnostics/implements_disallowed_class_test.dart @@ -19,11 +19,6 @@ class ImplementsDisallowedClassTest extends PubPackageResolutionTest { await assertErrorsInCode(''' class A implements bool {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 4), ]); } @@ -56,11 +51,6 @@ class A implements Enum {} await assertErrorsInCode(''' class A implements double {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 6), ]); } @@ -106,11 +96,6 @@ class A implements FutureOr {} await assertErrorsInCode(''' class A implements int {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 3), ]); } @@ -135,11 +120,6 @@ class A implements num {} await assertErrorsInCode(''' class A implements Record {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 6), ]); } @@ -148,11 +128,6 @@ class A implements Record {} await assertErrorsInCode(''' class A implements String {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 6), ]); } @@ -161,11 +136,6 @@ class A implements String {} await assertErrorsInCode(''' class A implements String, num {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 6), error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 27, 3), ]); @@ -309,11 +279,6 @@ mixin M implements Enum {} await assertErrorsInCode(r''' mixin M implements int {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 19, 3), ]); diff --git a/pkg/analyzer/test/src/diagnostics/mixin_of_disallowed_class_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_of_disallowed_class_test.dart index d9e5d87841e..ac69af8721c 100644 --- a/pkg/analyzer/test/src/diagnostics/mixin_of_disallowed_class_test.dart +++ b/pkg/analyzer/test/src/diagnostics/mixin_of_disallowed_class_test.dart @@ -19,11 +19,6 @@ class MixinOfDisallowedClassTest extends PubPackageResolutionTest { await assertErrorsInCode(''' class A extends Object with bool {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 28, 4), ]); } @@ -32,11 +27,6 @@ class A extends Object with bool {} await assertErrorsInCode(''' class A extends Object with double {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 28, 6), ]); } @@ -72,11 +62,6 @@ class A extends Object with FutureOr {} await assertErrorsInCode(''' class A extends Object with int {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 28, 3), ]); } @@ -101,11 +86,6 @@ class A extends Object with num {} await assertErrorsInCode(''' class A extends Object with Record {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 28, 6), ]); } @@ -114,11 +94,6 @@ class A extends Object with Record {} await assertErrorsInCode(''' class A extends Object with String {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 28, 6), ]); } diff --git a/pkg/analyzer/test/src/diagnostics/mixin_super_class_constraint_disallowed_class_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_super_class_constraint_disallowed_class_test.dart index b4c804384ee..7e8ad5eb8bb 100644 --- a/pkg/analyzer/test/src/diagnostics/mixin_super_class_constraint_disallowed_class_test.dart +++ b/pkg/analyzer/test/src/diagnostics/mixin_super_class_constraint_disallowed_class_test.dart @@ -46,11 +46,8 @@ mixin M on Enum {} await assertErrorsInCode(r''' mixin M on int {} ''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1), + error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 6, 1), error(CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_DISALLOWED_CLASS, 11, 3), ]); diff --git a/pkg/analyzer/test/src/diagnostics/subtype_of_base_is_not_base_final_or_sealed_test.dart b/pkg/analyzer/test/src/diagnostics/subtype_of_base_is_not_base_final_or_sealed_test.dart new file mode 100644 index 00000000000..112dee96337 --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/subtype_of_base_is_not_base_final_or_sealed_test.dart @@ -0,0 +1,352 @@ +// 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 '../../generated/test_support.dart'; +import '../dart/resolution/context_collection_resolution.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(SubtypeOfBaseIsNotBaseFinalOrSealedTest); + }); +} + +@reflectiveTest +class SubtypeOfBaseIsNotBaseFinalOrSealedTest extends PubPackageResolutionTest { + test_class_extends() async { + await assertErrorsInCode(r''' +base class A {} +class B extends A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 22, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), + ]); + } + + test_class_extends_multiple() async { + await assertErrorsInCode(r''' +base class A {} +base class B extends A {} +class C extends A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 48, 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), + ]); + } + + test_class_extends_multiple_files() async { + final a = newFile('$testPackageLibPath/a.dart', r''' +base class A {} +class B extends A {} +'''); + + await assertErrorsInFile2(a.path, [ + error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 22, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), + ]); + await assertErrorsInCode(r''' +import 'a.dart'; +class C extends B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 23, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", + contextMessages: [ + ExpectedContextMessage(a.path, 22, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_class_extends_outside() async { + newFile('$testPackageLibPath/a.dart', r''' +base class A {} +'''); + + await assertErrorsInCode(r''' +import 'a.dart'; +class B extends A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 23, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), + ]); + } + + test_class_implements() async { + await assertErrorsInCode(r''' +base class A {} +class B implements A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 22, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), + ]); + } + + test_class_mixin_mixedIn() async { + await assertErrorsInCode(r''' +base mixin class A {} +class B with A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 28, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), + ]); + } + + test_class_mixin_mixedIn_outside() async { + newFile('$testPackageLibPath/a.dart', r''' +base mixin class A {} +'''); + + await assertErrorsInCode(r''' +import 'a.dart'; +class B with A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 23, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), + ]); + } + + test_class_sealed_extends() async { + await assertErrorsInCode(r''' +base class A {} +sealed class B extends A {} +class C extends B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 50, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 29, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_class_sealed_extends_multiple() async { + await assertErrorsInCode(r''' +base class A {} +sealed class B extends A {} +sealed class C extends B {} +class D extends C {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 78, + 1, + text: + "The type 'D' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 57, 1, + text: + "The type 'C' is a subtype of 'A', and 'C' is defined here.") + ], + ), + ]); + } + + test_class_sealed_extends_outside() async { + newFile('$testPackageLibPath/a.dart', r''' +base class A {} +'''); + + await assertErrorsInCode(r''' +import 'a.dart'; +sealed class B extends A {} +class C extends B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 51, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 30, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_class_sealed_extends_unordered() async { + await assertErrorsInCode(r''' +class C extends B {} +sealed class B extends A {} +base class A {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 6, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 34, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_class_sealed_implements() async { + await assertErrorsInCode(r''' +base class A {} +sealed class B implements A {} +class C implements B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 53, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 29, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_class_sealed_mixin_mixedIn() async { + await assertErrorsInCode(r''' +base mixin class A {} +sealed class B with A {} +class C extends B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 53, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 35, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_class_sealed_mixin_mixedIn_outside() async { + newFile('$testPackageLibPath/a.dart', r''' +base mixin class A {} +'''); + + await assertErrorsInCode(r''' +import 'a.dart'; +sealed class B with A {} +class C extends B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 48, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 30, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_mixin_implements() async { + await assertErrorsInCode(r''' +base class A {} +mixin B implements A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 22, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), + ]); + } + + test_mixin_on() async { + await assertErrorsInCode(r''' +base class A {} +mixin B on A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 22, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), + ]); + } + + test_mixin_sealed_implements() async { + await assertErrorsInCode(r''' +base class A {} +sealed mixin B implements A {} +mixin C implements B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 53, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 29, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_mixin_sealed_on() async { + await assertErrorsInCode(r''' +base class A {} +sealed mixin B on A {} +mixin C on B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED, + 45, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 29, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } +} diff --git a/pkg/analyzer/test/src/diagnostics/subtype_of_base_or_final_is_not_base_final_or_sealed_test.dart b/pkg/analyzer/test/src/diagnostics/subtype_of_base_or_final_is_not_base_final_or_sealed_test.dart deleted file mode 100644 index 7a633a1cf0a..00000000000 --- a/pkg/analyzer/test/src/diagnostics/subtype_of_base_or_final_is_not_base_final_or_sealed_test.dart +++ /dev/null @@ -1,572 +0,0 @@ -// 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 '../../generated/test_support.dart'; -import '../dart/resolution/context_collection_resolution.dart'; - -main() { - defineReflectiveSuite(() { - defineReflectiveTests(SubtypeOfBaseOrFinalIsNotBaseFinalOrSealedTest); - }); -} - -@reflectiveTest -class SubtypeOfBaseOrFinalIsNotBaseFinalOrSealedTest - extends PubPackageResolutionTest { - test_class_base_extends() async { - await assertErrorsInCode(r''' -base class A {} -class B extends A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 22, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), - ]); - } - - test_class_base_extends_multiple() async { - await assertErrorsInCode(r''' -base class A {} -base class B extends A {} -class C extends A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 48, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), - ]); - } - - test_class_base_extends_multiple_files() async { - await assertErrorsInFile( - resourceProvider.convertPath('$testPackageLibPath/a.dart'), r''' -base class A {} -class B extends A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 22, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), - ]); - await assertErrorsInFile( - resourceProvider.convertPath('$testPackageLibPath/c.dart'), r''' -import 'a.dart'; -class C extends B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 23, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/a.dart', 22, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - await assertErrorsInCode(r''' -import 'a.dart'; -class D extends B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 23, - 1, - text: - "The type 'D' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/a.dart', 22, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_class_base_extends_outside() async { - newFile('$testPackageLibPath/foo.dart', r''' -base class A {} -'''); - - await assertErrorsInCode(r''' -import 'foo.dart'; -class B extends A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 25, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), - ]); - } - - test_class_base_implements() async { - await assertErrorsInCode(r''' -base class A {} -class B implements A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 22, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), - ]); - } - - test_class_base_mixin_mixedIn() async { - await assertErrorsInCode(r''' -base mixin class A {} -class B with A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 28, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), - ]); - } - - test_class_base_mixin_mixedIn_outside() async { - newFile('$testPackageLibPath/foo.dart', r''' -base mixin class A {} -'''); - - await assertErrorsInCode(r''' -import 'foo.dart'; -class B with A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 25, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), - ]); - } - - test_class_base_multiple() async { - await assertErrorsInCode(r''' -base class A {} -final class B {} -class C extends B implements A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 39, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'B' is 'final'."), - ]); - } - - test_class_final_extends() async { - await assertErrorsInCode(r''' -final class A {} -class B extends A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 23, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."), - ]); - } - - test_class_final_implements() async { - await assertErrorsInCode(r''' -final class A {} -class B implements A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 23, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."), - ]); - } - - test_class_sealed_base_extends() async { - await assertErrorsInCode(r''' -base class A {} -sealed class B extends A {} -class C extends B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 50, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 29, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_class_sealed_base_extends_multiple() async { - await assertErrorsInCode(r''' -base class A {} -sealed class B extends A {} -sealed class C extends B {} -class D extends C {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 78, - 1, - text: - "The type 'D' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 57, 1, - text: - "The type 'C' is a subtype of 'A', and 'C' is defined here.") - ], - ), - ]); - } - - test_class_sealed_base_extends_outside() async { - newFile('$testPackageLibPath/foo.dart', r''' -base class A {} -'''); - - await assertErrorsInCode(r''' -import 'foo.dart'; -sealed class B extends A {} -class C extends B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 53, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 32, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_class_sealed_base_extends_unordered() async { - await assertErrorsInCode(r''' -class C extends B {} -sealed class B extends A {} -base class A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 6, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 34, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_class_sealed_base_implements() async { - await assertErrorsInCode(r''' -base class A {} -sealed class B implements A {} -class C implements B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 53, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 29, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_class_sealed_base_mixin_mixedIn() async { - await assertErrorsInCode(r''' -base mixin class A {} -sealed class B with A {} -class C extends B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 53, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 35, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_class_sealed_base_mixin_mixedIn_outside() async { - newFile('$testPackageLibPath/foo.dart', r''' -base mixin class A {} -'''); - - await assertErrorsInCode(r''' -import 'foo.dart'; -sealed class B with A {} -class C extends B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 50, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 32, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_class_sealed_final_extends() async { - await assertErrorsInCode(r''' -final class A {} -sealed class B extends A {} -class C extends B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 51, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 30, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_class_sealed_final_implements() async { - await assertErrorsInCode(r''' -final class A {} -sealed class B implements A {} -class C implements B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 54, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 30, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_mixin_base_implements() async { - await assertErrorsInCode(r''' -base class A {} -mixin B implements A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 22, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), - ]); - } - - test_mixin_base_on() async { - await assertErrorsInCode(r''' -base class A {} -mixin B on A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 22, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'."), - ]); - } - - test_mixin_final_implements() async { - await assertErrorsInCode(r''' -final class A {} -mixin B implements A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 23, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."), - ]); - } - - test_mixin_final_on() async { - await assertErrorsInCode(r''' -final class A {} -mixin B on A {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 23, - 1, - text: - "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."), - ]); - } - - test_mixin_sealed_base_implements() async { - await assertErrorsInCode(r''' -base class A {} -sealed mixin B implements A {} -mixin C implements B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 53, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 29, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_mixin_sealed_base_on() async { - await assertErrorsInCode(r''' -base class A {} -sealed mixin B on A {} -mixin C on B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 45, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 29, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_mixin_sealed_final_implements() async { - await assertErrorsInCode(r''' -final class A {} -sealed mixin B implements A {} -mixin C implements B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 54, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 30, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } - - test_mixin_sealed_final_on() async { - await assertErrorsInCode(r''' -final class A {} -sealed mixin B on A {} -mixin C on B {} -''', [ - error( - CompileTimeErrorCode - .SUBTYPE_OF_BASE_OR_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, - 46, - 1, - text: - "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.", - contextMessages: [ - ExpectedContextMessage('/home/test/lib/test.dart', 30, 1, - text: - "The type 'B' is a subtype of 'A', and 'B' is defined here.") - ], - ), - ]); - } -} diff --git a/pkg/analyzer/test/src/diagnostics/subtype_of_final_is_not_base_final_or_sealed_test.dart b/pkg/analyzer/test/src/diagnostics/subtype_of_final_is_not_base_final_or_sealed_test.dart new file mode 100644 index 00000000000..457695b5a6f --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/subtype_of_final_is_not_base_final_or_sealed_test.dart @@ -0,0 +1,241 @@ +// 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 '../../generated/test_support.dart'; +import '../dart/resolution/context_collection_resolution.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(SubtypeOfFinalIsNotBaseFinalOrSealedTest); + }); +} + +@reflectiveTest +class SubtypeOfFinalIsNotBaseFinalOrSealedTest + extends PubPackageResolutionTest { + test_class_extends() async { + await assertErrorsInCode(r''' +final class A {} +class B extends A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 23, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."), + ]); + } + + test_class_implements() async { + await assertErrorsInCode(r''' +final class A {} +class B implements A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 23, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."), + ]); + } + + test_class_outside() async { + // No [SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED] reported outside of + // library. + newFile('$testPackageLibPath/a.dart', r''' +final class A {} +'''); + + await assertErrorsInCode(r''' +import 'a.dart'; +class B extends A {} +''', [ + error( + CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY, 33, 1), + ]); + } + + test_class_outside_on() async { + newFile('$testPackageLibPath/a.dart', r''' +final mixin A {} +'''); + + await assertErrorsInCode(r''' +import 'a.dart'; +mixin B on A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 23, 1), + ]); + } + + test_class_sealed_extends() async { + await assertErrorsInCode(r''' +final class A {} +sealed class B extends A {} +class C extends B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 51, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 30, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_class_sealed_extends_multiple() async { + await assertErrorsInCode(r''' +final class A {} +sealed class B extends A {} +sealed class C extends B {} +class D extends C {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 79, + 1, + text: + "The type 'D' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 58, 1, + text: + "The type 'C' is a subtype of 'A', and 'C' is defined here.") + ], + ), + ]); + } + + test_class_sealed_extends_outside() async { + // No [SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED] reported outside of + // library. + newFile('$testPackageLibPath/a.dart', r''' +final class A {} +'''); + + await assertErrorsInCode(r''' +import 'a.dart'; +sealed class B extends A {} +class C extends B {} +''', [ + error( + CompileTimeErrorCode.FINAL_CLASS_EXTENDED_OUTSIDE_OF_LIBRARY, 40, 1), + ]); + } + + test_class_sealed_extends_unordered() async { + await assertErrorsInCode(r''' +class C extends B {} +sealed class B extends A {} +final class A {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 6, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 34, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_class_sealed_implements() async { + await assertErrorsInCode(r''' +final class A {} +sealed class B implements A {} +class C implements B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 54, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 30, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_mixin_implements() async { + await assertErrorsInCode(r''' +final class A {} +mixin B implements A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 23, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."), + ]); + } + + test_mixin_on() async { + await assertErrorsInCode(r''' +final class A {} +mixin B on A {} +''', [ + error(CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 23, 1, + text: + "The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'."), + ]); + } + + test_mixin_sealed_implements() async { + await assertErrorsInCode(r''' +final class A {} +sealed mixin B implements A {} +mixin C implements B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 54, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 30, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } + + test_mixin_sealed_on() async { + await assertErrorsInCode(r''' +final class A {} +sealed mixin B on A {} +mixin C on B {} +''', [ + error( + CompileTimeErrorCode.SUBTYPE_OF_FINAL_IS_NOT_BASE_FINAL_OR_SEALED, + 46, + 1, + text: + "The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.", + contextMessages: [ + ExpectedContextMessage(testFile.path, 30, 1, + text: + "The type 'B' is a subtype of 'A', and 'B' is defined here.") + ], + ), + ]); + } +} diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart index b5d7b78cd37..4b048b4af0a 100644 --- a/pkg/analyzer/test/src/diagnostics/test_all.dart +++ b/pkg/analyzer/test/src/diagnostics/test_all.dart @@ -741,9 +741,11 @@ import 'spread_expression_from_deferred_library_test.dart' import 'static_access_to_instance_member_test.dart' as static_access_to_instance_member; import 'strict_raw_type_test.dart' as strict_raw_type; -import 'subtype_of_base_or_final_is_not_base_final_or_sealed_test.dart' - as subtype_of_base_or_final_is_not_base_final_or_sealed; +import 'subtype_of_base_is_not_base_final_or_sealed_test.dart' + as subtype_of_base_is_not_base_final_or_sealed; import 'subtype_of_ffi_class_test.dart' as subtype_of_ffi_class; +import 'subtype_of_final_is_not_base_final_or_sealed_test.dart' + as subtype_of_final_is_not_base_final_or_sealed; import 'subtype_of_sealed_class_test.dart' as subtype_of_sealed_class; import 'subtype_of_struct_class_test.dart' as subtype_of_struct_class; import 'super_formal_parameter_type_is_not_subtype_of_associated_test.dart' @@ -1353,8 +1355,9 @@ main() { spread_expression_from_deferred_library.main(); static_access_to_instance_member.main(); strict_raw_type.main(); - subtype_of_base_or_final_is_not_base_final_or_sealed.main(); + subtype_of_base_is_not_base_final_or_sealed.main(); subtype_of_ffi_class.main(); + subtype_of_final_is_not_base_final_or_sealed.main(); subtype_of_sealed_class.main(); subtype_of_struct_class.main(); super_formal_parameter_type_is_not_subtype_of_associated.main();