Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I167 #171

Closed
wants to merge 7 commits into from
Closed

I167 #171

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@
- add quick fix to avoid_final_with_getter (https://github.com/solid-software/solid_lints/pull/164)
- Renamed `avoid_debug_print` to `avoid_debug_print_in_release`
- The `avoid_debug_print_in_release` no longer reports a warning if the `debugPrint` call is wrapped in a `!kReleaseMode` check.
- Consistent `exclude` configuration for the following rules:
- `avoid_returning_widgets`
- `avoid_unused_parameters`
- `cyclomatic_complexity`
- `function_lines_of_code`
- `no_empty_bloc`
- `number_of_parameters`


## 0.1.5

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/listener.dart';
import 'package:collection/collection.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';
import 'package:solid_lints/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_parameters.dart';
import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.dart';
import 'package:solid_lints/src/models/rule_config.dart';
import 'package:solid_lints/src/models/solid_lint_rule.dart';
import 'package:solid_lints/src/utils/types_utils.dart';
Expand Down Expand Up @@ -50,8 +49,7 @@ import 'package:solid_lints/src/utils/types_utils.dart';
/// }
/// }
/// ```
class AvoidReturningWidgetsRule
extends SolidLintRule<AvoidReturningWidgetsParameters> {
class AvoidReturningWidgetsRule extends SolidLintRule<IgnoredEntitiesModel> {
/// The [LintCode] of this lint rule that represents
/// the error whether we return a widget.
static const lintName = 'avoid_returning_widgets';
Expand All @@ -64,7 +62,7 @@ class AvoidReturningWidgetsRule
final rule = RuleConfig(
configs: configs,
name: lintName,
paramsParser: AvoidReturningWidgetsParameters.fromJson,
paramsParser: IgnoredEntitiesModel.fromJson,
problemMessage: (_) =>
'Returning a widget from a function is considered an anti-pattern. '
'Unless you are overriding an existing method, '
Expand Down Expand Up @@ -96,7 +94,8 @@ class AvoidReturningWidgetsRule

final isWidgetReturned = hasWidgetType(returnType);

final isIgnored = _shouldIgnore(node);
final isIgnored = config.parameters.isIgnoredMethod(node) ||
config.parameters.isIgnoredClass(node);

final isOverriden = node.declaredElement?.hasOverride ?? false;

Expand All @@ -105,25 +104,4 @@ class AvoidReturningWidgetsRule
}
});
}

