Skip to content

Commit

Permalink
Add exclude config to the cyclomatic_complexity rule
Browse files Browse the repository at this point in the history
  • Loading branch information
sufftea committed May 2, 2024
1 parent 719a626 commit 63096c5
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';
import 'package:solid_lints/src/lints/cyclomatic_complexity/models/cyclomatic_complexity_parameters.dart';
Expand Down Expand Up @@ -39,7 +40,7 @@ class CyclomaticComplexityRule
paramsParser: CyclomaticComplexityParameters.fromJson,
problemMessage: (value) =>
'The maximum allowed complexity of a function is '
'${value.maxComplexity}. Please decrease it.',
'${value.maxCyclomaticComplexity.maxComplexity}. Please decrease it.',
);

return CyclomaticComplexityRule._(rule);
Expand All @@ -52,11 +53,23 @@ class CyclomaticComplexityRule
CustomLintContext context,
) {
context.registry.addBlockFunctionBody((node) {
final functionNode = node.thisOrAncestorOfType<Declaration>();
if (functionNode != null &&
config.parameters.ignoredEntities.matchMethod(functionNode)) {
return;
}

final classNode = node.thisOrAncestorOfType<ClassDeclaration>();
if (classNode != null &&
config.parameters.ignoredEntities.matchClass(classNode)) {
return;
}

final visitor = CyclomaticComplexityFlowVisitor();
node.visitChildren(visitor);

if (visitor.complexityEntities.length + 1 >
config.parameters.maxComplexity) {
config.parameters.maxCyclomaticComplexity.maxComplexity) {
reporter.reportErrorForNode(code, node);
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
/// Cyclomatic complexity metric limits configuration.
import 'package:solid_lints/src/lints/cyclomatic_complexity/models/max_cyclomatic_complexity_parameters.dart';
import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.dart';

/// Config parameters for the `cyclomatic_complexity` rule
class CyclomaticComplexityParameters {
/// Threshold cyclomatic complexity level, exceeding it triggers a warning.
final int maxComplexity;
/// `max_complexity` configuration
final MaxCyclomaticComplexityParameters maxCyclomaticComplexity;

/// Reference: NIST 500-235 item 2.5
static const _defaultMaxComplexity = 10;
/// `exclude` configuration
final IgnoredEntitiesModel ignoredEntities;

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

/// Method for creating from json data
factory CyclomaticComplexityParameters.fromJson(Map<String, Object?> json) =>
CyclomaticComplexityParameters(
maxComplexity: json['max_complexity'] as int? ?? _defaultMaxComplexity,
);
///
factory CyclomaticComplexityParameters.fromJson(Map<String, Object?> json) {
return CyclomaticComplexityParameters(
ignoredEntities: IgnoredEntitiesModel.fromJson(json),
maxCyclomaticComplexity: MaxCyclomaticComplexityParameters.fromJson(json),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/// Cyclomatic complexity metric limits configuration.
class MaxCyclomaticComplexityParameters {
/// Threshold cyclomatic complexity level, exceeding it triggers a warning.
final int maxComplexity;

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

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

/// Method for creating from json data
factory MaxCyclomaticComplexityParameters.fromJson(
Map<String, Object?> json,
) =>
MaxCyclomaticComplexityParameters(
maxComplexity: json['max_complexity'] as int? ?? _defaultMaxComplexity,
);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:solid_lints/src/models/ignored_entities_model/ignored_entity.dart';

/// Manages a list of entities (functions/methods/classes) that should be
/// Manages a list of entities (functions/methods/classes) that should be
/// excluded from a lint rule.
///
///
/// Example config:
/// ```yaml
/// custom_lint:
Expand Down
1 change: 1 addition & 0 deletions lib/src/models/ignored_entities_model/ignored_entity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class IgnoredEntity {

/// Class name
final String? className;

/// Function name
final String? functionName;

Expand Down
13 changes: 13 additions & 0 deletions lint_test/cyclomatic_complexity/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
analyzer:
plugins:
- ../custom_lint

custom_lint:
rules:
- cyclomatic_complexity:
max_complexity: 4
exclude:
- method_name: excludeMethod
class_name: ExcludeClass
- method_name: excludeFunction
- class_name: ExcludeEntireClass
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,48 @@ class A {
if (true) {}
}
}

void excludeFunction() {
if (true) {
if (true) {
if (true) {
if (true) {}
}
}
}
}

class ExcludeEntireClass {
void foo() {
if (true) {
if (true) {
if (true) {
if (true) {}
}
}
}
}
}

class ExcludeClass {
/// expect_lint: cyclomatic_complexity
void foo() {
if (true) {
if (true) {
if (true) {
if (true) {}
}
}
}
}

void excludeMethod() {
if (true) {
if (true) {
if (true) {
if (true) {}
}
}
}
}
}

0 comments on commit 63096c5

Please sign in to comment.