Skip to content

Commit 48e0dbe

Browse files
pqCommit Queue
authored andcommitted
[element model] migrate overridden_fields
This one really deserved a re-write (as migrating as-is was really ugly). The implementation is much simpler and far more efficient. I'd definitely appreciate a close look though to make sure it's also *correct*. :) Bug: https://github.com/dart-lang/linter/issues/5099 Change-Id: I7dcbcf9c98279c84b45921d674f2c3fe90b9d9bc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/392081 Commit-Queue: Phil Quitslund <[email protected]> Auto-Submit: Phil Quitslund <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]>
1 parent e2cdc76 commit 48e0dbe

File tree

2 files changed

+85
-77
lines changed

2 files changed

+85
-77
lines changed

pkg/linter/lib/src/rules/overridden_fields.dart

Lines changed: 15 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,13 @@
44

55
import 'package:analyzer/dart/ast/ast.dart';
66
import 'package:analyzer/dart/ast/visitor.dart';
7-
import 'package:analyzer/dart/element/element.dart';
8-
import 'package:analyzer/dart/element/type.dart';
9-
import 'package:collection/collection.dart' show IterableExtension;
7+
import 'package:analyzer/dart/element/element2.dart';
108

119
import '../analyzer.dart';
1210
import '../extensions.dart';
1311

1412
const _desc = r"Don't override fields.";
1513

