Index: lib/src/rules/final_override_non_final.dart |
diff --git a/lib/src/rules/final_override_non_final.dart b/lib/src/rules/final_override_non_final.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ea2e99f206108077fb2014b3d3146288a50a8535 |
--- /dev/null |
+++ b/lib/src/rules/final_override_non_final.dart |
@@ -0,0 +1,102 @@ |
+// Copyright (c) 2016, 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. |
+ |
+library linter.src.rules.final_override_non_final; |
+ |
+import 'package:linter/src/linter.dart'; |
+import 'package:analyzer/dart/ast/visitor.dart'; |
+import 'package:analyzer/dart/ast/ast.dart'; |
+import 'package:analyzer/dart/element/element.dart'; |
+import 'package:analyzer/src/generated/resolver.dart'; |
+ |
+const desc = r'Final field overrides non-final field xxx'; |
+ |
+const details = r''' |
+ |
+**DO** Do not override final fields. |
+ |
+**BAD:** |
+``` |
+class Base { |
+ final Object field = 'lorem'; |
+} |
+ |
+class Bad extends Base { |
+ @override |
+ final field = 'ipsum'; |
+} |
+``` |
+ |
+**GOOD:** |
+``` |
+class Base { |
+ Object something = 'lorem'; |
+} |
+ |
+class Ok extends Base { |
+ @override |
+ Object something = 'ipsum'; |
Lasse Reichstein Nielsen
2016/04/09 22:03:37
I'd argue that this is also bad.
You are shadowing
Alexei Diaz
2016/04/10 23:22:12
Fixed
|
+} |
+``` |
+ |
+'''; |
+ |
+class FinalOverrideNonFinal extends LintRule { |
+ FinalOverrideNonFinal() |
+ : super( |
+ name: 'final_override_non_final', |
+ description: desc, |
+ details: details, |
+ group: Group.style); |
+ |
+ @override |
+ AstVisitor getVisitor() => new _Visitor(this); |
+} |
+ |
+class _Visitor extends SimpleAstVisitor { |
+ InheritanceManager _manager; |
+ |
+ final LintRule rule; |
+ _Visitor(this.rule); |
+ |
+ @override |
+ visitCompilationUnit(CompilationUnit node) { |
+ LibraryElement library = node?.element?.library; |
+ _manager = library == null ? null : new InheritanceManager(library); |
+ } |
+ |
+ @override |
+ visitFieldDeclaration(FieldDeclaration node) { |
+ void reportIfFinalFieldIsOverriden(VariableDeclaration variable) { |
+ ExecutableElement member = _getOverriddenMember(variable.element); |
+ final parentClass = member.enclosingElement as ClassElement; |
+ parentClass.fields.forEach((FieldElement field) { |
+ if (field.name == node.fields.variables.first.name.name && |
+ field.getter != null && |
+ field.setter != null) { |
+ rule.reportLint(variable.name); |
+ } |
+ }); |
+ } |
+ ; |
+ |
+ node.fields.variables |
+ .where((v) => v?.element != null && v.element.isOverride && v.isFinal) |
+ .forEach(reportIfFinalFieldIsOverriden); |
+ } |
+ |
+ ExecutableElement _getOverriddenMember(Element member) { |
+ if (member == null || _manager == null) { |
+ return null; |
+ } |
+ |
+ ClassElement classElement = |
+ member.getAncestor((element) => element is ClassElement); |
+ if (classElement == null) { |
+ return null; |
+ } |
+ |
+ return _manager.lookupInheritance(classElement, member.name); |
+ } |
+} |