• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dart-lang / linter / 6444183028

01 Sep 2023 04:26PM CUT coverage: 96.562% (+0.01%) from 96.551%
6444183028

push

github

web-flow
update labels (#4740)

9127 of 9452 relevant lines covered (96.56%)

1.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.29
/lib/src/rules/prefer_for_elements_to_map_fromIterable.dart
1
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2
// for details. All rights reserved. Use of this source code is governed by a
3
// BSD-style license that can be found in the LICENSE file.
4

5
// ignore_for_file: file_names
6
import 'package:analyzer/dart/ast/ast.dart';
7
import 'package:analyzer/dart/ast/visitor.dart';
8

9
import '../analyzer.dart';
10

11
const _desc = r"Prefer 'for' elements when building maps from iterables.";
12

13
const _details = r'''
14
When building maps from iterables, it is preferable to use 'for' elements.
15

16
Using 'for' elements brings several benefits including:
17

18
- Performance
19
- Flexibility
20
- Readability
21
- Improved type inference
22
- Improved interaction with null safety
23

24

25
**BAD:**
26
```dart
27
Map<String, WidgetBuilder>.fromIterable(
28
  kAllGalleryDemos,
29
  key: (demo) => '${demo.routeName}',
30
  value: (demo) => demo.buildRoute,
31
);
32

33
```
34

35
**GOOD:**
36
```dart
37
return {
38
  for (var demo in kAllGalleryDemos)
39
    '${demo.routeName}': demo.buildRoute,
40
};
41
```
42

43
**GOOD:**
44
```dart
45
// Map<int, Student> is not required, type is inferred automatically.
46
final pizzaRecipients = {
47
  ...studentLeaders,
48
  for (var student in classG)
49
    if (student.isPassing) student.id: student,
50
};
51
```
52
''';
53

54
class PreferForElementsToMapFromIterable extends LintRule {
55
  static const LintCode code = LintCode(
56
      'prefer_for_elements_to_map_fromIterable',
57
      "Use 'for' elements when building maps from iterables.",
58
      correctionMessage:
59
          "Try using a collection literal with a 'for' element.");
60

61
  PreferForElementsToMapFromIterable()
1✔
62
      : super(
1✔
63
            name: 'prefer_for_elements_to_map_fromIterable',
64
            description: _desc,
65
            details: _details,
66
            group: Group.style);
67

68
  @override
1✔
69
  LintCode get lintCode => code;
70

71
  @override
1✔
72
  void registerNodeProcessors(
73
      NodeLintRegistry registry, LinterContext context) {
74
    var visitor = _Visitor(this, context);
1✔
75
    registry.addInstanceCreationExpression(this, visitor);
1✔
76
  }
77
}
78

79
class _Visitor extends SimpleAstVisitor<void> {
80
  final LintRule rule;
81
  final LinterContext context;
82

83
  _Visitor(this.rule, this.context);
1✔
84

85
  @override
1✔
86
  void visitInstanceCreationExpression(InstanceCreationExpression creation) {
87
    var element = creation.constructorName.staticElement;
2✔
88
    if (element == null ||
89
        element.name != 'fromIterable' ||
2✔
90
        element.enclosingElement != context.typeProvider.mapElement) {
5✔
91
      return;
92
    }
93

94
    //
95
    // Ensure that the arguments have the right form.
96
    //
97
    var arguments = creation.argumentList.arguments;
2✔
98
    if (arguments.length != 3) {
2✔
99
      return;
100
    }
101

102
    // TODO(srawlins): Handle named arguments anywhere.
103
    var secondArg = arguments[1];
1✔
104
    var thirdArg = arguments[2];
1✔
105

106
    var keyClosure =
107
        _extractClosure('key', secondArg) ?? _extractClosure('key', thirdArg);
1✔
108
    var valueClosure = _extractClosure('value', thirdArg) ??
1✔
109
        _extractClosure('value', secondArg);
×
110
    if (keyClosure == null || valueClosure == null) {
111
      return;
112
    }
113

114
    rule.reportLint(creation);
2✔
115
  }
116

117
  FunctionExpression? _extractClosure(String name, Expression argument) {
1✔
118
    if (argument is NamedExpression && argument.name.label.name == name) {
5✔
119
      var expression = argument.expression.unParenthesized;
2✔
120
      if (expression is FunctionExpression) {
1✔
121
        var parameters = expression.parameters?.parameters;
2✔
122
        if (parameters != null &&
123
            parameters.length == 1 &&
2✔
124
            parameters.first.isRequired) {
2✔
125
          if (expression.hasSingleExpressionBody) {
1✔
126
            return expression;
127
          }
128
        }
129
      }
130
    }
131
    return null;
132
  }
133
}
134

135
extension on FunctionExpression {
136
  /// Whether this has a single expression body, which could be a single
137
  /// return statement in a block function body.
138
  bool get hasSingleExpressionBody {
1✔
139
    var body = this.body;
1✔
140
    if (body is ExpressionFunctionBody) {
1✔
141
      return true;
142
    } else if (body is BlockFunctionBody) {
×
143
      var statements = body.block.statements;
×
144
      if (statements.length == 1) {
×
145
        return statements.first is ReturnStatement;
×
146
      }
147
    }
148
    return false;
149
  }
150
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc