Skip to content

Commit

Permalink
add exclude params support to avoid_returning_widgets rule (#162)
Browse files Browse the repository at this point in the history
* add exclude params support to avoid_returning_widgets rule

* refactor and fix class ignore `avoid_returning_widgets` rule
  • Loading branch information
4akloon authored Apr 22, 2024
1 parent 4ea6cb4 commit 9be59e9
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
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';
import 'package:solid_lints/src/models/solid_lint_rule.dart';
import 'package:solid_lints/src/utils/types_utils.dart';
Expand Down Expand Up @@ -48,7 +50,8 @@ import 'package:solid_lints/src/utils/types_utils.dart';
/// }
/// }
/// ```
class AvoidReturningWidgetsRule extends SolidLintRule {
class AvoidReturningWidgetsRule
extends SolidLintRule<AvoidReturningWidgetsParameters> {
/// The [LintCode] of this lint rule that represents
/// the error whether we return a widget.
static const lintName = 'avoid_returning_widgets';
Expand All @@ -61,6 +64,7 @@ class AvoidReturningWidgetsRule extends SolidLintRule {
final rule = RuleConfig(
configs: configs,
name: lintName,
paramsParser: AvoidReturningWidgetsParameters.fromJson,
problemMessage: (_) =>
'Returning a widget from a function is considered an anti-pattern. '
'Unless you are overriding an existing method, '
Expand Down Expand Up @@ -92,11 +96,34 @@ class AvoidReturningWidgetsRule extends SolidLintRule {

final isWidgetReturned = hasWidgetType(returnType);

final isIgnored = _shouldIgnore(node);

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

if (isWidgetReturned && !isOverriden) {
if (isWidgetReturned && !isOverriden && !isIgnored) {
reporter.reportErrorForNode(code, node);
}
});
}

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
@@ -0,0 +1,24 @@
/// Model class for AvoidReturningWidgetsExclude parameters
class AvoidReturningWidgetsExclude {
/// The name of the method that should be excluded from the lint.
final String methodName;

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

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

///
factory AvoidReturningWidgetsExclude.fromJson(
Map<dynamic, dynamic> json,
) {
return AvoidReturningWidgetsExclude(
methodName: json['method_name'] as String,
className: json['class_name'] as String?,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'package:solid_lints/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_exclude.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;

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

/// 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,
);
}
}
11 changes: 11 additions & 0 deletions lint_test/avoid_returning_widget_test/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
analyzer:
plugins:
- ../custom_lint

custom_lint:
rules:
- avoid_returning_widgets:
exclude:
- method_name: excludeWidgetMethod
class_name: ExcludeWidget
- method_name: excludeMethod
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,31 @@ class MyWidget extends BaseWidget {
Widget build() {
return Offstage();
}

SizedBox excludeMethod() => const SizedBox();

class ExcludeWidget extends StatelessWidget {
const ExcludeWidget({super.key});

@override
Widget build(BuildContext context) {
return const Placeholder();
}

Widget excludeWidgetMethod() => const SizedBox();

// expect_lint: avoid_returning_widgets
Widget excludeWidgetMethod2() => const SizedBox();
}

class NotExcludeWidget extends StatelessWidget {
const NotExcludeWidget({super.key});

@override
Widget build(BuildContext context) {
return const Placeholder();
}

// expect_lint: avoid_returning_widgets
Widget excludeWidgetMethod() => const SizedBox();
}

0 comments on commit 9be59e9

Please sign in to comment.