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 <scheglov@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
0804245caa
commit
d2c5a24fd9
@@ -880,8 +880,8 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
|
||||
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) {
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user