From d2c5a24fd9ead97a7f18d02786e679293cc3709e Mon Sep 17 00:00:00 2001 From: Brian Wilkerson Date: Tue, 2 Oct 2018 19:20:35 +0000 Subject: [PATCH] Recognize mixins as subtypes of their superclass constraints in hint generation (issue 34633) Change-Id: I84b86e998ec353c13b18a460f2a7ca8cb0802204 Reviewed-on: https://dart-review.googlesource.com/77665 Reviewed-by: Konstantin Shcheglov Commit-Queue: Brian Wilkerson --- pkg/analyzer/lib/src/generated/resolver.dart | 11 +- .../test/generated/hint_code_test.dart | 407 ++++++++++-------- 2 files changed, 226 insertions(+), 192 deletions(-) diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart index 93695fd9d21..0ff08348d0a 100644 --- a/pkg/analyzer/lib/src/generated/resolver.dart +++ b/pkg/analyzer/lib/src/generated/resolver.dart @@ -880,8 +880,8 @@ class BestPracticesVerifier extends RecursiveAstVisitor { return; } ClassElement definingClass = element.enclosingElement; - ClassDeclaration accessingClass = - identifier.getAncestor((AstNode node) => node is ClassDeclaration); + ClassOrMixinDeclaration accessingClass = identifier + .getAncestor((AstNode node) => node is ClassOrMixinDeclaration); if (_hasTypeOrSuperType( accessingClass?.declaredElement, definingClass.type)) { return; @@ -3954,6 +3954,13 @@ class OverrideVerifier extends RecursiveAstVisitor { } } + @override + visitMixinDeclaration(MixinDeclaration node) { + _currentInterface = _inheritance.getInterface(node.declaredElement.type); + super.visitMixinDeclaration(node); + _currentInterface = null; + } + /// Return `true` if the [member] overrides a member from the superinterface. bool _isOverride(ExecutableElement member) { if (member == null) { diff --git a/pkg/analyzer/test/generated/hint_code_test.dart b/pkg/analyzer/test/generated/hint_code_test.dart index 1789773bf65..e4d808c37d3 100644 --- a/pkg/analyzer/test/generated/hint_code_test.dart +++ b/pkg/analyzer/test/generated/hint_code_test.dart @@ -1542,17 +1542,6 @@ m6({a, @required b}) => null; verify([source]); } - test_invalidSealedAnnotation_onNonClass() async { - Source source = addNamedSource('/lib1.dart', r''' -import 'package:meta/meta.dart'; - -@sealed m({a = 1}) => null; -'''); - await computeAnalysisResult(source); - assertErrors(source, [HintCode.INVALID_SEALED_ANNOTATION]); - verify([source]); - } - test_invalidSealedAnnotation_onClass() async { Source source = addNamedSource('/lib1.dart', r''' import 'package:meta/meta.dart'; @@ -1564,6 +1553,17 @@ import 'package:meta/meta.dart'; verify([source]); } + test_invalidSealedAnnotation_onMixin() async { + Source source = addNamedSource('/lib1.dart', r''' +import 'package:meta/meta.dart'; + +@sealed mixin M {} +'''); + await computeAnalysisResult(source); + assertNoErrors(source); + verify([source]); + } + test_invalidSealedAnnotation_onMixinApplication() async { Source source = addNamedSource('/lib1.dart', r''' import 'package:meta/meta.dart'; @@ -1579,14 +1579,14 @@ abstract class B {} verify([source]); } - test_invalidSealedAnnotation_onMixin() async { + test_invalidSealedAnnotation_onNonClass() async { Source source = addNamedSource('/lib1.dart', r''' import 'package:meta/meta.dart'; -@sealed mixin M {} +@sealed m({a = 1}) => null; '''); await computeAnalysisResult(source); - assertNoErrors(source); + assertErrors(source, [HintCode.INVALID_SEALED_ANNOTATION]); verify([source]); } @@ -1651,6 +1651,33 @@ abstract class B implements A { verify([source]); } + test_invalidUseOfProtectedMember_fromSuperclassConstraint() async { + Source sourceA = addNamedSource('/a.dart', r''' +import 'package:meta/meta.dart'; + +abstract class A { + @protected + void foo() {} +} +'''); + Source sourceM = addNamedSource('/m.dart', r''' +import 'a.dart'; + +mixin M on A { + @override + void foo() { + super.foo(); + } +} +'''); + + await computeAnalysisResult(sourceA); + await computeAnalysisResult(sourceM); + assertNoErrors(sourceA); + assertNoErrors(sourceM); + verify([sourceA, sourceM]); + } + test_invalidUseOfProtectedMember_function() async { Source source = addNamedSource('/lib1.dart', r''' import 'package:meta/meta.dart'; @@ -2016,166 +2043,6 @@ main() { verify([source]); } - test_invalidUseOfVisibleForTestingMember_constructor() async { - Source source = addNamedSource('/lib1.dart', r''' -import 'package:meta/meta.dart'; -class A { - int _x; - - @visibleForTesting - A.forTesting(this._x); -} -'''); - Source source2 = addNamedSource('/lib2.dart', r''' -import 'lib1.dart'; - -void main() { - new A.forTesting(0); -} -'''); - await computeAnalysisResult(source); - await computeAnalysisResult(source2); - assertErrors(source2, [HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]); - verify([source, source2]); - } - - test_invalidUseOfVisibleForTestingMember_method() async { - Source source = addNamedSource('/lib1.dart', r''' -import 'package:meta/meta.dart'; -class A { - @visibleForTesting - void a(){ } -} -'''); - Source source2 = addNamedSource('/lib2.dart', r''' -import 'lib1.dart'; - -class B { - void b() => new A().a(); -} -'''); - await computeAnalysisResult(source); - await computeAnalysisResult(source2); - assertErrors(source2, [HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]); - verify([source, source2]); - } - - test_invalidUseOfVisibleForTestingMember_method_OK() async { - Source source = addNamedSource('/lib1.dart', r''' -import 'package:meta/meta.dart'; -class A { - @visibleForTesting - void a(){ } -} -'''); - Source source2 = addNamedSource('/test/test1.dart', r''' -import '../lib1.dart'; - -class B { - void b() => new A().a(); -} -'''); - Source source3 = addNamedSource('/testing/lib1.dart', r''' -import '../lib1.dart'; - -class C { - void b() => new A().a(); -} -'''); - await computeAnalysisResult(source); - await computeAnalysisResult(source2); - await computeAnalysisResult(source3); - assertNoErrors(source2); - assertNoErrors(source3); - verify([source, source2, source3]); - } - - test_invalidUseOfVisibleForTestingMember_export_OK() async { - Source source = addNamedSource('/lib1.dart', r''' -import 'package:meta/meta.dart'; - -@visibleForTesting -int fn0() => 1; -'''); - Source source2 = addNamedSource('/lib2.dart', r''' -export 'lib1.dart' show fn0; -'''); - await computeAnalysisResult(source); - await computeAnalysisResult(source2); - assertNoErrors(source2); - verify([source, source2]); - } - - test_invalidUseOfVisibleForTestingMember_propertyAccess() async { - Source source = addNamedSource('/lib1.dart', r''' -import 'package:meta/meta.dart'; -class A { - @visibleForTesting - int get a => 7; - - @visibleForTesting - set b(_) => 7; -} -'''); - Source source2 = addNamedSource('/lib2.dart', r''' -import 'lib1.dart'; - -void main() { - new A().a; - new A().b = 6; -} -'''); - await computeAnalysisResult(source); - await computeAnalysisResult(source2); - assertErrors(source2, [ - HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER, - HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER - ]); - verify([source, source2]); - } - - test_invalidUseOfVisibleForTestingMember_topLevelFunction() async { - Source source = addNamedSource('/lib1.dart', r''' -import 'package:meta/meta.dart'; - -@visibleForTesting -int fn0() => 1; -'''); - Source source2 = addNamedSource('/lib2.dart', r''' -import 'lib1.dart'; - -void main() { - fn0(); -} -'''); - await computeAnalysisResult(source); - await computeAnalysisResult(source2); - assertErrors(source2, [HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]); - verify([source, source2]); - } - - test_invalidUseProtectedAndForTesting_asProtected_OK() async { - Source source = addNamedSource('/lib1.dart', r''' -import 'package:meta/meta.dart'; -class A { - @protected - @visibleForTesting - void a(){ } -} -'''); - Source source2 = addNamedSource('/lib2.dart', r''' -import 'lib1.dart'; - -class B extends A { - void b() => new A().a(); -} -'''); - await computeAnalysisResult(source); - await computeAnalysisResult(source2); - assertNoErrors(source2); - verify([source, source2]); - } - test_invalidUseOfVisibleForTemplateMember_constructor() async { Source source = addNamedSource('/lib1.dart', r''' import 'package:angular_meta/angular_meta.dart'; @@ -2200,6 +2067,22 @@ void main() { verify([source, source2]); } + test_invalidUseOfVisibleForTemplateMember_export_OK() async { + Source source = addNamedSource('/lib1.dart', r''' +import 'package:angular_meta/angular_meta.dart'; + +@visibleForTemplate +int fn0() => 1; +'''); + Source source2 = addNamedSource('/lib2.dart', r''' +export 'lib1.dart' show fn0; +'''); + await computeAnalysisResult(source); + await computeAnalysisResult(source2); + assertNoErrors(source2); + verify([source, source2]); + } + test_invalidUseOfVisibleForTemplateMember_method() async { Source source = addNamedSource('/lib1.dart', r''' import 'package:angular_meta/angular_meta.dart'; @@ -2243,22 +2126,6 @@ class B { verify([source, source2]); } - test_invalidUseOfVisibleForTemplateMember_export_OK() async { - Source source = addNamedSource('/lib1.dart', r''' -import 'package:angular_meta/angular_meta.dart'; - -@visibleForTemplate -int fn0() => 1; -'''); - Source source2 = addNamedSource('/lib2.dart', r''' -export 'lib1.dart' show fn0; -'''); - await computeAnalysisResult(source); - await computeAnalysisResult(source2); - assertNoErrors(source2); - verify([source, source2]); - } - test_invalidUseOfVisibleForTemplateMember_propertyAccess() async { Source source = addNamedSource('/lib1.dart', r''' import 'package:angular_meta/angular_meta.dart'; @@ -2308,6 +2175,144 @@ void main() { verify([source, source2]); } + test_invalidUseOfVisibleForTestingMember_constructor() async { + Source source = addNamedSource('/lib1.dart', r''' +import 'package:meta/meta.dart'; +class A { + int _x; + + @visibleForTesting + A.forTesting(this._x); +} +'''); + Source source2 = addNamedSource('/lib2.dart', r''' +import 'lib1.dart'; + +void main() { + new A.forTesting(0); +} +'''); + await computeAnalysisResult(source); + await computeAnalysisResult(source2); + assertErrors(source2, [HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]); + verify([source, source2]); + } + + test_invalidUseOfVisibleForTestingMember_export_OK() async { + Source source = addNamedSource('/lib1.dart', r''' +import 'package:meta/meta.dart'; + +@visibleForTesting +int fn0() => 1; +'''); + Source source2 = addNamedSource('/lib2.dart', r''' +export 'lib1.dart' show fn0; +'''); + await computeAnalysisResult(source); + await computeAnalysisResult(source2); + assertNoErrors(source2); + verify([source, source2]); + } + + test_invalidUseOfVisibleForTestingMember_method() async { + Source source = addNamedSource('/lib1.dart', r''' +import 'package:meta/meta.dart'; +class A { + @visibleForTesting + void a(){ } +} +'''); + Source source2 = addNamedSource('/lib2.dart', r''' +import 'lib1.dart'; + +class B { + void b() => new A().a(); +} +'''); + await computeAnalysisResult(source); + await computeAnalysisResult(source2); + assertErrors(source2, [HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]); + verify([source, source2]); + } + + test_invalidUseOfVisibleForTestingMember_method_OK() async { + Source source = addNamedSource('/lib1.dart', r''' +import 'package:meta/meta.dart'; +class A { + @visibleForTesting + void a(){ } +} +'''); + Source source2 = addNamedSource('/test/test1.dart', r''' +import '../lib1.dart'; + +class B { + void b() => new A().a(); +} +'''); + Source source3 = addNamedSource('/testing/lib1.dart', r''' +import '../lib1.dart'; + +class C { + void b() => new A().a(); +} +'''); + await computeAnalysisResult(source); + await computeAnalysisResult(source2); + await computeAnalysisResult(source3); + assertNoErrors(source2); + assertNoErrors(source3); + verify([source, source2, source3]); + } + + test_invalidUseOfVisibleForTestingMember_propertyAccess() async { + Source source = addNamedSource('/lib1.dart', r''' +import 'package:meta/meta.dart'; +class A { + @visibleForTesting + int get a => 7; + + @visibleForTesting + set b(_) => 7; +} +'''); + Source source2 = addNamedSource('/lib2.dart', r''' +import 'lib1.dart'; + +void main() { + new A().a; + new A().b = 6; +} +'''); + await computeAnalysisResult(source); + await computeAnalysisResult(source2); + assertErrors(source2, [ + HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER, + HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER + ]); + verify([source, source2]); + } + + test_invalidUseOfVisibleForTestingMember_topLevelFunction() async { + Source source = addNamedSource('/lib1.dart', r''' +import 'package:meta/meta.dart'; + +@visibleForTesting +int fn0() => 1; +'''); + Source source2 = addNamedSource('/lib2.dart', r''' +import 'lib1.dart'; + +void main() { + fn0(); +} +'''); + await computeAnalysisResult(source); + await computeAnalysisResult(source2); + assertErrors(source2, [HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER]); + verify([source, source2]); + } + test_invalidUseProtectedAndForTemplate_asProtected_OK() async { Source source = addNamedSource('/lib1.dart', r''' import 'package:angular_meta/angular_meta.dart'; @@ -2354,6 +2359,28 @@ void main() { verify([source, source2]); } + test_invalidUseProtectedAndForTesting_asProtected_OK() async { + Source source = addNamedSource('/lib1.dart', r''' +import 'package:meta/meta.dart'; +class A { + @protected + @visibleForTesting + void a(){ } +} +'''); + Source source2 = addNamedSource('/lib2.dart', r''' +import 'lib1.dart'; + +class B extends A { + void b() => new A().a(); +} +'''); + await computeAnalysisResult(source); + await computeAnalysisResult(source2); + assertNoErrors(source2); + verify([source, source2]); + } + test_invalidUseProtectedAndForTesting_asTesting_OK() async { Source source = addNamedSource('/lib1.dart', r''' import 'package:meta/meta.dart';