Skip to content
This repository was archived by the owner on Jul 16, 2023. It is now read-only.

Commit d19a1e4

Browse files
authored
feat: add allow-nullable config option for avoid-returning-widgets (#1180)
* feat: add allow-nullable config option for avoid-returning-widgets * chore: remove unused import
1 parent cde4648 commit d19a1e4

File tree

24 files changed

+115
-54
lines changed

24 files changed

+115
-54
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44

5+
* feat: add `allow-nullable` config option for [`avoid-returning-widgets`](https://dcm.dev/docs/individuals/rules/common/avoid-returning-widgets).
56
* fix: support `assert(mounted)` for [`use-setstate-synchronously`](https://dcm.dev/docs/individuals/rules/flutter/use-setstate-synchronously).
67
* fix: correctly support dartdoc tags for [`format-comment`](https://dcm.dev/docs/individuals/rules/common/format-comment).
78

lib/src/analyzers/lint_analyzer/rules/rules_list/avoid_collection_methods_with_unrelated_types/avoid_collection_methods_with_unrelated_types_rule.dart

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import 'package:analyzer/dart/ast/ast.dart';
44
import 'package:analyzer/dart/ast/visitor.dart';
55
import 'package:analyzer/dart/element/element.dart';
6-
import 'package:analyzer/dart/element/nullability_suffix.dart';
76
import 'package:analyzer/dart/element/type.dart';
87
import 'package:collection/collection.dart';
98

lib/src/analyzers/lint_analyzer/rules/rules_list/avoid_collection_methods_with_unrelated_types/visitor.dart

+1-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ class _Visitor extends RecursiveAstVisitor<void> {
7373
childType != null &&
7474
(_isNotInstance(childType, parentElement) &&
7575
_isNotDynamic(childType)) &&
76-
!(parentElement.type.nullabilitySuffix == NullabilitySuffix.question &&
77-
childType.isDartCoreNull)) {
76+
!(isNullableType(parentElement.type) && childType.isDartCoreNull)) {
7877
_expressions.add(node);
7978
}
8079
}

lib/src/analyzers/lint_analyzer/rules/rules_list/avoid_redundant_async/avoid_redundant_async_rule.dart

+10-8
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import 'package:analyzer/dart/ast/ast.dart';
44
import 'package:analyzer/dart/ast/token.dart';
55
import 'package:analyzer/dart/ast/visitor.dart';
6-
import 'package:analyzer/dart/element/nullability_suffix.dart';
76

7+
import '../../../../../utils/dart_types_utils.dart';
88
import '../../../../../utils/node_utils.dart';
99
import '../../../lint_utils.dart';
1010
import '../../../models/internal_resolved_unit_result.dart';
@@ -35,12 +35,14 @@ class AvoidRedundantAsyncRule extends CommonRule {
3535

3636
source.unit.visitChildren(visitor);
3737

38-
return visitor.nodes.map(
39-
(node) => createIssue(
40-
rule: this,
41-
location: nodeLocation(node: node, source: source),
42-
message: _warningMessage,
43-
),
44-
);
38+
return visitor.nodes
39+
.map(
40+
(node) => createIssue(
41+
rule: this,
42+
location: nodeLocation(node: node, source: source),
43+
message: _warningMessage,
44+
),
45+
)
46+
.toList(growable: false);
4547
}
4648
}

lib/src/analyzers/lint_analyzer/rules/rules_list/avoid_redundant_async/visitor.dart

+1-3
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,7 @@ class _AsyncVisitor extends RecursiveAstVisitor<void> {
7171
_returnsInsideIf.add(node);
7272
}
7373

74-
if (type == null ||
75-
!type.isDartAsyncFuture ||
76-
type.nullabilitySuffix == NullabilitySuffix.question) {
74+
if (type == null || !type.isDartAsyncFuture || isNullableType(type)) {
7775
hasValidAsync = true;
7876
}
7977
}

lib/src/analyzers/lint_analyzer/rules/rules_list/avoid_returning_widgets/avoid_returning_widgets_rule.dart

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:analyzer/dart/ast/token.dart';
55
import 'package:analyzer/dart/ast/visitor.dart';
66
import 'package:analyzer/dart/element/type.dart';
77

8+
import '../../../../../utils/dart_types_utils.dart';
89
import '../../../../../utils/flutter_types_utils.dart';
910
import '../../../../../utils/node_utils.dart';
1011
import '../../../lint_utils.dart';
@@ -29,10 +30,12 @@ class AvoidReturningWidgetsRule extends FlutterRule {
2930

3031
final Iterable<String> _ignoredNames;
3132
final Iterable<String> _ignoredAnnotations;
33+
final bool _allowNullable;
3234

3335
AvoidReturningWidgetsRule([Map<String, Object> config = const {}])
3436
: _ignoredNames = _ConfigParser.getIgnoredNames(config),
3537
_ignoredAnnotations = _ConfigParser.getIgnoredAnnotations(config),
38+
_allowNullable = _ConfigParser.getAllowNullable(config),
3639
super(
3740
id: ruleId,
3841
severity: readSeverity(config, Severity.warning),
@@ -46,13 +49,15 @@ class AvoidReturningWidgetsRule extends FlutterRule {
4649
json[_ConfigParser._ignoredNamesConfig] = _ignoredNames.toList();
4750
json[_ConfigParser._ignoredAnnotationsConfig] =
4851
_ignoredAnnotations.toList();
52+
json[_ConfigParser._allowNullable] = _allowNullable;
4953

5054
return json;
5155
}
5256

5357
@override
5458
Iterable<Issue> check(InternalResolvedUnitResult source) {
55-
final visitor = _Visitor(_ignoredNames, _ignoredAnnotations);
59+
final visitor =
60+
_Visitor(_ignoredNames, _ignoredAnnotations, _allowNullable);
5661

5762
source.unit.visitChildren(visitor);
5863

lib/src/analyzers/lint_analyzer/rules/rules_list/avoid_returning_widgets/config_parser.dart

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ part of 'avoid_returning_widgets_rule.dart';
33
class _ConfigParser {
44
static const _ignoredNamesConfig = 'ignored-names';
55
static const _ignoredAnnotationsConfig = 'ignored-annotations';
6+
static const _allowNullable = 'allow-nullable';
67

78
static Iterable<String> getIgnoredNames(Map<String, Object> config) =>
89
_getIterable(config, _ignoredNamesConfig) ?? [];
@@ -11,6 +12,9 @@ class _ConfigParser {
1112
_getIterable(config, _ignoredAnnotationsConfig) ??
1213
functionalWidgetAnnotations;
1314

15+
static bool getAllowNullable(Map<String, Object> config) =>
16+
config[_allowNullable] as bool? ?? false;
17+
1418
static Iterable<String>? _getIterable(
1519
Map<String, Object> config,
1620
String name,
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
part of 'avoid_returning_widgets_rule.dart';
22

3+
// ignore: long-parameter-list
34
Declaration? _visitDeclaration(
45
Declaration node,
56
String name,
67
TypeAnnotation? returnType,
78
Iterable<String> ignoredNames,
89
Iterable<String> ignoredAnnotations, {
910
required bool isSetter,
11+
required bool allowNullable,
1012
}) {
1113
final hasIgnoredAnnotation = node.metadata.any(
1214
(node) =>
1315
ignoredAnnotations.contains(node.name.name) &&
1416
node.atSign.type == TokenType.AT,
1517
);
1618

17-
if (!hasIgnoredAnnotation && !isSetter && !_isIgnored(name, ignoredNames)) {
18-
final type = returnType?.type;
19-
if (type != null && hasWidgetType(type)) {
20-
return node;
21-
}
19+
if (!hasIgnoredAnnotation &&
20+
!isSetter &&
21+
!_isIgnored(name, ignoredNames) &&
22+
_hasWidgetType(returnType?.type, allowNullable)) {
23+
return node;
2224
}
2325

2426
return null;
@@ -29,3 +31,8 @@ bool _isIgnored(
2931
Iterable<String> ignoredNames,
3032
) =>
3133
name == 'build' || ignoredNames.contains(name);
34+
35+
bool _hasWidgetType(DartType? type, bool allowNullable) =>
36+
type != null &&
37+
hasWidgetType(type) &&
38+
(!allowNullable || (allowNullable && !isNullableType(type)));

lib/src/analyzers/lint_analyzer/rules/rules_list/avoid_returning_widgets/visitor.dart

+18-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// ignore_for_file: avoid_positional_boolean_parameters
2+
13
part of 'avoid_returning_widgets_rule.dart';
24

35
class _Visitor extends RecursiveAstVisitor<void> {
@@ -7,12 +9,13 @@ class _Visitor extends RecursiveAstVisitor<void> {
79

810
final Iterable<String> _ignoredNames;
911
final Iterable<String> _ignoredAnnotations;
12+
final bool _allowNullable;
1013

1114
Iterable<InvocationExpression> get invocations => _invocations;
1215
Iterable<Declaration> get getters => _getters;
1316
Iterable<Declaration> get globalFunctions => _globalFunctions;
1417

15-
_Visitor(this._ignoredNames, this._ignoredAnnotations);
18+
_Visitor(this._ignoredNames, this._ignoredAnnotations, this._allowNullable);
1619

1720
@override
1821
void visitFunctionDeclaration(FunctionDeclaration node) {
@@ -27,6 +30,7 @@ class _Visitor extends RecursiveAstVisitor<void> {
2730
_ignoredNames,
2831
_ignoredAnnotations,
2932
isSetter: node.isSetter,
33+
allowNullable: _allowNullable,
3034
);
3135

3236
if (declaration != null) {
@@ -44,6 +48,7 @@ class _Visitor extends RecursiveAstVisitor<void> {
4448
final declarationsVisitor = _DeclarationsVisitor(
4549
_ignoredNames,
4650
_ignoredAnnotations,
51+
_allowNullable,
4752
);
4853
node.visitChildren(declarationsVisitor);
4954

@@ -52,7 +57,7 @@ class _Visitor extends RecursiveAstVisitor<void> {
5257
.whereType<String>()
5358
.toSet();
5459

55-
final invocationsVisitor = _InvocationsVisitor(names);
60+
final invocationsVisitor = _InvocationsVisitor(names, _allowNullable);
5661
node.visitChildren(invocationsVisitor);
5762

5863
_invocations.addAll(invocationsVisitor.invocations);
@@ -64,10 +69,11 @@ class _InvocationsVisitor extends RecursiveAstVisitor<void> {
6469
final _invocations = <InvocationExpression>[];
6570

6671
final Set<String> _declarationNames;
72+
final bool _allowNullable;
6773

6874
Iterable<InvocationExpression> get invocations => _invocations;
6975

70-
_InvocationsVisitor(this._declarationNames);
76+
_InvocationsVisitor(this._declarationNames, this._allowNullable);
7177

7278
@override
7379
void visitMethodInvocation(MethodInvocation node) {
@@ -90,7 +96,7 @@ class _InvocationsVisitor extends RecursiveAstVisitor<void> {
9096
final type = expression.staticType;
9197
if (type is FunctionType) {
9298
return type.returnType is InterfaceType &&
93-
hasWidgetType(type.returnType);
99+
_hasWidgetType(type.returnType, _allowNullable);
94100
}
95101
}
96102

@@ -104,11 +110,16 @@ class _DeclarationsVisitor extends RecursiveAstVisitor<void> {
104110

105111
final Iterable<String> _ignoredNames;
106112
final Iterable<String> _ignoredAnnotations;
113+
final bool _allowNullable;
107114

108115
Iterable<Declaration> get declarations => _declarations;
109116
Iterable<Declaration> get getters => _getters;
110117

111-
_DeclarationsVisitor(this._ignoredNames, this._ignoredAnnotations);
118+
_DeclarationsVisitor(
119+
this._ignoredNames,
120+
this._ignoredAnnotations,
121+
this._allowNullable,
122+
);
112123

113124
@override
114125
void visitMethodDeclaration(MethodDeclaration node) {
@@ -121,6 +132,7 @@ class _DeclarationsVisitor extends RecursiveAstVisitor<void> {
121132
_ignoredNames,
122133
_ignoredAnnotations,
123134
isSetter: node.isSetter,
135+
allowNullable: _allowNullable,
124136
);
125137

126138
if (declaration != null) {
@@ -143,6 +155,7 @@ class _DeclarationsVisitor extends RecursiveAstVisitor<void> {
143155
_ignoredNames,
144156
_ignoredAnnotations,
145157
isSetter: node.isSetter,
158+
allowNullable: _allowNullable,
146159
);
147160

148161
if (declaration != null) {

lib/src/analyzers/lint_analyzer/rules/rules_list/avoid_unnecessary_type_assertions/avoid_unnecessary_type_assertions_rule.dart

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import 'package:analyzer/dart/ast/ast.dart';
22
import 'package:analyzer/dart/ast/visitor.dart';
3-
import 'package:analyzer/dart/element/nullability_suffix.dart';
43
import 'package:analyzer/dart/element/type.dart';
54
import 'package:collection/collection.dart';
65

lib/src/analyzers/lint_analyzer/rules/rules_list/avoid_unnecessary_type_assertions/visitor.dart

+2-4
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,8 @@ class _Visitor extends RecursiveAstVisitor<void> {
8585
}
8686

8787
bool _checkNullableCompatibility(DartType objectType, DartType castedType) {
88-
final isObjectTypeNullable =
89-
objectType.nullabilitySuffix != NullabilitySuffix.none;
90-
final isCastedTypeNullable =
91-
castedType.nullabilitySuffix != NullabilitySuffix.none;
88+
final isObjectTypeNullable = isNullableType(objectType);
89+
final isCastedTypeNullable = isNullableType(castedType);
9290

9391
// Only one case `Type? is Type` always valid assertion case.
9492
return isObjectTypeNullable && !isCastedTypeNullable;

lib/src/analyzers/lint_analyzer/rules/rules_list/avoid_unnecessary_type_casts/avoid_unnecessary_type_casts_rule.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import 'package:analyzer/dart/ast/ast.dart';
22
import 'package:analyzer/dart/ast/visitor.dart';
3-
import 'package:analyzer/dart/element/nullability_suffix.dart';
43
import 'package:analyzer/dart/element/type.dart';
54
import 'package:collection/collection.dart';
65

6+
import '../../../../../utils/dart_types_utils.dart';
77
import '../../../../../utils/node_utils.dart';
88
import '../../../lint_utils.dart';
99
import '../../../models/internal_resolved_unit_result.dart';

lib/src/analyzers/lint_analyzer/rules/rules_list/avoid_unnecessary_type_casts/visitor.dart

+2-4
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,8 @@ class _Visitor extends RecursiveAstVisitor<void> {
3939
}
4040

4141
bool _checkNullableCompatibility(DartType objectType, DartType castedType) {
42-
final isObjectTypeNullable =
43-
objectType.nullabilitySuffix != NullabilitySuffix.none;
44-
final isCastedTypeNullable =
45-
castedType.nullabilitySuffix != NullabilitySuffix.none;
42+
final isObjectTypeNullable = isNullableType(objectType);
43+
final isCastedTypeNullable = isNullableType(castedType);
4644

4745
// Only one case `Type? is Type` always valid assertion case.
4846
return isObjectTypeNullable && !isCastedTypeNullable;

lib/src/analyzers/lint_analyzer/rules/rules_list/member_ordering/member_ordering_rule.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
import 'package:analyzer/dart/ast/ast.dart';
44
import 'package:analyzer/dart/ast/visitor.dart';
5-
import 'package:analyzer/dart/element/nullability_suffix.dart';
65
import 'package:collection/collection.dart';
76

7+
import '../../../../../utils/dart_types_utils.dart';
88
import '../../../../../utils/flutter_types_utils.dart';
99
import '../../../../../utils/node_utils.dart';
1010
import '../../../lint_utils.dart';

lib/src/analyzers/lint_analyzer/rules/rules_list/member_ordering/models/member_group.dart

+1-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ class _FieldMemberGroup extends _MemberGroup {
4343
Identifier.isPrivateName(declaration.fields.variables.first.name.lexeme)
4444
? _Modifier.private
4545
: _Modifier.public;
46-
final isNullable = declaration.fields.type?.type?.nullabilitySuffix ==
47-
NullabilitySuffix.question;
46+
final isNullable = isNullableType(declaration.fields.type?.type);
4847
final keyword = declaration.fields.isConst
4948
? _FieldKeyword.isConst
5049
: declaration.fields.isFinal

lib/src/analyzers/lint_analyzer/rules/rules_list/no_boolean_literal_compare/no_boolean_literal_compare_rule.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
import 'package:analyzer/dart/ast/ast.dart';
44
import 'package:analyzer/dart/ast/token.dart';
55
import 'package:analyzer/dart/ast/visitor.dart';
6-
import 'package:analyzer/dart/element/nullability_suffix.dart';
76
import 'package:analyzer/dart/element/type.dart';
87

8+
import '../../../../../utils/dart_types_utils.dart';
99
import '../../../../../utils/node_utils.dart';
1010
import '../../../lint_utils.dart';
1111
import '../../../models/internal_resolved_unit_result.dart';

lib/src/analyzers/lint_analyzer/rules/rules_list/no_boolean_literal_compare/visitor.dart

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,5 @@ class _Visitor extends RecursiveAstVisitor<void> {
2424
}
2525

2626
bool _isTypeBoolean(DartType? type) =>
27-
type != null &&
28-
type.isDartCoreBool &&
29-
type.nullabilitySuffix == NullabilitySuffix.none;
27+
type != null && type.isDartCoreBool && !isNullableType(type);
3028
}

lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_iterable_of/prefer_iterable_of_rule.dart

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import 'package:analyzer/dart/ast/ast.dart';
44
import 'package:analyzer/dart/ast/visitor.dart';
5-
import 'package:analyzer/dart/element/nullability_suffix.dart';
65
import 'package:analyzer/dart/element/type.dart';
76
import 'package:collection/collection.dart';
87

lib/src/analyzers/lint_analyzer/rules/rules_list/prefer_iterable_of/visitor.dart

+2-4
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,8 @@ class _Visitor extends RecursiveAstVisitor<void> {
7676
}
7777

7878
bool _checkNullableCompatibility(DartType objectType, DartType castedType) {
79-
final isObjectTypeNullable =
80-
objectType.nullabilitySuffix != NullabilitySuffix.none;
81-
final isCastedTypeNullable =
82-
castedType.nullabilitySuffix != NullabilitySuffix.none;
79+
final isObjectTypeNullable = isNullableType(objectType);
80+
final isCastedTypeNullable = isNullableType(castedType);
8381

8482
// Only one case `Type? is Type` always valid assertion case.
8583
return isObjectTypeNullable && !isCastedTypeNullable;

lib/src/analyzers/unnecessary_nullable_analyzer/declarations_visitor.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import 'package:analyzer/dart/ast/ast.dart';
44
import 'package:analyzer/dart/ast/visitor.dart';
55
import 'package:analyzer/dart/element/element.dart';
6-
import 'package:analyzer/dart/element/nullability_suffix.dart';
76

7+
import '../../utils/dart_types_utils.dart';
88
import '../../utils/node_utils.dart';
99
import '../../utils/suppression.dart';
1010

@@ -75,7 +75,7 @@ class DeclarationsVisitor extends RecursiveAstVisitor<void> {
7575
final type = parameter.declaredElement?.type;
7676

7777
return type != null &&
78-
(type.nullabilitySuffix == NullabilitySuffix.question &&
78+
(isNullableType(type) &&
7979
(!parameter.isOptional ||
8080
parameter.isOptional && parameter.isRequired)) ||
8181
(parameter is DefaultFormalParameter &&

0 commit comments

Comments
 (0)