Skip to content

Commit 25e51c7

Browse files
author
shaark
committed
issue-93. added new consider_making_a_member_privat rule
1 parent 3ee83ca commit 25e51c7

26 files changed

+230
-19
lines changed

example/analysis_options.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ custom_lint:
2020
- double_literal_format
2121
- avoid_unnecessary_type_assertions
2222
- avoid_debug_print_in_release
23+
- consider_making_a_member_private
2324
- avoid_using_api:
2425
severity: info
2526
entries:

lib/analysis_options.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ custom_lint:
5252
- avoid_unused_parameters
5353
- avoid_debug_print_in_release
5454
- avoid_final_with_getter
55+
- consider_making_a_member_private
5556

5657
- cyclomatic_complexity:
5758
max_complexity: 10

lib/solid_lints.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:solid_lints/src/lints/avoid_unnecessary_type_casts/avoid_unneces
1313
import 'package:solid_lints/src/lints/avoid_unrelated_type_assertions/avoid_unrelated_type_assertions_rule.dart';
1414
import 'package:solid_lints/src/lints/avoid_unused_parameters/avoid_unused_parameters_rule.dart';
1515
import 'package:solid_lints/src/lints/avoid_using_api/avoid_using_api_rule.dart';
16+
import 'package:solid_lints/src/lints/consider_making_a_member_private/consider_making_a_member_private_rule.dart';
1617
import 'package:solid_lints/src/lints/cyclomatic_complexity/cyclomatic_complexity_rule.dart';
1718
import 'package:solid_lints/src/lints/double_literal_format/double_literal_format_rule.dart';
1819
import 'package:solid_lints/src/lints/function_lines_of_code/function_lines_of_code_rule.dart';
@@ -65,6 +66,7 @@ class _SolidLints extends PluginBase {
6566
AvoidDebugPrintInReleaseRule.createRule(configs),
6667
PreferEarlyReturnRule.createRule(configs),
6768
AvoidFinalWithGetterRule.createRule(configs),
69+
ConsiderMakingAMemberPrivateRule.createRule(configs),
6870
];
6971

