Skip to content

Commit

Permalink
issue-93. added more test case
Browse files Browse the repository at this point in the history
  • Loading branch information
shaark committed Dec 5, 2024
1 parent 25e51c7 commit fef0045
Show file tree
Hide file tree
Showing 17 changed files with 162 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,18 @@ class ConsiderMakingAMemberPrivateRule extends SolidLintRule {
node.visitChildren(visitor);

final unusedMembers = visitor.unusedPublicMembers;
final unusedGlobalVariables = visitor.unusedGlobalVariables;
final unusedGlobalFunctions = visitor.unusedGlobalFunctions;

for (final member in unusedMembers) {
reporter.atNode(member, code);
}
for (final variable in unusedGlobalVariables) {
reporter.atNode(variable, code);
}
for (final function in unusedGlobalFunctions) {
reporter.atNode(function, code);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,48 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';

/// The AST visitor that will find lines with code.
/// AST Visitor for identifying unused public members, global functions,
/// and variables.
class ConsiderMakingAMemberPrivateVisitor extends RecursiveAstVisitor<void> {
final CompilationUnit _node;

final _unusedPublicMembers = <ClassMember>{};
final _unusedGlobalFunctions = <FunctionDeclaration>{};
final _unusedGlobalVariables = <VariableDeclaration>{};

/// Returns public members that are not used as representatives of the class.
/// Returns unused public members of classes.
Iterable<ClassMember> get unusedPublicMembers => _unusedPublicMembers;

/// Creates a new instance of [ConsiderMakingAMemberPrivateVisitor].
/// Returns unused global functions.
Iterable<FunctionDeclaration> get unusedGlobalFunctions =>
_unusedGlobalFunctions;

/// Returns unused global variables.
Iterable<VariableDeclaration> get unusedGlobalVariables =>
_unusedGlobalVariables;

/// Constructor for [ConsiderMakingAMemberPrivateVisitor]
ConsiderMakingAMemberPrivateVisitor(this._node);

@override
void visitClassDeclaration(ClassDeclaration node) {
// Check for unused public members in a class.
final classMembers = node.members.where((member) {
if (member is MethodDeclaration || member is FieldDeclaration) {
final name = _getMemberName(member);
return name != null && !_isPrivate(name);
}
if (member is ConstructorDeclaration) {
final name = _getMemberName(member);
if (name == null) return true;

return !_isPrivate(name);
}
return false;
}).toList();

for (final member in classMembers) {
final memberName = _getMemberName(member)!;
final memberName = _getMemberName(member);
if (!_isUsedOutsideClass(memberName, node)) {
_unusedPublicMembers.add(member);
}
Expand All @@ -56,54 +74,105 @@ class ConsiderMakingAMemberPrivateVisitor extends RecursiveAstVisitor<void> {
super.visitClassDeclaration(node);
}

bool _isPrivate(String name) => name.startsWith('_');
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
final name = node.declaredElement?.name;
if (!_isPrivate(name) && !_isUsedEntity(name)) {
_unusedGlobalFunctions.add(node);
}
super.visitFunctionDeclaration(node);
}

@override
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
for (final variable in node.variables.variables) {
final name = variable.declaredElement?.name;
if (!_isPrivate(name) && !_isUsedEntity(name)) {
_unusedGlobalVariables.add(variable);
}
}
super.visitTopLevelVariableDeclaration(node);
}

bool _isPrivate(String? name) => name?.startsWith('_') ?? false;

String? _getMemberName(ClassMember member) {
if (member is MethodDeclaration) return member.declaredElement?.name;
if (member is FieldDeclaration) {
final fields = member.fields.variables;
return fields.isNotEmpty ? fields.first.declaredElement?.name : null;
}
if (member is ConstructorDeclaration) {
return member.declaredElement?.name;
}
return null;
}

bool _isUsedOutsideClass(String memberName, ClassDeclaration classNode) {
bool _isUsedOutsideClass(String? memberName, ClassDeclaration classNode) {
bool isUsedOutside = false;

_node.visitChildren(
_PublicMemberUsageVisitor(
memberName: memberName,
classNode: classNode,
_GlobalEntityUsageVisitor(
entityName: memberName!,
onUsageFound: () {
isUsedOutside = true;
},
),
);

if (memberName.isEmpty) return true;

return isUsedOutside;
}

bool _isUsedEntity(String? entityName) {
bool isUsed = false;

if (entityName == null) return false;

_node.visitChildren(
_GlobalEntityUsageVisitor(
entityName: entityName,
onUsageFound: () {
isUsed = true;
},
),
);

return isUsed;
}
}

class _PublicMemberUsageVisitor extends RecursiveAstVisitor<void> {
final String memberName;
final ClassDeclaration classNode;
class _GlobalEntityUsageVisitor extends RecursiveAstVisitor<void> {
final String entityName;
final Function() onUsageFound;

_PublicMemberUsageVisitor({
required this.memberName,
required this.classNode,
_GlobalEntityUsageVisitor({
required this.entityName,
required this.onUsageFound,
});

@override
void visitSimpleIdentifier(SimpleIdentifier identifier) {
if (identifier.name == memberName) {
final parentClass = identifier.thisOrAncestorOfType<ClassDeclaration>();
if (parentClass != classNode) {
onUsageFound();
}
if (identifier.name == entityName) {
onUsageFound();
}

super.visitSimpleIdentifier(identifier);
}

@override
void visitInstanceCreationExpression(InstanceCreationExpression node) {
if (node.constructorName.name?.name == entityName) {
onUsageFound();
}
super.visitInstanceCreationExpression(node);
}

@override
void visitMethodInvocation(MethodInvocation node) {
if (node.target != null && node.target.toString() == entityName) {
onUsageFound();
}
super.visitMethodInvocation(node);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: unused_local_variable
// ignore_for_file: unused_local_variable, consider_making_a_member_private

import 'package:flutter/foundation.dart' as f;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: unused_local_variable
// ignore_for_file: unused_local_variable, consider_making_a_member_private

import 'package:flutter/foundation.dart';

Expand Down
2 changes: 1 addition & 1 deletion lint_test/avoid_unnecessary_type_assertions_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: prefer_const_declarations, prefer_match_file_name, cyclomatic_complexity, unused_element
// ignore_for_file: prefer_const_declarations, prefer_match_file_name, cyclomatic_complexity, unused_element, consider_making_a_member_private
// ignore_for_file: unnecessary_nullable_for_final_variable_declarations
// ignore_for_file: unnecessary_type_check
// ignore_for_file: unused_local_variable
Expand Down
2 changes: 1 addition & 1 deletion lint_test/avoid_unnecessary_type_casts_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: prefer_const_declarations
// ignore_for_file: prefer_const_declarations, consider_making_a_member_private
// ignore_for_file: unnecessary_nullable_for_final_variable_declarations
// ignore_for_file: unnecessary_cast
// ignore_for_file: unused_local_variable
Expand Down
2 changes: 1 addition & 1 deletion lint_test/avoid_unrelated_type_assertions_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: prefer_const_declarations, prefer_match_file_name, unused_element
// ignore_for_file: prefer_const_declarations, prefer_match_file_name, unused_element, consider_making_a_member_private
// ignore_for_file: unnecessary_nullable_for_final_variable_declarations
// ignore_for_file: unused_local_variable

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
//ignore_for_file:consider_making_a_member_private
// expect_lint: avoid_global_state
int banned = 5;
54 changes: 50 additions & 4 deletions lint_test/consider_making_a_member_private_test.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,65 @@
// ignore_for_file: no_empty_block, prefer_match_file_name, unused_element, member_ordering
// ignore_for_file: no_empty_block, prefer_match_file_name, unused_element, member_ordering, avoid_global_state, avoid_unused_parameters
/// Check the `consider_making_a_member_private` rule
///
// expect_lint:consider_making_a_member_private
const int unusedGlobalVariables = 0;

//no lint
const int usedGlobalVariables = 0;

// expect_lint:consider_making_a_member_private
void unusedGLobalFunction() {}

//no lint
void usedGLobalFunction() {}

class X {
// expect_lint:consider_making_a_member_private
void unusedX() {}

// no lint
void usedX() {}
// expect_lint:consider_making_a_member_private
final int unusedFinalX = 0;
// expect_lint:consider_making_a_member_private
static final int unusedStaticX = 0;

// expect_lint:consider_making_a_member_private
int unusedMutableX = 0;

// expect_lint:consider_making_a_member_private
int get unusedGetX => 0;

// expect_lint:consider_making_a_member_private
set unusedSetX(int y) {}

// no lint
void usedMethodX() {}

// expect_lint:consider_making_a_member_private
static void unusedStaticMethodX() {}

// no lint
X();

// expect_lint:consider_making_a_member_private
X.withValue({
required this.unusedMutableX,
});

// expect_lint:consider_making_a_member_private
factory X.factory() => X();

// no lint
factory X.usedFactory() => X();
}

class Y {
// no lint
void _y() {
final x = X();
x.usedX();
X.usedFactory();
x.usedMethodX();
usedGLobalFunction();
usedGlobalVariables;
}
}
2 changes: 1 addition & 1 deletion lint_test/no_equal_then_else_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: unused_local_variable
// ignore_for_file: unused_local_variable, consider_making_a_member_private
// ignore_for_file: cyclomatic_complexity
// ignore_for_file: no_magic_number
// ignore_for_file: prefer_conditional_expressions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: avoid_returning_widgets
// ignore_for_file: avoid_returning_widgets, consider_making_a_member_private
// ignore_for_file: prefer_match_file_name

// Allowed for numbers in a Widget subtype parameters.
Expand Down
1 change: 1 addition & 0 deletions lint_test/number_of_parameters_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: consider_making_a_member_private
/// Check number of parameters fail
///
/// `number_of_parameters: max_parameters`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: unused_local_variable
// ignore_for_file: unused_local_variable,consider_making_a_member_private
// ignore_for_file: cyclomatic_complexity
// ignore_for_file: no_equal_then_else

Expand Down
2 changes: 1 addition & 1 deletion lint_test/prefer_conditional_expressions_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: unused_local_variable
// ignore_for_file: unused_local_variable, consider_making_a_member_private
// ignore_for_file: cyclomatic_complexity
// ignore_for_file: no_equal_then_else
// ignore_for_file: dead_code
Expand Down
2 changes: 1 addition & 1 deletion lint_test/prefer_early_return_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: dead_code, cyclomatic_complexity, no_equal_then_else, prefer_match_file_name
// ignore_for_file: dead_code, cyclomatic_complexity, no_equal_then_else, prefer_match_file_name, consider_making_a_member_private

// ignore: no_empty_block
void _doSomething() {}
Expand Down
1 change: 1 addition & 0 deletions lint_test/prefer_first_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: consider_making_a_member_private
/// Check the `prefer_first` rule
void fun() {
const zero = 0;
Expand Down
1 change: 1 addition & 0 deletions lint_test/prefer_last_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore_for_file: consider_making_a_member_private
/// Check the `prefer_first` rule
void fun() {
final list = [0, 1, 2, 3];
Expand Down

0 comments on commit fef0045

Please sign in to comment.