add lint unnecessary_nullable_for_final_variable_declarations
diff --git a/example/all.yaml b/example/all.yaml
index 3655b01..d68d3bf 100644
--- a/example/all.yaml
+++ b/example/all.yaml
@@ -151,6 +151,7 @@
- unnecessary_getters_setters
- unnecessary_lambdas
- unnecessary_new
+ - unnecessary_nullable_for_final_variable_declarations
- unnecessary_null_aware_assignments
- unnecessary_null_in_if_null_operators
- unnecessary_overrides
diff --git a/lib/src/rules.dart b/lib/src/rules.dart
index 61e7688..6f46a52 100644
--- a/lib/src/rules.dart
+++ b/lib/src/rules.dart
@@ -156,6 +156,7 @@
import 'rules/unnecessary_new.dart';
import 'rules/unnecessary_null_aware_assignments.dart';
import 'rules/unnecessary_null_in_if_null_operators.dart';
+import 'rules/unnecessary_nullable_for_final_variable_declarations.dart';
import 'rules/unnecessary_overrides.dart';
import 'rules/unnecessary_parenthesis.dart';
import 'rules/unnecessary_raw_strings.dart';
@@ -336,6 +337,7 @@
//..register(UnnecessaryGetters())
..register(UnnecessaryGettersSetters())
..register(UnnecessaryLambdas())
+ ..register(UnnecessaryNullableForFinalVariableDeclarations())
..register(UnnecessaryOverrides())
..register(UnnecessaryParenthesis())
..register(UnnecessaryRawStrings())
diff --git a/lib/src/rules/unnecessary_nullable_for_final_variable_declarations.dart b/lib/src/rules/unnecessary_nullable_for_final_variable_declarations.dart
new file mode 100644
index 0000000..61a5f67
--- /dev/null
+++ b/lib/src/rules/unnecessary_nullable_for_final_variable_declarations.dart
@@ -0,0 +1,108 @@
+// Copyright (c) 2020, 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/analysis/features.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+
+import '../analyzer.dart';
+
+const _desc = r'Use non-nullable type '
+ 'for final variable initialized with non-nullable value.';
+
+const _details = r'''
+
+Use non-nullable type for final variable initialized with non-nullable value.
+
+**BAD:**
+```
+final int? i = 1;
+```
+
+**GOOD:**
+```
+final int i = 1;
+```
+
+''';
+
+class UnnecessaryNullableForFinalVariableDeclarations extends LintRule
+ implements NodeLintRule {
+ UnnecessaryNullableForFinalVariableDeclarations()
+ : super(
+ name: 'unnecessary_nullable_for_final_variable_declarations',
+ description: _desc,
+ details: _details,
+ maturity: Maturity.experimental,
+ group: Group.style);
+
+ @override
+ void registerNodeProcessors(NodeLintRegistry registry,
+ [LinterContext context]) {
+ final visitor = _Visitor(this, context);
+ registry.addCompilationUnit(this, visitor);
+ registry.addFieldDeclaration(this, visitor);
+ registry.addTopLevelVariableDeclaration(this, visitor);
+ registry.addVariableDeclarationStatement(this, visitor);
+ }
+}
+
+class _Visitor extends SimpleAstVisitor<void> {
+ _Visitor(this.rule, this.context);
+
+ final LintRule rule;
+ final LinterContext context;
+
+ bool _isNonNullableEnabled;
+
+ @override
+ void visitCompilationUnit(CompilationUnit node) {
+ _isNonNullableEnabled = node.featureSet.isEnabled(Feature.non_nullable);
+ }
+
+ @override
+ void visitFieldDeclaration(FieldDeclaration node) {
+ if (!_isNonNullableEnabled) return;
+
+ for (var variable in node.fields.variables) {
+ // We could also include public members in private classes but to do that
+ // we'd need to ensure that there are no instances of either the
+ // enclosing class or any subclass of the enclosing class that are ever
+ // accessible outside this library.
+ if (Identifier.isPrivateName(variable.name.name) || node.isStatic) {
+ _visit(variable);
+ }
+ }
+ }
+
+ @override
+ void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+ if (!_isNonNullableEnabled) return;
+
+ node.variables.variables.forEach(_visit);
+ }
+
+ @override
+ void visitVariableDeclarationStatement(VariableDeclarationStatement node) {
+ if (!_isNonNullableEnabled) return;
+
+ node.variables.variables.forEach(_visit);
+ }
+
+ void _visit(VariableDeclaration variable) {
+ if (!variable.isFinal && !variable.isConst) {
+ return;
+ }
+ if (variable.isSynthetic) {
+ return;
+ }
+ if (variable.initializer == null) {
+ return;
+ }
+ if (context.typeSystem.isNullable(variable.declaredElement.type) &&
+ context.typeSystem.isNonNullable(variable.initializer.staticType)) {
+ rule.reportLint(variable);
+ }
+ }
+}
diff --git a/test/rules/experiments/nnbd/rules/unnecessary_nullable_for_final_variable_declarations.dart b/test/rules/experiments/nnbd/rules/unnecessary_nullable_for_final_variable_declarations.dart
new file mode 100644
index 0000000..7ead35b
--- /dev/null
+++ b/test/rules/experiments/nnbd/rules/unnecessary_nullable_for_final_variable_declarations.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2020, 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_nullable_for_final_variable_declarations`
+
+final int? _i = 1; // LINT
+final int _j = 1; // OK
+final int? i = 1; // LINT
+final int j = 1; // OK
+const int? i = 1; // LINT
+const int j = 1; // OK
+
+class A {
+ final int? _i = 1; // LINT
+ final int _j = 1; // OK
+ final int? i = 1; // OK (may be overriden or may override)
+ final int j = 1; // OK
+ static final int? si = 1; // LINT
+ static final int sj = 1; // OK
+}
+
+extension E on A {
+ static final int? _e1i = 1; // LINT
+ static final int _e1j = 1; // OK
+ static final int? e1i = 1; // LINT
+ static final int e1j = 1; // OK
+}
+
+m() {
+ final int? _i = 1; // LINT
+ final int _j = 1; // OK
+ final int? i = 1; // LINT
+ final int j = 1; // OK
+}
diff --git a/test/rules/unnecessary_nullable_for_final_variable_declarations.dart b/test/rules/unnecessary_nullable_for_final_variable_declarations.dart
new file mode 100644
index 0000000..65718b8
--- /dev/null
+++ b/test/rules/unnecessary_nullable_for_final_variable_declarations.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2020, 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_nullable_for_final_variable_declarations`
+
+final int _i = 1; // OK