Skip to content

Commit

Permalink
Issue 167 1 (#186)
Browse files Browse the repository at this point in the history
* issue-167. extract exclude rule code

* issue-167. fixed null check

* issue-167. fixed after comments

* issue-167. fixed after comments

* issue-167. added ingore parametrs to some lints

* issue-167. fixed comments

* issue-167. fixed after comments

* issue-167. fixed after comments

* issue-167. fixed no_empty_block_rule format

* issue-167. fixed after comments

* issue-167. fixed after comments

* issue-167. chaged test

* issue-167. fixed after comments

---------

Co-authored-by: shaark <[email protected]>
  • Loading branch information
StarovNikita and shaark authored Dec 6, 2024
1 parent 3ee83ca commit 3e1711b
Show file tree
Hide file tree
Showing 23 changed files with 274 additions and 61 deletions.
11 changes: 9 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
## 0.2.4

## 0.3.0
- Added `exclude` parameter for the following lints:
- `avoid_returning_widgets`
- `avoid_unused_parameters`
- `cyclomatic_complexity`
- `function_lines_of_code`
- `no_empty_bloc`
- `number_of_parameters`
- BREAKING CHANGE: Renamed `excludeNames` parameter to `exclude` for `function_lines_of_code` lint.
- Fixed an issue with `prefer_early_retrun` for throw expression

## 0.2.3
Expand Down
10 changes: 7 additions & 3 deletions lib/src/common/parameters/excluded_identifier_parameter.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
/// Model class for ExcludeRule parameters
class ExcludedIdentifierParameter {
/// The name of the method that should be excluded from the lint.
final String methodName;
final String? methodName;

/// The name of the class that should be excluded from the lint.
final String? className;

/// The name of the plain Strings that should be excluded from the lint
final String? declarationName;

/// Constructor for [ExcludedIdentifierParameter] model
const ExcludedIdentifierParameter({
required this.methodName,
required this.className,
this.methodName,
this.className,
this.declarationName,
});

///
Expand Down
38 changes: 35 additions & 3 deletions lib/src/common/parameters/excluded_identifiers_list_parameter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,51 @@ class ExcludedIdentifiersListParameter {
for (final item in excludeList) {
if (item is Map) {
exclude.add(ExcludedIdentifierParameter.fromJson(item));
} else if (item is String) {
exclude.add(
ExcludedIdentifierParameter(
declarationName: item,
),
);
}
}
return ExcludedIdentifiersListParameter(
exclude: exclude,
);
}

/// Method for creating from json data with default params
factory ExcludedIdentifiersListParameter.defaultFromJson(
Map<String, dynamic> json,
) {
final excludeList =
json[ExcludedIdentifiersListParameter.excludeParameterName]
as Iterable? ??
[];

return ExcludedIdentifiersListParameter.fromJson(
excludeList: excludeList,
);
}

/// Returns whether the target node should be ignored during analysis.
bool shouldIgnore(Declaration node) {
final methodName = node.declaredElement?.name;
final declarationName = node.declaredElement?.name;

final excludedItem =
exclude.firstWhereOrNull((e) => e.methodName == methodName);
final excludedItem = exclude.firstWhereOrNull(
(e) {
if (e.declarationName == declarationName) {
return true;
} else if (node is ClassDeclaration) {
return e.className == declarationName;
} else if (node is MethodDeclaration) {
return e.methodName == declarationName;
} else if (node is FunctionDeclaration) {
return e.methodName == declarationName;
}
return false;
},
);

if (excludedItem == null) return false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ class AvoidReturningWidgetsParameters {
/// Method for creating from json data
factory AvoidReturningWidgetsParameters.fromJson(Map<String, dynamic> json) {
return AvoidReturningWidgetsParameters(
exclude: ExcludedIdentifiersListParameter.fromJson(
excludeList: json[ExcludedIdentifiersListParameter.excludeParameterName]
as Iterable? ??
[],
),
exclude: ExcludedIdentifiersListParameter.defaultFromJson(json),
);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';
import 'package:solid_lints/src/lints/avoid_unused_parameters/models/avoid_unused_parameters.dart';
import 'package:solid_lints/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart';
import 'package:solid_lints/src/models/rule_config.dart';
import 'package:solid_lints/src/models/solid_lint_rule.dart';
Expand Down Expand Up @@ -64,7 +65,7 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart';
/// };
///
/// ```
class AvoidUnusedParametersRule extends SolidLintRule {
class AvoidUnusedParametersRule extends SolidLintRule<AvoidUnusedParameters> {
/// This lint rule represents
/// the error whether we use bad formatted double literals.
static const String lintName = 'avoid_unused_parameters';
Expand All @@ -79,6 +80,7 @@ class AvoidUnusedParametersRule extends SolidLintRule {
final rule = RuleConfig(
configs: configs,
name: lintName,
paramsParser: AvoidUnusedParameters.fromJson,
problemMessage: (_) => 'Parameter is unused.',
);

Expand All @@ -91,7 +93,11 @@ class AvoidUnusedParametersRule extends SolidLintRule {
ErrorReporter reporter,
CustomLintContext context,
) {
context.registry.addCompilationUnit((node) {
context.registry.addDeclaration((node) {
final isIgnored = config.parameters.exclude.shouldIgnore(node);

if (isIgnored) return;

final visitor = AvoidUnusedParametersVisitor();
node.accept(visitor);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:solid_lints/src/common/parameters/excluded_identifiers_list_parameter.dart';

/// A data model class that represents the "avoid returning widgets" input
/// parameters.
class AvoidUnusedParameters {
/// A list of methods that should be excluded from the lint.
final ExcludedIdentifiersListParameter exclude;

/// Constructor for [AvoidUnusedParameters] model
AvoidUnusedParameters({
required this.exclude,
});

/// Method for creating from json data
factory AvoidUnusedParameters.fromJson(Map<String, dynamic> json) {
return AvoidUnusedParameters(
exclude: ExcludedIdentifiersListParameter.defaultFromJson(json),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,19 @@ class CyclomaticComplexityRule
CustomLintContext context,
) {
context.registry.addBlockFunctionBody((node) {
final visitor = CyclomaticComplexityFlowVisitor();
node.visitChildren(visitor);
context.registry.addDeclaration((declarationNode) {
final isIgnored =
config.parameters.exclude.shouldIgnore(declarationNode);
if (isIgnored) return;

if (visitor.complexityEntities.length + 1 >
config.parameters.maxComplexity) {
reporter.atNode(node, code);
}
final visitor = CyclomaticComplexityFlowVisitor();
node.visitChildren(visitor);

if (visitor.complexityEntities.length + 1 >
config.parameters.maxComplexity) {
reporter.atNode(node, code);
}
});
});
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import 'package:solid_lints/src/common/parameters/excluded_identifiers_list_parameter.dart';

/// Cyclomatic complexity metric limits configuration.
class CyclomaticComplexityParameters {
/// Threshold cyclomatic complexity level, exceeding it triggers a warning.
final int maxComplexity;

/// A list of methods that should be excluded from the lint.
final ExcludedIdentifiersListParameter exclude;

/// Reference: NIST 500-235 item 2.5
static const _defaultMaxComplexity = 10;

/// Constructor for [CyclomaticComplexityParameters] model
const CyclomaticComplexityParameters({
required this.maxComplexity,
required this.exclude,
});

/// Method for creating from json data
factory CyclomaticComplexityParameters.fromJson(Map<String, Object?> json) =>
CyclomaticComplexityParameters(
maxComplexity: json['max_complexity'] as int? ?? _defaultMaxComplexity,
exclude: ExcludedIdentifiersListParameter.defaultFromJson(json),
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,22 @@ class FunctionLinesOfCodeRule
) {
void checkNode(AstNode node) => _checkNode(resolver, reporter, node);

context.registry.addMethodDeclaration(checkNode);
context.registry.addFunctionDeclaration(checkNode);
context.registry.addFunctionExpression(checkNode);
context.registry.addDeclaration((declarationNode) {
final isIgnored = config.parameters.exclude.shouldIgnore(declarationNode);

if (isIgnored) return;

context.registry.addMethodDeclaration(checkNode);
context.registry.addFunctionDeclaration(checkNode);
context.registry.addFunctionExpression(checkNode);
});
}

void _checkNode(
CustomLintResolver resolver,
ErrorReporter reporter,
AstNode node,
) {
final functionName = _getFunctionName(node);
if (functionName != null &&
config.parameters.excludeNames.contains(functionName)) {
return;
}

final visitor = FunctionLinesOfCodeVisitor(resolver.lineInfo);
node.visitChildren(visitor);

Expand All @@ -84,16 +84,4 @@ class FunctionLinesOfCodeRule
);
}
}

String? _getFunctionName(AstNode node) {
if (node is FunctionDeclaration) {
return node.name.lexeme;
} else if (node is MethodDeclaration) {
return node.name.lexeme;
} else if (node is FunctionExpression) {
return node.declaredElement?.name;
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import 'package:solid_lints/src/common/parameters/excluded_identifiers_list_parameter.dart';

/// A data model class that represents the "function lines of code" input
/// parameters.
class FunctionLinesOfCodeParameters {
/// Maximum allowed number of lines of code (LoC) per function,
/// exceeding this limit triggers a warning.
final int maxLines;

/// Function names to be excluded from the rule check
final List<String> excludeNames;
/// A list of methods that should be excluded from the lint.
final ExcludedIdentifiersListParameter exclude;

static const _defaultMaxLines = 200;

/// Constructor for [FunctionLinesOfCodeParameters] model
const FunctionLinesOfCodeParameters({
required this.maxLines,
required this.excludeNames,
required this.exclude,
});

/// Method for creating from json data
factory FunctionLinesOfCodeParameters.fromJson(Map<String, Object?> json) =>
FunctionLinesOfCodeParameters(
maxLines: json['max_lines'] as int? ?? _defaultMaxLines,
excludeNames:
List<String>.from(json['excludeNames'] as Iterable? ?? []),
exclude: ExcludedIdentifiersListParameter.defaultFromJson(json),
);
}
20 changes: 20 additions & 0 deletions lib/src/lints/no_empty_block/models/no_empty_block_parameters.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:solid_lints/src/common/parameters/excluded_identifiers_list_parameter.dart';

/// A data model class that represents the "no empty block" lint input
/// parameters.
class NoEmptyBlockParameters {
/// A list of methods that should be excluded from the lint.
final ExcludedIdentifiersListParameter exclude;

/// Constructor for [NoEmptyBlockParameters] model
NoEmptyBlockParameters({
required this.exclude,
});

/// Method for creating from json data
factory NoEmptyBlockParameters.fromJson(Map<String, dynamic> json) {
return NoEmptyBlockParameters(
exclude: ExcludedIdentifiersListParameter.defaultFromJson(json),
);
}
}
9 changes: 7 additions & 2 deletions lib/src/lints/no_empty_block/no_empty_block_rule.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';
import 'package:solid_lints/src/lints/no_empty_block/models/no_empty_block_parameters.dart';
import 'package:solid_lints/src/lints/no_empty_block/visitors/no_empty_block_visitor.dart';
import 'package:solid_lints/src/models/rule_config.dart';
import 'package:solid_lints/src/models/solid_lint_rule.dart';
Expand Down Expand Up @@ -49,7 +50,7 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart';
/// } catch (_) {} // ignored by this rule
/// }
/// ```
class NoEmptyBlockRule extends SolidLintRule {
class NoEmptyBlockRule extends SolidLintRule<NoEmptyBlockParameters> {
/// This lint rule represents
/// the error whether left empty block.
static const String lintName = 'no_empty_block';
Expand All @@ -62,6 +63,7 @@ class NoEmptyBlockRule extends SolidLintRule {
final config = RuleConfig(
configs: configs,
name: lintName,
paramsParser: NoEmptyBlockParameters.fromJson,
problemMessage: (_) =>
'Block is empty. Empty blocks are often indicators of missing code.',
);
Expand All @@ -75,7 +77,10 @@ class NoEmptyBlockRule extends SolidLintRule {
ErrorReporter reporter,
CustomLintContext context,
) {
context.registry.addCompilationUnit((node) {
context.registry.addDeclaration((node) {
final isIgnored = config.parameters.exclude.shouldIgnore(node);
if (isIgnored) return;

final visitor = NoEmptyBlockVisitor();
node.accept(visitor);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import 'package:solid_lints/src/common/parameters/excluded_identifiers_list_parameter.dart';

/// A data model class that represents the "number of parameters" input
/// parameters.
class NumberOfParametersParameters {
/// Maximum number of parameters allowed before a warning is triggered.
final int maxParameters;

/// A list of methods that should be excluded from the lint.
final ExcludedIdentifiersListParameter exclude;

static const _defaultMaxParameters = 2;

/// Constructor for [NumberOfParametersParameters] model
const NumberOfParametersParameters({
required this.maxParameters,
required this.exclude,
});

/// Method for creating from json data
factory NumberOfParametersParameters.fromJson(Map<String, Object?> json) =>
NumberOfParametersParameters(
maxParameters: json['max_parameters'] as int? ?? _defaultMaxParameters,
exclude: ExcludedIdentifiersListParameter.defaultFromJson(json),
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class NumberOfParametersRule
CustomLintContext context,
) {
context.registry.addDeclaration((node) {
final isIgnored = config.parameters.exclude.shouldIgnore(node);
final parameters = switch (node) {
(final MethodDeclaration node) =>
node.parameters?.parameters.length ?? 0,
Expand All @@ -73,7 +74,7 @@ class NumberOfParametersRule
_ => 0,
};

if (parameters > config.parameters.maxParameters) {
if (!isIgnored && parameters > config.parameters.maxParameters) {
reporter.atOffset(
offset: node.firstTokenAfterCommentAndMetadata.offset,
length: node.end,
Expand Down
Loading

0 comments on commit 3e1711b

Please sign in to comment.