bool _shouldIgnore(Declaration node) {
final methodName = node.declaredElement?.name;

final excludedItem = config.parameters.exclude
.firstWhereOrNull((e) => e.methodName == methodName);

if (excludedItem == null) return false;

final className = excludedItem.className;

if (className == null || node is! MethodDeclaration) {
return true;
} else {
final classDeclaration = node.thisOrAncestorOfType<ClassDeclaration>();

if (classDeclaration == null) return false;

return classDeclaration.name.toString() == className;
}
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:analyzer/error/listener.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';
import 'package:solid_lints/src/lints/avoid_unused_parameters/visitors/avoid_unused_parameters_visitor.dart';
import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.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<IgnoredEntitiesModel> {
/// The [LintCode] of this lint rule that 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: IgnoredEntitiesModel.fromJson,
problemMessage: (_) => 'Parameter is unused.',
);

Expand All @@ -92,7 +94,7 @@ class AvoidUnusedParametersRule extends SolidLintRule {
CustomLintContext context,
) {
context.registry.addCompilationUnit((node) {
final visitor = AvoidUnusedParametersVisitor();
final visitor = AvoidUnusedParametersVisitor(config.parameters);
node.accept(visitor);

for (final element in visitor.unusedParameters) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,19 @@ import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:collection/collection.dart';
import 'package:solid_lints/src/models/ignored_entities_model/ignored_entities_model.dart';
import 'package:solid_lints/src/utils/node_utils.dart';
import 'package:solid_lints/src/utils/parameter_utils.dart';

/// AST Visitor which finds all is expressions and checks if they are
/// unrelated (result always false)
class AvoidUnusedParametersVisitor extends RecursiveAstVisitor<void> {
/// AvoidUnusedParametersVisitor constructor
AvoidUnusedParametersVisitor(this.ignoredEntities);

/// Entities that should be ignored
final IgnoredEntitiesModel ignoredEntities;

final _unusedParameters = <FormalParameter>[];

/// List of unused parameters
Expand All @@ -48,6 +55,11 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor<void> {
parameters.parameters.isEmpty) {
return;
}

if (ignoredEntities.isIgnoredClass(node)) {
return;
}

final unused = _getUnusedParameters(
node.body,
parameters.parameters,
Expand All @@ -73,6 +85,11 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor<void> {
return;
}

if (ignoredEntities.isIgnoredMethod(node) ||
ignoredEntities.isIgnoredClass(node)) {
return;
}

final isTearOff = _usedAsTearOff(node);

if (!isOverride(node.metadata) && !isTearOff) {
Expand All @@ -93,6 +110,10 @@ class AvoidUnusedParametersVisitor extends RecursiveAstVisitor<void> {
return;
}

if (ignoredEntities.isIgnoredMethod(node)) {
return;
}

_unusedParameters.addAll(
_filterOutUnderscoresAndNamed(
node.body,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,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 +52,16 @@ class CyclomaticComplexityRule
CustomLintContext context,
) {
context.registry.addBlockFunctionBody((node) {
if (config.parameters.ignoredEntities.isIgnoredMethod(node) ||
config.parameters.ignoredEntities.isIgnoredClass(node)) {
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;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think you need to create a separate class for extra params. Just go ahead and inherit this parameters class from the IgnoredEntitiesModel.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's easier to implement fromJson this way. Otherwise:

class CyclomaticComplexityParams extends IgnoredEntitiesModel {
  // ...  
  factory CyclomaticComplexityParams.fromJson(Map<String, Object?> json) {
    // With more properties, I'll have to go through all of them:
    final entities = IgnoredEntitiesModel.fromJson(json).entities;

    return CyclomaticComplexityParams(
      entities: entities,
      other: 1,
    );
  }
}

/// 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
Expand Up @@ -16,8 +16,11 @@ import 'package:solid_lints/src/models/solid_lint_rule.dart';
/// rules:
/// - function_lines_of_code:
/// max_lines: 100
/// excludeNames:
/// - "Build"
/// exclude:
/// - method_name: excludeMethod
/// class_name: ExcludeClass
/// - method_name: excludeFunction
/// - class_name: ExcludeEntireClass
/// ```
class FunctionLinesOfCodeRule
extends SolidLintRule<FunctionLinesOfCodeParameters> {
Expand All @@ -35,7 +38,7 @@ class FunctionLinesOfCodeRule
name: lintName,
paramsParser: FunctionLinesOfCodeParameters.fromJson,
problemMessage: (value) =>
'The maximum allowed number of lines is ${value.maxLines}. '
'The maximum allowed number of lines is ${value.maxLinesModel}. '
'Try splitting this function into smaller parts.',
);

Expand All @@ -60,16 +63,16 @@ class FunctionLinesOfCodeRule
ErrorReporter reporter,
AstNode node,
) {
final functionName = _getFunctionName(node);
if (functionName != null &&
config.parameters.excludeNames.contains(functionName)) {
if (config.parameters.ignoredEntitiesModel.isIgnoredMethod(node) ||
config.parameters.ignoredEntitiesModel.isIgnoredClass(node)) {
return;
}

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

if (visitor.linesWithCode.length > config.parameters.maxLines) {
if (visitor.linesWithCode.length >
config.parameters.maxLinesModel.maxLines) {
if (node is! AnnotatedNode) {
return reporter.reportErrorForNode(code, node);
}
Expand All @@ -84,16 +87,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;
}
}
}
Loading
Loading