2
2
// for details. All rights reserved. Use of this source code is governed by a
3
3
// BSD-style license that can be found in the LICENSE file.
4
4
5
+ import 'dart:collection' ;
6
+
5
7
import 'package:analyzer/dart/ast/ast.dart' ;
6
8
import 'package:analyzer/dart/ast/visitor.dart' ;
7
9
import 'package:analyzer/dart/element/element.dart' ;
@@ -15,11 +17,11 @@ const _desc = 'Unused top-level members in executable libraries.';
15
17
const _details = r'''
16
18
17
19
Top-level members in an executable library should be used directly inside this
18
- library. Executable libraries are usually never used as dependency and it's
19
- better to avoid defining unused members.
20
+ library. Executable libraries are usually never imported and it's better to
21
+ avoid defining unused members.
20
22
21
- This rule assumes that an executable library shouldn 't be imported by other
22
- files except to execute its `main` function.
23
+ This rule assumes that an executable library isn 't imported by other files
24
+ except to execute its `main` function.
23
25
24
26
**BAD:**
25
27
@@ -46,6 +48,7 @@ class UnusedTopMembersInExecutableLibraries extends LintRule {
46
48
description: _desc,
47
49
details: _details,
48
50
group: Group .style,
51
+ maturity: Maturity .experimental,
49
52
);
50
53
51
54
@override
@@ -78,7 +81,8 @@ class _Visitor extends SimpleAstVisitor<void> {
78
81
])
79
82
.toSet ();
80
83
81
- if (! topDeclarations.any (_isEntryPoint)) return ;
84
+ var entryPoints = topDeclarations.where (_isEntryPoint).toList ();
85
+ if (entryPoints.isEmpty) return ;
82
86
83
87
var declarationByElement = < Element , Declaration > {};
84
88
for (var declaration in topDeclarations) {
@@ -98,26 +102,32 @@ class _Visitor extends SimpleAstVisitor<void> {
98
102
99
103
var dependencies = Map <Declaration , Set <Declaration >>.fromIterable (
100
104
topDeclarations,
101
- value: (e) => DartTypeUtilities .traverseNodesInDFS (e as Declaration )
102
- .expand ((e) => [
103
- if (e is SimpleIdentifier ) e.staticElement,
104
- // with `id++` staticElement of `id` is null
105
- if (e is CompoundAssignmentExpression ) ...[
106
- e.readElement,
107
- e.writeElement,
108
- ],
109
- ])
110
- .whereNotNull ()
111
- .map ((e) => declarationByElement[e])
112
- .whereNotNull ()
113
- .toSet (),
105
+ value: (declaration) =>
106
+ DartTypeUtilities .traverseNodesInDFS (declaration as Declaration )
107
+ .expand ((e) => [
108
+ if (e is SimpleIdentifier ) e.staticElement,
109
+ // with `id++` staticElement of `id` is null
110
+ if (e is CompoundAssignmentExpression ) ...[
111
+ e.readElement,
112
+ e.writeElement,
113
+ ],
114
+ ])
115
+ .whereNotNull ()
116
+ .map ((e) {
117
+ while (e.enclosingElement != null &&
118
+ e.enclosingElement is ! CompilationUnitElement ) {
119
+ e = e.enclosingElement! ;
120
+ }
121
+ return e;
122
+ })
123
+ .map ((e) => declarationByElement[e])
124
+ .whereNotNull ()
125
+ .where ((e) => e != declaration)
126
+ .toSet (),
114
127
);
115
128
116
- var entryPoints = topDeclarations.where (_isEntryPoint);
117
- if (entryPoints.isEmpty) return ;
118
-
119
129
var usedMembers = entryPoints.toSet ();
120
- var toTraverse = usedMembers. toList ( );
130
+ var toTraverse = Queue . from (usedMembers );
121
131
while (toTraverse.isNotEmpty) {
122
132
var declaration = toTraverse.removeLast ();
123
133
for (var dep in dependencies[declaration]! ) {
0 commit comments