Skip to content

Commit 9be59e9

Browse files
authored
add exclude params support to avoid_returning_widgets rule (#162)
* add exclude params support to avoid_returning_widgets rule * refactor and fix class ignore `avoid_returning_widgets` rule
1 parent 4ea6cb4 commit 9be59e9

5 files changed

Lines changed: 120 additions & 2 deletions

File tree

lib/src/lints/avoid_returning_widgets/avoid_returning_widgets_rule.dart

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import 'package:analyzer/dart/ast/ast.dart';
22
import 'package:analyzer/dart/element/type.dart';
33
import 'package:analyzer/error/listener.dart';
4+
import 'package:collection/collection.dart';
45
import 'package:custom_lint_builder/custom_lint_builder.dart';
6+
import 'package:solid_lints/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_parameters.dart';
57
import 'package:solid_lints/src/models/rule_config.dart';
68
import 'package:solid_lints/src/models/solid_lint_rule.dart';
79
import 'package:solid_lints/src/utils/types_utils.dart';
@@ -48,7 +50,8 @@ import 'package:solid_lints/src/utils/types_utils.dart';
4850
/// }
4951
/// }
5052
/// ```
51-
class AvoidReturningWidgetsRule extends SolidLintRule {
53+
class AvoidReturningWidgetsRule
54+
extends SolidLintRule<AvoidReturningWidgetsParameters> {
5255
/// The [LintCode] of this lint rule that represents
5356
/// the error whether we return a widget.
5457
static const lintName = 'avoid_returning_widgets';
@@ -61,6 +64,7 @@ class AvoidReturningWidgetsRule extends SolidLintRule {
6164
final rule = RuleConfig(
6265
configs: configs,
6366
name: lintName,
67+
paramsParser: AvoidReturningWidgetsParameters.fromJson,
6468
problemMessage: (_) =>
6569
'Returning a widget from a function is considered an anti-pattern. '
6670
'Unless you are overriding an existing method, '
@@ -92,11 +96,34 @@ class AvoidReturningWidgetsRule extends SolidLintRule {
9296

9397
final isWidgetReturned = hasWidgetType(returnType);
9498

99+
final isIgnored = _shouldIgnore(node);
100+
95101
final isOverriden = node.declaredElement?.hasOverride ?? false;
96102

97-
if (isWidgetReturned && !isOverriden) {
103+
if (isWidgetReturned && !isOverriden && !isIgnored) {
98104
reporter.reportErrorForNode(code, node);
99105
}
100106
});
101107
}
108+
109+
bool _shouldIgnore(Declaration node) {
110+
final methodName = node.declaredElement?.name;
111+
112+
final excludedItem = config.parameters.exclude
113+
.firstWhereOrNull((e) => e.methodName == methodName);
114+
115+
if (excludedItem == null) return false;
116+
117+
final className = excludedItem.className;
118+
119+
if (className == null || node is! MethodDeclaration) {
120+
return true;
121+
} else {
122+
final classDeclaration = node.thisOrAncestorOfType<ClassDeclaration>();
123+
124+
if (classDeclaration == null) return false;
125+
126+
return classDeclaration.name.toString() == className;
127+
}
128+
}
102129
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// Model class for AvoidReturningWidgetsExclude parameters
2+
class AvoidReturningWidgetsExclude {
3+
/// The name of the method that should be excluded from the lint.
4+
final String methodName;
5+
6+
/// The name of the class that should be excluded from the lint.
7+
final String? className;
8+
9+
/// Constructor for [AvoidReturningWidgetsExclude] model
10+
const AvoidReturningWidgetsExclude({
11+
required this.methodName,
12+
required this.className,
13+
});
14+
15+
///
16+
factory AvoidReturningWidgetsExclude.fromJson(
17+
Map<dynamic, dynamic> json,
18+
) {
19+
return AvoidReturningWidgetsExclude(
20+
methodName: json['method_name'] as String,
21+
className: json['class_name'] as String?,
22+
);
23+
}
24+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import 'package:solid_lints/src/lints/avoid_returning_widgets/models/avoid_returning_widgets_exclude.dart';
2+
3+
/// A data model class that represents the "avoid returning widgets" input
4+
/// parameters.
5+
class AvoidReturningWidgetsParameters {
6+
/// A list of methods that should be excluded from the lint.
7+
final List<AvoidReturningWidgetsExclude> exclude;
8+
9+
/// Constructor for [AvoidReturningWidgetsParameters] model
10+
AvoidReturningWidgetsParameters({
11+
required this.exclude,
12+
});
13+
14+
/// Method for creating from json data
15+
factory AvoidReturningWidgetsParameters.fromJson(Map<String, dynamic> json) {
16+
final exclude = <AvoidReturningWidgetsExclude>[];
17+
18+
final excludeList = json['exclude'] as Iterable? ?? [];
19+
for (final item in excludeList) {
20+
if (item is Map) {
21+
exclude.add(AvoidReturningWidgetsExclude.fromJson(item));
22+
}
23+
}
24+
return AvoidReturningWidgetsParameters(
25+
exclude: exclude,
26+
);
27+
}
28+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
analyzer:
2+
plugins:
3+
- ../custom_lint
4+
5+
custom_lint:
6+
rules:
7+
- avoid_returning_widgets:
8+
exclude:
9+
- method_name: excludeWidgetMethod
10+
class_name: ExcludeWidget
11+
- method_name: excludeMethod

lint_test/avoid_returning_widget_test.dart renamed to lint_test/avoid_returning_widget_test/avoid_returning_widget_test.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,31 @@ class MyWidget extends BaseWidget {
6464
Widget build() {
6565
return Offstage();
6666
}
67+
68+
SizedBox excludeMethod() => const SizedBox();
69+
70+
class ExcludeWidget extends StatelessWidget {
71+
const ExcludeWidget({super.key});
72+
73+
@override
74+
Widget build(BuildContext context) {
75+
return const Placeholder();
76+
}
77+
78+
Widget excludeWidgetMethod() => const SizedBox();
79+
80+
// expect_lint: avoid_returning_widgets
81+
Widget excludeWidgetMethod2() => const SizedBox();
82+
}
83+
84+
class NotExcludeWidget extends StatelessWidget {
85+
const NotExcludeWidget({super.key});
86+
87+
@override
88+
Widget build(BuildContext context) {
89+
return const Placeholder();
90+
}
91+
92+
// expect_lint: avoid_returning_widgets
93+
Widget excludeWidgetMethod() => const SizedBox();
94+
}

0 commit comments

Comments
 (0)