-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
add avoid_final_with_getter rule
Showing
6 changed files
with
171 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
lib/src/lints/avoid_final_with_getter/avoid_final_with_getter_rule.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import 'package:analyzer/error/listener.dart'; | ||
import 'package:custom_lint_builder/custom_lint_builder.dart'; | ||
import 'package:solid_lints/src/lints/avoid_final_with_getter/avoid_final_with_getter_visitor.dart'; | ||
import 'package:solid_lints/src/models/rule_config.dart'; | ||
import 'package:solid_lints/src/models/solid_lint_rule.dart'; | ||
|
||
/// Avoid using final private fields with getters. | ||
/// | ||
/// Final private variables used in a pair with a getter | ||
/// must be changed to a final public type without a getter | ||
/// because it is the same as a public field. | ||
/// | ||
/// ### Example | ||
/// | ||
/// #### BAD: | ||
/// | ||
/// ```dart | ||
/// class MyClass { | ||
/// final int _myField = 0; | ||
/// | ||
/// int get myField => _myField; | ||
/// } | ||
/// ``` | ||
/// | ||
/// #### GOOD: | ||
/// | ||
/// ```dart | ||
/// class MyClass { | ||
/// final int myField = 0; | ||
/// } | ||
/// ``` | ||
/// | ||
class AvoidFinalWithGetterRule extends SolidLintRule { | ||
/// The [LintCode] of this lint rule that represents | ||
/// the error whether we use final private fields with getters. | ||
static const lintName = 'avoid_final_with_getter'; | ||
|
||
AvoidFinalWithGetterRule._(super.config); | ||
|
||
/// Creates a new instance of [AvoidFinalWithGetterRule] | ||
/// based on the lint configuration. | ||
factory AvoidFinalWithGetterRule.createRule(CustomLintConfigs configs) { | ||
final rule = RuleConfig( | ||
configs: configs, | ||
name: lintName, | ||
problemMessage: (_) => 'Avoid final private fields with getters.', | ||
); | ||
|
||
return AvoidFinalWithGetterRule._(rule); | ||
} | ||
|
||
@override | ||
void run( | ||
CustomLintResolver resolver, | ||
ErrorReporter reporter, | ||
CustomLintContext context, | ||
) { | ||
context.registry.addCompilationUnit((node) { | ||
final visitor = AvoidFinalWithGetterVisitor(); | ||
node.accept(visitor); | ||
|
||
for (final variable in visitor.variables) { | ||
reporter.reportErrorForNode(code, variable); | ||
} | ||
}); | ||
} | ||
} |
77 changes: 77 additions & 0 deletions
77
lib/src/lints/avoid_final_with_getter/avoid_final_with_getter_visitor.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import 'package:analyzer/dart/ast/ast.dart'; | ||
import 'package:analyzer/dart/ast/visitor.dart'; | ||
import 'package:analyzer/dart/element/element.dart'; | ||
|
||
/// A visitor that checks for final private fields with getters. | ||
/// If a final private field has a getter, it is considered as a public field. | ||
class AvoidFinalWithGetterVisitor extends RecursiveAstVisitor<void> { | ||
final _variables = <VariableDeclaration>[]; | ||
|
||
/// List of final private fields with getters | ||
Iterable<VariableDeclaration> get variables => _variables; | ||
|
||
@override | ||
void visitVariableDeclaration(VariableDeclaration node) { | ||
final isPrivate = node.declaredElement?.isPrivate ?? false; | ||
final isFinalPrivate = node.isFinal && isPrivate; | ||
|
||
if (!isFinalPrivate) return; | ||
|
||
final visitor = _GettersVisitor(node); | ||
node.parent?.parent?.parent?.accept(visitor); | ||
|
||
if (visitor.getter != null) { | ||
_variables.add(node); | ||
} | ||
super.visitVariableDeclaration(node); | ||
} | ||
} | ||
|
||
class _GettersVisitor extends RecursiveAstVisitor<void> { | ||
final VariableDeclaration variable; | ||
final String fieldName; | ||
|
||
MethodDeclaration? getter; | ||
|
||
_GettersVisitor(this.variable) | ||
: fieldName = variable.name.toString().replaceFirst('_', ''); | ||
|
||
@override | ||
void visitMethodDeclaration(MethodDeclaration node) { | ||
final name = node.name.toString(); | ||
|
||
if (name == fieldName && node.isGetter) { | ||
final nodeId = node.getterReferenceId; | ||
|
||
final variableId = variable.variableId; | ||
|
||
if (nodeId == variableId) { | ||
getter = node; | ||
} | ||
} | ||
super.visitMethodDeclaration(node); | ||
} | ||
} | ||
|
||
extension on MethodDeclaration { | ||
int? get getterReferenceId => switch (body) { | ||
ExpressionFunctionBody( | ||
expression: SimpleIdentifier( | ||
staticElement: Element( | ||
declaration: PropertyAccessorElement( | ||
variable: PropertyInducingElement(id: final int id) | ||
) | ||
) | ||
) | ||
) => | ||
id, | ||
_ => null, | ||
}; | ||
} | ||
|
||
extension on VariableDeclaration { | ||
int? get variableId => switch (declaredElement) { | ||
VariableElement(id: final int id) => id, | ||
_ => null, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,3 +59,4 @@ custom_lint: | |
- prefer_last | ||
- prefer_match_file_name | ||
- proper_super_calls | ||
- avoid_final_with_getter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// ignore_for_file: type_annotate_public_apis, prefer_match_file_name, unused_local_variable | ||
|
||
/// Check final private field with getter fail | ||
/// `avoid_final_with_getter` | ||
class Fail { | ||
// expect_lint: avoid_final_with_getter | ||
final int _myField = 0; | ||
|
||
int get myField => _myField; | ||
|
||
int get myField2 => _myField + 1; | ||
} | ||
|
||
class Good { | ||
final int myField = 0; | ||
} |