16-
Iterable<InterfaceType> _findAllSupertypesAndMixins(
17-
InterfaceType? interface, List<InterfaceType> accumulator) {
18-
if (interface == null ||
19-
interface.isDartCoreObject ||
20-
accumulator.contains(interface)) {
21-
return accumulator;
22-
}
23-
24-
accumulator.add(interface);
25-
var superclass = interface.superclass;
26-
var interfaces = <InterfaceType>[];
27-
if (superclass != null) {
28-
interfaces.add(superclass);
29-
}
30-
interfaces
31-
..addAll(interface.element.mixins)
32-
..addAll(_findAllSupertypesAndMixins(superclass, accumulator));
33-
return interfaces.where((i) => i != interface);
34-
}
35-
36-
Iterable<InterfaceType> _findAllSupertypesInMixin(MixinElement mixinElement) {
37-
var supertypes = <InterfaceType>[];
38-
var accumulator = <InterfaceType>[];
39-
for (var type in mixinElement.superclassConstraints) {
40-
supertypes.add(type);
41-
supertypes.addAll(_findAllSupertypesAndMixins(type, accumulator));
42-
}
43-
return supertypes;
44-
}
45-
4614
class OverriddenFields extends LintRule {
4715
OverriddenFields()
4816
: super(
@@ -56,66 +24,36 @@ class OverriddenFields extends LintRule {
5624
@override
5725
void registerNodeProcessors(
5826
NodeLintRegistry registry, LinterContext context) {
59-
var visitor = _Visitor(this);
27+
var visitor = _Visitor(this, context.inheritanceManager);
6028
registry.addFieldDeclaration(this, visitor);
6129
}
6230
}
6331

6432
class _Visitor extends SimpleAstVisitor<void> {
6533
final LintRule rule;
34+
final InheritanceManager3 inheritanceManager;
6635

67-
_Visitor(this.rule);
36+
_Visitor(this.rule, this.inheritanceManager);
6837

6938
@override
7039
void visitFieldDeclaration(FieldDeclaration node) {
7140
if (node.isAugmentation) return;
7241
if (node.isStatic) return;
7342

7443
for (var variable in node.fields.variables) {
75-
var declaredField = variable.declaredElement;
76-
if (declaredField != null) {
77-
var overriddenField = _getOverriddenMember(declaredField);
78-
if (overriddenField != null && !overriddenField.isAbstract) {
79-
rule.reportLintForToken(variable.name,
80-
arguments: [overriddenField.enclosingElement3.displayName]);
81-
}
82-
}
83-
}
84-
}
85-
86-
PropertyAccessorElement? _getOverriddenMember(Element member) {
87-
var memberName = member.name;
88-
var library = member.library;
89-
bool isOverriddenMember(PropertyAccessorElement a) {
90-
if (memberName == null || a.isStatic) {
91-
return false;
92-
}
93-
if (a.isSynthetic && a.name == memberName) {
94-
// Ensure that private members are overriding a member of the same library.
95-
if (Identifier.isPrivateName(memberName)) {
96-
return library == a.library;
44+
var parent = variable.declaredFragment?.element.enclosingElement2;
45+
if (parent is InterfaceElement2) {
46+
var overriddenMember = inheritanceManager.getMember4(
47+
parent, Name(parent.library2.uri, variable.name.lexeme),
48+
forSuper: true);
49+
if (overriddenMember is GetterElement && overriddenMember.isSynthetic) {
50+
var definingInterface = overriddenMember.enclosingElement2;
51+
if (definingInterface != null) {
52+
rule.reportLintForToken(variable.name,
53+
arguments: [definingInterface.displayName]);
54+
}
9755
}
98-
return true;
9956
}
100-
return false;
101-
}
102-
103-
bool containsOverriddenMember(InterfaceType i) =>
104-
i.accessors.any(isOverriddenMember);
105-
var enclosingElement = member.enclosingElement3;
106-
if (enclosingElement is! InterfaceElement) {
107-
return null;
108-
}
109-
var classElement = enclosingElement;
110-
111-
Iterable<InterfaceType> interfaces;
112-
if (classElement is MixinElement) {
113-
interfaces = _findAllSupertypesInMixin(classElement);
114-
} else {
115-
interfaces =
116-
_findAllSupertypesAndMixins(classElement.thisType, <InterfaceType>[]);
11757
}
118-
var interface = interfaces.firstWhereOrNull(containsOverriddenMember);
119-
return interface?.accessors.firstWhere(isOverriddenMember);
12058
}
12159
}

pkg/linter/test/rules/overridden_fields_test.dart

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,20 @@ augment class A {
7070
await assertNoDiagnosticsInFile(b.path);
7171
}
7272

73+
test_conflictingFieldAndMethod() async {
74+
await assertDiagnostics(r'''
75+
class A {
76+
int x() => 0;
77+
}
78+
79+
class B extends A {
80+
int x = 9;
81+
}
82+
''', [
83+
error(CompileTimeErrorCode.CONFLICTING_FIELD_AND_METHOD, 55, 1),
84+
]);
85+
}
86+
7387
/// https://github.com/dart-lang/linter/issues/2874
7488
test_conflictingStaticAndInstance() async {
7589
await assertNoDiagnostics(r'''
@@ -115,6 +129,18 @@ class B extends A {
115129
]);
116130
}
117131

132+
test_fieldOverridesGetter() async {
133+
await assertNoDiagnostics(r'''
134+
class A {
135+
int get a => 0;
136+
}
137+
class B extends A {
138+
@override
139+
int a = 1;
140+
}
141+
''');
142+
}
143+
118144
test_mixinInheritsFromNotObject() async {
119145
// See: https://github.com/dart-lang/linter/issues/2969
120146
// Preserves existing testing logic but has so many misuses of mixins that
@@ -189,6 +215,7 @@ class GC34 extends GC33 {
189215
lint(127, 5),
190216
lint(194, 9),
191217
error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 273, 4),
218+
lint(301, 9),
192219
lint(343, 5),
193220
lint(418, 9),
194221
error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 472, 4),
@@ -203,6 +230,49 @@ class GC34 extends GC33 {
203230
]);
204231
}
205232

233+
test_overridingAbstractField() async {
234+
await assertNoDiagnostics(r'''
235+
abstract class A {
236+
abstract int x;
237+
}
238+
239+
class B extends A {
240+
@override
241+
int x = 1;
242+
}
243+
''');
244+
}
245+
246+
test_privateFieldInSameLibrary() async {
247+
await assertDiagnostics(r'''
248+
class A {
249+
int _x = 0;
250+
}
251+
252+
class B extends A {
253+
int _x = 9;
254+
}
255+
''', [
256+
error(WarningCode.UNUSED_FIELD, 16, 2),
257+
lint(53, 2),
258+
error(WarningCode.UNUSED_FIELD, 53, 2),
259+
]);
260+
}
261+
262+
test_publicFieldInSameLibrary() async {
263+
await assertDiagnostics(r'''
264+
class A {
265+
int x = 0;
266+
}
267+
268+
class B extends A {
269+
int x = 9;
270+
}
271+
''', [
272+
lint(52, 1),
273+
]);
274+
}
275+
206276
test_recursiveInterfaceInheritance() async {
207277
// Produces a recursive_interface_inheritance diagnostic.
208278
await assertDiagnostics(r'''

0 commit comments

Comments
 (0)