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

Commit 2bdc27e

Browse files
committed
Merge remote-tracking branch 'origin' into fix-moving-to-variable-false-positives
2 parents ee25370 + 4cecc46 commit 2bdc27e

File tree

25 files changed

+125
-65
lines changed

25 files changed

+125
-65
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
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
* fix: resolve several false-positives with while loops, setters and implicit type parameters for [`prefer-moving-to-variable`](https://dcm.dev/docs/individuals/rules/common/prefer-moving-to-variable).

CONTRIBUTING.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@ PR titles should follow the format below:
1919
To create a new rule:
2020

2121
1. Choose a rule name according to our naming guide or take it from existing issue for the rule.
22-
2. Add an `.md` file with the rule documentation to `website/docs/rules`. If the rule supports configuration add ![Configurable](https://img.shields.io/badge/-configurable-informational) badge, if it has auto-fixes add ![Has auto-fix](https://img.shields.io/badge/-has%20auto--fix-success) badge.
23-
3. Add rule entry into rule index file `website/docs/rules/index.mdx`.
24-
4. Create a rule `.dart` file under `lib/src/analyzers/lint_analyzer/rules/rules_list`.
25-
5. Create a class that extends an abstract rule class depending on your rule type. Available classes: `FlutterRule`, `CommonRule`, `IntlRule`, `AngularRule`. Add a public field with rule id, documentation url.
22+
2. Create a rule `.dart` file under `lib/src/analyzers/lint_analyzer/rules/rules_list`.
23+
3. Create a class that extends an abstract rule class depending on your rule type. Available classes: `FlutterRule`, `CommonRule`, `IntlRule`, `AngularRule`. Add a public field with rule id, documentation url.
2624

2725
The class constructor should take `Map<String, Object> config` parameter which represents config that is passed to the rule from the `analysis_options.yaml`. Example:
2826

@@ -36,10 +34,10 @@ To create a new rule:
3634
);
3735
```
3836
39-
6. Add a visitor class which extends any of the base visitors. Usually you will need `RecursiveAstVisitor`. All visitors are [listed there](https://github.com/dart-lang/sdk/blob/master/pkg/analyzer/lib/dart/ast/visitor.dart). Visitor should be added to a separate file and imported with `part` directive.
40-
7. Add methods overrides to the visitor class for nodes that you want to check (ex. `visitBinaryExpression`, `visitBlock`).
41-
8. Collect all data needed for the rule (we usually use a private field for data storage and public getter to access it from the `check` method).
42-
9. In the rule class add override to `check` method. Create a visitor instance and visit all compilation unit children with it.
37+
4. Add a visitor class which extends any of the base visitors. Usually you will need `RecursiveAstVisitor`. All visitors are [listed there](https://github.com/dart-lang/sdk/blob/master/pkg/analyzer/lib/dart/ast/visitor.dart). Visitor should be added to a separate file and imported with `part` directive.
38+
5. Add methods overrides to the visitor class for nodes that you want to check (ex. `visitBinaryExpression`, `visitBlock`).
39+
6. Collect all data needed for the rule (we usually use a private field for data storage and public getter to access it from the `check` method).
40+
7. In the rule class add override to `check` method. Create a visitor instance and visit all compilation unit children with it.
4341
4442
Convert data to `Issue`'s and return them from the method. Example:
4543
@@ -65,7 +63,7 @@ To create a new rule:
6563
```
6664
6765
> Override `toJson` method if the rule is configurable.
68-
10. Add the rule to the `lib/src/analyzers/lint_analyzer/rules/rules_factory.dart`. Example:
66+
8. Add the rule to the `lib/src/analyzers/lint_analyzer/rules/rules_factory.dart`. Example:
6967
7068
```dart
7169
final _implementedRules = <String, Rule Function(Map<String, Object>)>{
@@ -76,8 +74,9 @@ To create a new rule:
7674
}
7775
```
7876
79-
11. Add the rule tests under `test/analyzers/lint_analyzer/rules/rules_list/`. Prefer to split test examples to a correct/incorrect groups.
80-
12. Add rule into appropriate presets file: `lib/presets/dart_all.yaml` or `lib/presets/flutter_all.yaml`.
77+
9. Add the rule tests under `test/analyzers/lint_analyzer/rules/rules_list/`. Prefer to split test examples to a correct/incorrect groups.
78+
10. Add rule into appropriate presets file: `lib/presets/dart_all.yaml` or `lib/presets/flutter_all.yaml`.
79+
11. Before submitting the PR, add the rule documentation to the PR's description. Refer [to this rule](https://dcm.dev/docs/individuals/rules/common/prefer-trailing-comma/) as an example.
8180
8281
## Run the plugin in IDE
8382

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

Lines changed: 0 additions & 1 deletion
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

Lines changed: 1 addition & 2 deletions
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

Lines changed: 10 additions & 8 deletions
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

Lines changed: 1 addition & 3 deletions
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

Lines changed: 6 additions & 1 deletion
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

Lines changed: 4 additions & 0 deletions
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,
Lines changed: 12 additions & 5 deletions
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

Lines changed: 18 additions & 5 deletions
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

Lines changed: 0 additions & 1 deletion
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

Lines changed: 2 additions & 4 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 4 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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';

0 commit comments

Comments
 (0)