Skip to content
This repository was archived by the owner on Jul 16, 2023. It is now read-only.

Commit fd16bc0

Browse files
Konoshenko Vladgrafovdenisdkrutskikh
authored
feat: Prefer correct identifier length (#494)
* Prefer correct identifier name * Added rule to rules factory * Review changes * feat: formatted code * feat: moved creating validator in rule constructor * feat: moved validator file * feat: sorted alphabetical * fix: changed test case * Update lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_correct_identifier_length/utils/config_parser.dart Co-authored-by: Denis Grafov <grafov.denis@gmail.com> * fix: Den review changes * fix: Add getter and setter lint. Ignore _ in variable name * fix: Analised issue * fix: CHANGELOG.md * fix: formatted code * Update lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_correct_identifier_length/prefer_correct_identifier_length.dart Co-authored-by: Denis Grafov <grafov.denis@gmail.com> * fix: change error label * Update CHANGELOG.md Co-authored-by: Denis Grafov <grafov.denis@gmail.com> * fix: change reduce -> decrease * fix: change reduce -> decrease * fix: change reduce -> decrease * fix: change reduce -> decrease * fix: change reduce -> decrease * check const and global variable * convert to normal function * add examples and support enums * Review changes * Add lint comments Co-authored-by: Denis Grafov <grafov.denis@gmail.com> Co-authored-by: Dmitry Krutskikh <dmitry.krutskikh@gmail.com>
1 parent 21d0785 commit fd16bc0

File tree

13 files changed

+388
-1
lines changed

13 files changed

+388
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* chore: changed min `SDK` version to `2.14.0`.
66
* chore: restrict `analyzer` version to `>=2.4.0 <2.6.0`.
77
* chore: changed the supported `analyzer_plugin` version to `^0.8.0`.
8+
* feat: add static code diagnostic `prefer-correct-identifier-length`.
89

910
## 4.4.0
1011

lib/src/analyzers/lint_analyzer/rules/rules_factory.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import 'rules_list/no_magic_number/no_magic_number.dart';
2222
import 'rules_list/no_object_declaration/no_object_declaration.dart';
2323
import 'rules_list/prefer_conditional_expressions/prefer_conditional_expressions.dart';
2424
import 'rules_list/prefer_const_border_radius/prefer_const_border_radius.dart';
25+
import 'rules_list/prefer_correct_identifier_length/prefer_correct_identifier_length.dart';
2526
import 'rules_list/prefer_extracting_callbacks/prefer_extracting_callbacks.dart';
2627
import 'rules_list/prefer_intl_name/prefer_intl_name.dart';
2728
import 'rules_list/prefer_match_file_name/prefer_match_file_name.dart';
@@ -67,6 +68,8 @@ final _implementedRules = <String, Rule Function(Map<String, Object>)>{
6768
PreferConditionalExpressionsRule(config),
6869
PreferConstBorderRadiusRule.ruleId: (config) =>
6970
PreferConstBorderRadiusRule(config),
71+
PreferCorrectIdentifierLength.ruleId: (config) =>
72+
PreferCorrectIdentifierLength(config),
7073
PreferExtractingCallbacksRule.ruleId: (config) =>
7174
PreferExtractingCallbacksRule(config),
7275
PreferIntlNameRule.ruleId: (config) => PreferIntlNameRule(config),
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import 'package:analyzer/dart/ast/ast.dart';
2+
3+
import '../../../../../utils/node_utils.dart';
4+
import '../../../lint_utils.dart';
5+
import '../../../metrics/scope_visitor.dart';
6+
import '../../../models/internal_resolved_unit_result.dart';
7+
import '../../../models/issue.dart';
8+
import '../../../models/severity.dart';
9+
import '../../models/common_rule.dart';
10+
import '../../models/rule_documentation.dart';
11+
import '../../rule_utils.dart';
12+
13+
part 'utils/config_parser.dart';
14+
15+
part 'validator.dart';
16+
17+
part 'visitor.dart';
18+
19+
class PreferCorrectIdentifierLength extends CommonRule {
20+
static const String ruleId = 'prefer-correct-identifier-length';
21+
final _Validator _validator;
22+
23+
PreferCorrectIdentifierLength([Map<String, Object> config = const {}])
24+
: _validator = _Validator(
25+
_ConfigParser.readMaxIdentifierLength(config),
26+
_ConfigParser.readMinIdentifierLength(config),
27+
_ConfigParser.readExceptions(config),
28+
),
29+
super(
30+
id: ruleId,
31+
documentation: const RuleDocumentation(
32+
name: 'Prefer correct identifier length',
33+
brief: 'Warns when identifier name length very short or long.',
34+
),
35+
severity: readSeverity(config, Severity.style),
36+
excludes: readExcludes(config),
37+
);
38+
39+
@override
40+
Iterable<Issue> check(InternalResolvedUnitResult source) {
41+
final visitor = _Visitor(_validator);
42+
43+
source.unit.visitChildren(visitor);
44+
45+
return visitor.nodes
46+
.map(
47+
(node) => createIssue(
48+
rule: this,
49+
location: nodeLocation(node: node, source: source),
50+
message: createErrorMessage(node.name),
51+
),
52+
)
53+
.toList(growable: false);
54+
}
55+
56+
String createErrorMessage(String name) => name.length > _validator.maxLength
57+
? "The $name identifier is ${name.length} characters long. It's recommended to decrease it to ${_validator.maxLength} chars long."
58+
: "The $name identifier is ${name.length} characters long. It's recommended to increase it up to ${_validator.minLength} chars long.";
59+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
part of '../prefer_correct_identifier_length.dart';
2+
3+
const _defaultMinIdentifierLength = 3;
4+
const _defaultMaxIdentifierLength = 300;
5+
const _defaultExceptions = <String>[];
6+
7+
const _minIdentifierLengthLabel = 'min-identifier-length';
8+
const _maxIdentifierLengthLabel = 'max-identifier-length';
9+
const _exceptionsLabel = 'exceptions';
10+
11+
/// Parser for rule configuration
12+
class _ConfigParser {
13+
/// Read min identifier length from config
14+
static int readMinIdentifierLength(Map<String, Object> config) =>
15+
_parseIntConfig(config[_minIdentifierLengthLabel]) ??
16+
_defaultMinIdentifierLength;
17+
18+
/// Read max identifier length from config
19+
static int readMaxIdentifierLength(Map<String, Object> config) =>
20+
_parseIntConfig(config[_maxIdentifierLengthLabel]) ??
21+
_defaultMaxIdentifierLength;
22+
23+
/// Read exceptions list from config
24+
static Iterable<String> readExceptions(Map<String, Object> config) =>
25+
_isIterableOfStrings(config[_exceptionsLabel])
26+
? (config[_exceptionsLabel] as Iterable).cast<String>()
27+
: _defaultExceptions;
28+
29+
static int? _parseIntConfig(Object? value) =>
30+
value != null ? int.tryParse(value.toString()) : null;
31+
32+
static bool _isIterableOfStrings(Object? object) =>
33+
object is Iterable<Object> && object.every((node) => node is String);
34+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
part of 'prefer_correct_identifier_length.dart';
2+
3+
class _Validator {
4+
final int maxLength;
5+
final int minLength;
6+
final Iterable<String> exceptions;
7+
8+
_Validator(this.maxLength, this.minLength, this.exceptions);
9+
10+
bool isValid(SimpleIdentifier identifier) =>
11+
_validate(_getNameWithoutUnderscore(identifier.name));
12+
13+
bool _validate(String name) =>
14+
exceptions.contains(name) ||
15+
(name.length >= minLength && name.length <= maxLength);
16+
17+
String _getNameWithoutUnderscore(String name) =>
18+
name.startsWith('_') ? name.replaceFirst('_', '') : name;
19+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
part of 'prefer_correct_identifier_length.dart';
2+
3+
class _Visitor extends ScopeVisitor {
4+
final _declarationNodes = <SimpleIdentifier>[];
5+
final _Validator validator;
6+
7+
_Visitor(this.validator);
8+
9+
Iterable<SimpleIdentifier> get nodes => _declarationNodes;
10+
11+
@override
12+
void visitMethodDeclaration(MethodDeclaration node) {
13+
super.visitMethodDeclaration(node);
14+
15+
if (node.isGetter || node.isSetter && !validator.isValid(node.name)) {
16+
_declarationNodes.add(node.name);
17+
}
18+
}
19+
20+
@override
21+
void visitEnumDeclaration(EnumDeclaration node) {
22+
super.visitEnumDeclaration(node);
23+
24+
for (final node in node.constants) {
25+
_declarationNodes.add(node.name);
26+
}
27+
}
28+
29+
@override
30+
void visitVariableDeclaration(VariableDeclaration node) {
31+
super.visitVariableDeclaration(node);
32+
33+
if (!validator.isValid(node.name)) {
34+
_declarationNodes.add(node.name);
35+
}
36+
}
37+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
class Example {
2+
final x = 0; // LINT
3+
final y = 0; // LINT
4+
final z = 0;
5+
final zyt = 0;
6+
final property = 0;
7+
final multiplatformConfig = 0; // LINT
8+
final multiplatformConfigurationPoint = 0; // LINT
9+
10+
Example.todo() {
11+
final u = 1; // LINT
12+
const i = 1; // LINT
13+
}
14+
15+
Example._() {
16+
final u = 1; // LINT
17+
const i = 1; // LINT
18+
}
19+
20+
bool get o => false; // LINT
21+
22+
bool set p() => true; // LINT
23+
24+
void test() {
25+
final u = 1; // LINT
26+
const i = 1; // LINT
27+
}
28+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
void test() {
2+
final zy = 0; // LINT
3+
final _ze = 1; // LINT
4+
}
5+
6+
final u = 1; // LINT
7+
const i = 1; // LINT
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
enum Enum {
2+
u, // LINT
3+
i, // LINT
4+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
extension Extension on String {
2+
onExtension() {
3+
final u = 1; // LINT
4+
const i = 1; // LINT
5+
}
6+
}

0 commit comments

Comments
 (0)