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

Commit 48b53eb

Browse files
committed
Merge remote-tracking branch 'upstream/master' into implement-avoid-unnecessary-setstate
2 parents 2a48724 + 2fe0033 commit 48b53eb

File tree

16 files changed

+152
-47
lines changed

16 files changed

+152
-47
lines changed

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for all configuration options:
4+
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5+
6+
version: 2
7+
updates:
8+
- package-ecosystem: "github-actions"
9+
directory: "/"
10+
schedule:
11+
interval: "daily"

.vscode/settings.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
{
2+
"files.eol": "\n",
3+
"files.insertFinalNewline": true,
24
"cSpell.words": [
35
"Backport",
4-
"McCabe's",
56
"Gitlab",
7+
"McCabe's",
68
"SLOC",
79
"ansicolor",
810
"codecov",
911
"cyclomatic",
1012
"dartanalyzer",
1113
"dartdocs",
14+
"dependabot",
1215
"dkrutskikh",
1316
"incendial",
1417
"lcov",

analysis_options.yaml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,20 @@ linter:
3838
# - always_specify_types
3939
# - always_use_package_imports
4040
- avoid_annotating_with_dynamic
41-
# - avoid_as
4241
- avoid_bool_literals_in_conditional_expressions
4342
- avoid_catches_without_on_clauses
4443
- avoid_catching_errors
4544
- avoid_classes_with_only_static_members
4645
- avoid_double_and_int_checks
46+
- avoid_dynamic_calls
47+
- avoid_empty_else
4748
- avoid_equals_and_hash_code_on_mutable_classes
4849
- avoid_escaping_inner_quotes
4950
- avoid_field_initializers_in_const_classes
5051
- avoid_function_literals_in_foreach_calls
5152
- avoid_implementing_value_types
5253
- avoid_js_rounded_ints
54+
- avoid_multiple_declarations_per_line
5355
- avoid_positional_boolean_parameters
5456
# - avoid_print
5557
- avoid_private_typedef_functions
@@ -60,21 +62,22 @@ linter:
6062
- avoid_returning_null_for_void
6163
- avoid_returning_this
6264
- avoid_setters_without_getters
63-
- avoid_single_cascade_in_expression_statements
6465
- avoid_slow_async_io
66+
- avoid_type_to_string
6567
- avoid_types_on_closure_parameters
6668
- avoid_unnecessary_containers
6769
- avoid_unused_constructor_parameters
6870
- avoid_void_async
6971
- avoid_web_libraries_in_flutter
70-
- await_only_futures
7172
- camel_case_types
7273
- cancel_subscriptions
7374
- cascade_invocations
75+
# - cast_nullable_to_non_nullable
7476
- close_sinks
7577
- comment_references
7678
- constant_identifier_names
7779
- control_flow_in_finally
80+
- deprecated_consistency
7881
- diagnostic_describe_all_properties
7982
- directives_ordering
8083
- do_not_use_environment
@@ -97,6 +100,7 @@ linter:
97100
- no_logic_in_create_state
98101
- no_runtimeType_toString
99102
- non_constant_identifier_names
103+
- null_check_on_nullable_type_parameter
100104
# - one_member_abstracts
101105
- only_throw_errors
102106
- overridden_fields
@@ -119,7 +123,6 @@ linter:
119123
- prefer_function_declarations_over_variables
120124
- prefer_if_elements_to_conditional_expressions
121125
- prefer_initializing_formals
122-
- prefer_inlined_adds
123126
- prefer_int_literals
124127
- prefer_interpolation_to_compose_strings
125128
- prefer_is_not_operator
@@ -131,31 +134,31 @@ linter:
131134
- provide_deprecation_message
132135
# - public_member_api_docs
133136
- sized_box_for_whitespace
134-
- sort_child_properties_last
135137
# - sort_constructors_first
136138
- sort_pub_dependencies
137139
- sort_unnamed_constructors_first
138140
- test_types_in_equals
139141
- throw_in_finally
142+
- tighten_type_of_initializing_formals
140143
- type_annotate_public_apis
141144
- unnecessary_await_in_return
142-
- unnecessary_brace_in_string_interps
143145
# - unnecessary_final
144-
- unnecessary_getters_setters
145146
- unnecessary_lambdas
146147
- unnecessary_null_aware_assignments
148+
- unnecessary_null_checks
147149
- unnecessary_nullable_for_final_variable_declarations
148150
- unnecessary_overrides
149151
- unnecessary_parenthesis
150152
- unnecessary_raw_strings
151153
- unnecessary_statements
152154
- unnecessary_string_escapes
153155
- unnecessary_string_interpolations
154-
- unsafe_html
155-
- use_full_hex_values_for_flutter_colors
156+
- use_build_context_synchronously
157+
- use_if_null_to_convert_nulls_to_bools
156158
- use_is_even_rather_than_modulo
157159
- use_key_in_widget_constructors
158160
- use_late_for_private_fields_and_variables
161+
- use_named_constants
159162
- use_raw_strings
160163
- use_setters_to_change_properties
161164
- use_string_buffers

doc/rules/avoid-returning-widgets.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ avoid-returning-widgets
88

99
## Description
1010

11-
Warns when a method or function returns a Widget or subclass of a Widget (**Note** `build` method will not trigger the rule).
11+
Warns when a method or function returns a Widget or subclass of a Widget. The following patterns will not trigger the rule:
12+
13+
- Widget `build` method overrides.
14+
- Functions with [functional_widget](https://pub.dev/packages/functional_widget) package annotations.
1215

1316
Extracting widgets to a method is considered as a Flutter anti-pattern, because when Flutter rebuilds widget tree, it calls the function all the time, making more processor time for the operations.
1417

@@ -21,7 +24,7 @@ Additional resources:
2124
* <https://www.reddit.com/r/FlutterDev/comments/avhvco/extracting_widgets_to_a_function_is_not_an/>
2225
* <https://medium.com/flutter-community/splitting-widgets-to-methods-is-a-performance-antipattern-16aa3fb4026c>
2326

24-
Use `ignored-names` configuration, if you want to ignore a function or method name. For example:
27+
Use `ignored-names` configuration, if you want to ignore a function or method name. Use `ignored-annotations` configuration, if you want to override default ignored annotation list. For example:
2528

2629
### Config example
2730

@@ -33,9 +36,11 @@ dart_code_metrics:
3336
- avoid-returning-widgets:
3437
ignored-names:
3538
- testFunction
39+
ignored-annotations:
40+
- allowedAnnotation
3641
```
3742
38-
will ignore all functions named `testFunction`.
43+
will ignore all functions named `testFunction` and all functions having `allowedAnnotation` annotation.
3944

4045
### Example
4146

doc/rules/member-ordering-extended.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Member ordering
1+
# Member ordering extended
22

33
![Configurable](https://img.shields.io/badge/-configurable-informational)
44

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ class AvoidReturningWidgetsRule extends Rule {
2020
static const _warningMessage = 'Avoid returning widgets from a function.';
2121

2222
final Iterable<String> _ignoredNames;
23+
final Iterable<String> _ignoredAnnotations;
2324

2425
AvoidReturningWidgetsRule([Map<String, Object> config = const {}])
2526
: _ignoredNames = _ConfigParser.getIgnoredNames(config),
27+
_ignoredAnnotations = _ConfigParser.getIgnoredAnnotations(config),
2628
super(
2729
id: ruleId,
2830
documentation: const RuleDocumentation(
@@ -36,7 +38,7 @@ class AvoidReturningWidgetsRule extends Rule {
3638

3739
@override
3840
Iterable<Issue> check(InternalResolvedUnitResult source) {
39-
final _visitor = _Visitor(_ignoredNames);
41+
final _visitor = _Visitor(_ignoredNames, _ignoredAnnotations);
4042

4143
source.unit.visitChildren(_visitor);
4244

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,26 @@ part of 'avoid_returning_widgets.dart';
22

33
class _ConfigParser {
44
static const _ignoredNamesConfig = 'ignored-names';
5+
static const _ignoredAnnotationsConfig = 'ignored-annotations';
6+
7+
static const _defaultIgnoredAnnotations = [
8+
'FunctionalWidget',
9+
'swidget',
10+
'hwidget',
11+
];
512

613
static Iterable<String> getIgnoredNames(Map<String, Object> config) =>
7-
config.containsKey(_ignoredNamesConfig) &&
8-
config[_ignoredNamesConfig] is Iterable
9-
? List<String>.from(config[_ignoredNamesConfig] as Iterable)
10-
: <String>[];
14+
_getIterable(config, _ignoredNamesConfig) ?? [];
15+
16+
static Iterable<String> getIgnoredAnnotations(Map<String, Object> config) =>
17+
_getIterable(config, _ignoredAnnotationsConfig) ??
18+
_defaultIgnoredAnnotations;
19+
20+
static Iterable<String>? _getIterable(
21+
Map<String, Object> config,
22+
String name,
23+
) =>
24+
config[name] is Iterable
25+
? List<String>.from(config[name] as Iterable)
26+
: null;
1127
}

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

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,51 @@ class _Visitor extends RecursiveAstVisitor<void> {
44
final _declarations = <Declaration>[];
55

66
final Iterable<String> _ignoredNames;
7+
final Iterable<String> _ignoredAnnotations;
78

89
Iterable<Declaration> get declarations => _declarations;
910

10-
_Visitor(this._ignoredNames);
11+
_Visitor(this._ignoredNames, this._ignoredAnnotations);
1112

1213
@override
1314
void visitMethodDeclaration(MethodDeclaration node) {
1415
super.visitMethodDeclaration(node);
1516

16-
if (!node.isSetter && !_isIgnored(node.name.name)) {
17-
final type = node.returnType?.type;
18-
if (type != null && _hasWidgetType(type)) {
19-
_declarations.add(node);
20-
}
21-
}
17+
_visitDeclaration(
18+
node,
19+
node.name,
20+
node.returnType,
21+
isSetter: node.isSetter,
22+
);
2223
}
2324

2425
@override
2526
void visitFunctionDeclaration(FunctionDeclaration node) {
2627
super.visitFunctionDeclaration(node);
2728

28-
if (!node.isSetter && !_isIgnored(node.name.name)) {
29-
final type = node.returnType?.type;
29+
_visitDeclaration(
30+
node,
31+
node.name,
32+
node.returnType,
33+
isSetter: node.isSetter,
34+
);
35+
}
36+
37+
void _visitDeclaration(
38+
Declaration node,
39+
SimpleIdentifier name,
40+
TypeAnnotation? returnType, {
41+
required bool isSetter,
42+
}) {
43+
final hasIgnoredAnnotation = node.metadata.firstWhereOrNull(
44+
(node) =>
45+
_ignoredAnnotations.contains(node.name.name) &&
46+
node.atSign.type.lexeme == '@',
47+
) !=
48+
null;
49+
50+
if (!hasIgnoredAnnotation && !isSetter && !_isIgnored(name.name)) {
51+
final type = returnType?.type;
3052
if (type != null && _hasWidgetType(type)) {
3153
_declarations.add(node);
3254
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ class _ConfigParser {
44
static const _orderConfig = 'order';
55

66
static List<_ArgumentGroup> parseOrder(Map<String, Object> config) {
7-
final order =
8-
config.containsKey(_orderConfig) && config[_orderConfig] is Iterable
9-
? List<String>.from(config[_orderConfig] as Iterable)
10-
: <String>[];
7+
final order = config[_orderConfig] is Iterable
8+
? List<String>.from(config[_orderConfig] as Iterable)
9+
: <String>[];
1110

1211
return order.isEmpty
1312
? _ArgumentGroup._groupsOrder

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ class _ConfigParser {
44
static const _orderConfig = 'order';
55

66
static List<_MembersGroup> parseOrder(Map<String, Object> config) {
7-
final order =
8-
config.containsKey(_orderConfig) && config[_orderConfig] is Iterable
9-
? List<String>.from(config[_orderConfig] as Iterable)
10-
: <String>[];
7+
final order = config[_orderConfig] is Iterable
8+
? List<String>.from(config[_orderConfig] as Iterable)
9+
: <String>[];
1110

1211
return order.isEmpty
1312
? _MembersGroup._groupsOrder

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class _ConfigParser {
2020
);
2121

2222
static List<_MemberGroup> parseOrder(Map<String, Object> config) {
23-
final order = config.containsKey('order') && config['order'] is Iterable
23+
final order = config['order'] is Iterable
2424
? List<String>.from(config['order'] as Iterable)
2525
: _defaultOrderList;
2626

lib/src/config_builder/config_builder.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class ConfigBuilder {
1313
static const _defaultSkippedFolders = [
1414
'ios/',
1515
'.dart_tool/**',
16-
'packages/**'
16+
'packages/**',
1717
];
1818

1919
static Config getConfig(

0 commit comments

Comments
 (0)