Add new lint: unnecessary_final.
diff --git a/example/all.yaml b/example/all.yaml
index 193d350..509fb7f 100644
--- a/example/all.yaml
+++ b/example/all.yaml
@@ -136,6 +136,7 @@
- unnecessary_await_in_return
- unnecessary_brace_in_string_interps
- unnecessary_const
+ - unnecessary_final
- unnecessary_getters_setters
- unnecessary_lambdas
- unnecessary_new
diff --git a/lib/src/rules.dart b/lib/src/rules.dart
index 574723b..c523f20 100644
--- a/lib/src/rules.dart
+++ b/lib/src/rules.dart
@@ -139,6 +139,7 @@
import 'rules/unnecessary_await_in_return.dart';
import 'rules/unnecessary_brace_in_string_interps.dart';
import 'rules/unnecessary_const.dart';
+import 'rules/unnecessary_final.dart';
import 'rules/unnecessary_getters_setters.dart';
import 'rules/unnecessary_lambdas.dart';
import 'rules/unnecessary_new.dart';
@@ -298,6 +299,7 @@
..register(UnnecessaryAwaitInReturn())
..register(UnnecessaryBraceInStringInterps())
..register(UnnecessaryConst())
+ ..register(UnnecessaryFinal())
..register(UnnecessaryNew())
..register(UnnecessaryNullAwareAssignments())
..register(UnnecessaryNullInIfNullOperators())
diff --git a/lib/src/rules/unnecessary_final.dart b/lib/src/rules/unnecessary_final.dart
new file mode 100644
index 0000000..d6f29f8
--- /dev/null
+++ b/lib/src/rules/unnecessary_final.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2019, 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/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+
+import '../analyzer.dart';
+
+const _desc = "Don't use `final` for local variables.";
+
+const _details = r'''
+**DON'T** use `final` for local variables.
+
+`var` is shorter, and `final` does not change the meaning of the code.
+
+**BAD:**
+```
+void badMethod() {
+ final label = 'Final or var?';
+ for (final char in ['v', 'a', 'r']) {
+ print(char);
+ }
+}
+```
+
+**GOOD:**
+```
+void goodMethod() {
+ var label = 'Final or var?';
+ for (var char in ['v', 'a', 'r']) {
+ print(char);
+ }
+}
+```
+''';
+
+class UnnecessaryFinal extends LintRule implements NodeLintRule {
+ UnnecessaryFinal()
+ : super(
+ name: 'unnecessary_final',
+ description: _desc,
+ details: _details,
+ group: Group.style);
+
+ @override
+ void registerNodeProcessors(
+ NodeLintRegistry registry, LinterContext context) {
+ final visitor = _Visitor(this);
+ registry
+ ..addFormalParameterList(this, visitor)
+ ..addForStatement(this, visitor)
+ ..addVariableDeclaration(this, visitor);
+ }
+}
+
+class _Visitor extends SimpleAstVisitor<void> {
+ final LintRule rule;
+
+ _Visitor(this.rule);
+
+ @override
+ void visitFormalParameterList(FormalParameterList parameterList) {
+ for (var node in parameterList.parameters) {
+ if (node.isFinal) {
+ rule.reportLint(node);
+ }
+ }
+ }
+
+ @override
+ void visitForStatement(ForStatement node) {
+ var forLoopParts = node.forLoopParts;
+ // If the following `if` test fails, then either the statement is not a
+ // for-each loop, or it is something like `for(a in b) { ... }`. In the
+ // second case, notice `a` is not actually declared from within the
+ // loop. `a` is a variable declared outside the loop.
+ if (forLoopParts is ForEachPartsWithDeclaration) {
+ final loopVariable = forLoopParts.loopVariable;
+
+ if (loopVariable.isFinal) {
+ rule.reportLint(loopVariable.identifier);
+ }
+ }
+ }
+
+ @override
+ void visitVariableDeclaration(VariableDeclaration node) {
+ if (node.isFinal) {
+ rule.reportLint(node.name);
+ }
+ }
+}
diff --git a/test/rules/unnecessary_final.dart b/test/rules/unnecessary_final.dart
new file mode 100644
index 0000000..3bb25cd
--- /dev/null
+++ b/test/rules/unnecessary_final.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2019, 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.
+
+// test w/ `pub run test -N unnecessary_final`
+
+void badMethod(final int x) { // LINT
+ final label = 'Final or var?'; // LINT
+ print(label);
+ for (final char in ['v', 'a', 'r']) { // LINT
+ print(((final String char) => char.length)(char)); // LINT
+ }
+}
+
+void goodMethod(int x) {
+ var label = 'Final or var?'; // OK
+ print(label);
+ for (var char in ['v', 'a', 'r']) { // OK
+ print(((String char) => char.length)(char)); // OK
+ }
+}