7072
// Return only enabled rules
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import 'package:analyzer/error/listener.dart';
2+
import 'package:custom_lint_builder/custom_lint_builder.dart';
3+
import 'package:solid_lints/src/lints/consider_making_a_member_private/visitor/consider_making_a_member_private_visitor.dart';
4+
import 'package:solid_lints/src/models/rule_config.dart';
5+
import 'package:solid_lints/src/models/solid_lint_rule.dart';
6+
7+
/// Warns about public method, field if its not used outside.
8+
///
9+
/// ### Example:
10+
/// #### BAD:
11+
/// class X {
12+
/// only used internally
13+
/// void x() {
14+
/// ...
15+
/// }
16+
///}
17+
/// #### Good:
18+
/// class X {
19+
/// only used internally
20+
/// void _x() {
21+
/// ...
22+
/// }
23+
///}
24+
/// #### Good:
25+
/// class X {
26+
///
27+
/// void x() {
28+
/// ...
29+
/// }
30+
///}
31+
///
32+
/// class Y {
33+
///
34+
/// final x = X();
35+
///
36+
/// void y(){
37+
/// x.x();
38+
/// }
39+
/// }
40+
class ConsiderMakingAMemberPrivateRule extends SolidLintRule {
41+
/// This lint rule represents
42+
/// the error whether we use public method, field if its not used outside.
43+
static const String lintName = 'consider_making_a_member_private';
44+
45+
ConsiderMakingAMemberPrivateRule._(super.config);
46+
47+
/// Creates a new instance of [ConsiderMakingAMemberPrivateRule]
48+
/// based on the lint configuration.
49+
factory ConsiderMakingAMemberPrivateRule.createRule(
50+
CustomLintConfigs configs,
51+
) {
52+
final rule = RuleConfig(
53+
configs: configs,
54+
name: lintName,
55+
problemMessage: (_) => 'Consider making a member privat',
56+
);
57+
58+
return ConsiderMakingAMemberPrivateRule._(rule);
59+
}
60+
61+
@override
62+
void run(
63+
CustomLintResolver resolver,
64+
ErrorReporter reporter,
65+
CustomLintContext context,
66+
) {
67+
context.registry.addCompilationUnit((node) {
68+
final visitor = ConsiderMakingAMemberPrivateVisitor(node);
69+
node.visitChildren(visitor);
70+
71+
final unusedMembers = visitor.unusedPublicMembers;
72+
73+
for (final member in unusedMembers) {
74+
reporter.atNode(member, code);
75+
}
76+
});
77+
}
78+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// MIT License
2+
//
3+
// Copyright (c) 2020-2021 Dart Code Checker team
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in
13+
// all
14+
// copies or substantial portions of the Software.
15+
//
16+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
// SOFTWARE.
23+
24+
import 'package:analyzer/dart/ast/ast.dart';
25+
import 'package:analyzer/dart/ast/visitor.dart';
26+
27+
/// The AST visitor that will find lines with code.
28+
class ConsiderMakingAMemberPrivateVisitor extends RecursiveAstVisitor<void> {
29+
final CompilationUnit _node;
30+
31+
final _unusedPublicMembers = <ClassMember>{};
32+
33+
/// Returns public members that are not used as representatives of the class.
34+
Iterable<ClassMember> get unusedPublicMembers => _unusedPublicMembers;
35+
36+
/// Creates a new instance of [ConsiderMakingAMemberPrivateVisitor].
37+
ConsiderMakingAMemberPrivateVisitor(this._node);
38+
39+
@override
40+
void visitClassDeclaration(ClassDeclaration node) {
41+
final classMembers = node.members.where((member) {
42+
if (member is MethodDeclaration || member is FieldDeclaration) {
43+
final name = _getMemberName(member);
44+
return name != null && !_isPrivate(name);
45+
}
46+
return false;
47+
}).toList();
48+
49+
for (final member in classMembers) {
50+
final memberName = _getMemberName(member)!;
51+
if (!_isUsedOutsideClass(memberName, node)) {
52+
_unusedPublicMembers.add(member);
53+
}
54+
}
55+
56+
super.visitClassDeclaration(node);
57+
}
58+
59+
bool _isPrivate(String name) => name.startsWith('_');
60+
61+
String? _getMemberName(ClassMember member) {
62+
if (member is MethodDeclaration) return member.declaredElement?.name;
63+
if (member is FieldDeclaration) {
64+
final fields = member.fields.variables;
65+
return fields.isNotEmpty ? fields.first.declaredElement?.name : null;
66+
}
67+
return null;
68+
}
69+
70+
bool _isUsedOutsideClass(String memberName, ClassDeclaration classNode) {
71+
bool isUsedOutside = false;
72+
73+
_node.visitChildren(
74+
_PublicMemberUsageVisitor(
75+
memberName: memberName,
76+
classNode: classNode,
77+
onUsageFound: () {
78+
isUsedOutside = true;
79+
},
80+
),
81+
);
82+
83+
return isUsedOutside;
84+
}
85+
}
86+
87+
class _PublicMemberUsageVisitor extends RecursiveAstVisitor<void> {
88+
final String memberName;
89+
final ClassDeclaration classNode;
90+
final Function() onUsageFound;
91+
92+
_PublicMemberUsageVisitor({
93+
required this.memberName,
94+
required this.classNode,
95+
required this.onUsageFound,
96+
});
97+
98+
@override
99+
void visitSimpleIdentifier(SimpleIdentifier identifier) {
100+
if (identifier.name == memberName) {
101+
final parentClass = identifier.thisOrAncestorOfType<ClassDeclaration>();
102+
if (parentClass != classNode) {
103+
onUsageFound();
104+
}
105+
}
106+
107+
super.visitSimpleIdentifier(identifier);
108+
}
109+
}

lint_test/alphabetize_by_type_test/alphabetize_by_type_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// ignore_for_file: unused_field
1+
// ignore_for_file: unused_field, consider_making_a_member_private
22
// ignore_for_file: unused_element
33
// ignore_for_file: prefer_match_file_name
44

lint_test/analysis_options.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,4 @@ custom_lint:
5858
- prefer_match_file_name
5959
- proper_super_calls
6060
- avoid_final_with_getter
61+
- consider_making_a_member_private

lint_test/avoid_final_with_getter_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// ignore_for_file: type_annotate_public_apis, prefer_match_file_name, unused_local_variable
1+
// ignore_for_file: type_annotate_public_apis, prefer_match_file_name, unused_local_variable, consider_making_a_member_private
22

33
/// Check final private field with getter fail
44
/// `avoid_final_with_getter`

lint_test/avoid_global_state_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// ignore_for_file: type_annotate_public_apis, prefer_match_file_name, unused_local_variable
1+
// ignore_for_file: type_annotate_public_apis, prefer_match_file_name, unused_local_variable, consider_making_a_member_private
22

33
/// Check global mutable variable fail
44
/// `avoid_global_state`

lint_test/avoid_late_keyword/allow_initialized/avoid_late_keyword_allow_initialized_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// ignore_for_file: prefer_const_declarations, unused_local_variable, prefer_match_file_name
1+
// ignore_for_file: prefer_const_declarations, unused_local_variable, prefer_match_file_name, consider_making_a_member_private
22
// ignore_for_file: avoid_global_state
33

44
abstract class Animation {}

0 commit comments

Comments
 (0)