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

Issue 167 1 #186

Merged
merged 15 commits into from
Dec 6, 2024
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
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/rule_config.dart';
Expand Down Expand Up @@ -96,7 +95,7 @@ class AvoidReturningWidgetsRule

final isWidgetReturned = hasWidgetType(returnType);

final isIgnored = _shouldIgnore(node);
final isIgnored = config.parameters.exclude.shouldIgnore(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;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import 'package:solid_lints/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_exclude.dart';
import 'package:solid_lints/src/models/excluded_identifiers_list_parameter.dart';

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

/// Constructor for [AvoidReturningWidgetsParameters] model
AvoidReturningWidgetsParameters({
Expand All @@ -13,16 +13,11 @@ class AvoidReturningWidgetsParameters {

/// Method for creating from json data
factory AvoidReturningWidgetsParameters.fromJson(Map<String, dynamic> json) {
final exclude = <AvoidReturningWidgetsExclude>[];

final excludeList = json['exclude'] as Iterable? ?? [];
for (final item in excludeList) {
if (item is Map) {
exclude.add(AvoidReturningWidgetsExclude.fromJson(item));
}
}
return AvoidReturningWidgetsParameters(
exclude: exclude,
exclude: ExcludedIdentifiersListParameter.fromJson(
excludeList:
json[ExcludedIdentifiersListParameter.excludeParameterName] as Iterable? ?? [],
),
);
yurii-prykhodko-solid marked this conversation as resolved.
Show resolved Hide resolved
}
}
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 @@ -92,12 +94,18 @@ class AvoidUnusedParametersRule extends SolidLintRule {
CustomLintContext context,
) {
context.registry.addCompilationUnit((node) {
final visitor = AvoidUnusedParametersVisitor();
node.accept(visitor);
context.registry.addDeclaration((declarationNode) {
final isIgnored =
config.parameters.exclude.shouldIgnore(declarationNode);
final visitor = AvoidUnusedParametersVisitor();
node.accept(visitor);

for (final element in visitor.unusedParameters) {
reporter.atNode(element, code);
}
if (!isIgnored) {
for (final element in visitor.unusedParameters) {
reporter.atNode(element, code);
}
}
});
});
}
}
yurii-prykhodko-solid marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:solid_lints/src/models/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.fromJson(
excludeList:
json[ExcludedIdentifiersListParameter.excludeParameterName] as Iterable? ?? [],
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,19 @@ class CyclomaticComplexityRule
ErrorReporter reporter,
CustomLintContext context,
) {
context.registry.addBlockFunctionBody((node) {
final visitor = CyclomaticComplexityFlowVisitor();
node.visitChildren(visitor);
context.registry.addDeclaration((declarationNode) {
context.registry.addBlockFunctionBody((node) {
final isIgnored =
config.parameters.exclude.shouldIgnore(declarationNode);
final visitor = CyclomaticComplexityFlowVisitor();
node.visitChildren(visitor);

if (visitor.complexityEntities.length + 1 >
config.parameters.maxComplexity) {
reporter.atNode(node, code);
}
if (!isIgnored &&
visitor.complexityEntities.length + 1 >
config.parameters.maxComplexity) {
reporter.atNode(node, code);
}
});
});
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
import 'package:solid_lints/src/models/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.fromJson(
excludeList:
json[ExcludedIdentifiersListParameter.excludeParameterName]
as Iterable? ??
[],
),
);
}
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) {
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,32 @@
import 'package:solid_lints/src/models/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.fromJson(
excludeList:
json[ExcludedIdentifiersListParameter.excludeParameterName]
as Iterable? ??
[],
),
);
}
24 changes: 24 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,24 @@
import 'package:solid_lints/src/models/excluded_identifiers_list_parameter.dart';

/// A data model class that represents the "avoid returning widgets" input
/// parameters.
yurii-prykhodko-solid marked this conversation as resolved.
Show resolved Hide resolved
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.fromJson(
excludeList: json[ExcludedIdentifiersListParameter.excludeParameterName]
as Iterable? ??
[],
),
);
}
}
22 changes: 15 additions & 7 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 @@ -76,12 +78,18 @@ class NoEmptyBlockRule extends SolidLintRule {
CustomLintContext context,
) {
context.registry.addCompilationUnit((node) {
final visitor = NoEmptyBlockVisitor();
node.accept(visitor);

for (final emptyBlock in visitor.emptyBlocks) {
reporter.atNode(emptyBlock, code);
}
context.registry.addDeclaration((declarationNode) {
final isIgnored =
config.parameters.exclude.shouldIgnore(declarationNode);
final visitor = NoEmptyBlockVisitor();
node.accept(visitor);

if (!isIgnored) {
for (final emptyBlock in visitor.emptyBlocks) {
reporter.atNode(emptyBlock, code);
}
}
});
});
}
}
Loading
Loading