Skip to content

Commit

Permalink
Add new lint: unnecessary_final.
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmorgan committed Nov 11, 2019
1 parent 2c284c2 commit 61d6f57
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 0 deletions.
1 change: 1 addition & 0 deletions example/all.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ linter:
- unnecessary_await_in_return
- unnecessary_brace_in_string_interps
- unnecessary_const
- unnecessary_final
- unnecessary_getters_setters
- unnecessary_lambdas
- unnecessary_new
Expand Down
2 changes: 2 additions & 0 deletions lib/src/rules.dart
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ import 'rules/unawaited_futures.dart';
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';
Expand Down Expand Up @@ -298,6 +299,7 @@ void registerLintRules() {
..register(UnnecessaryAwaitInReturn())
..register(UnnecessaryBraceInStringInterps())
..register(UnnecessaryConst())
..register(UnnecessaryFinal())
..register(UnnecessaryNew())
..register(UnnecessaryNullAwareAssignments())
..register(UnnecessaryNullInIfNullOperators())
Expand Down
93 changes: 93 additions & 0 deletions lib/src/rules/unnecessary_final.dart
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
21 changes: 21 additions & 0 deletions test/rules/unnecessary_final.dart
Original file line number Diff line number Diff line change
@@ -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
}
}

0 comments on commit 61d6f57

Please sign in to comment.