Skip to content
This repository was archived by the owner on Nov 20, 2024. It is now read-only.

Commit aa0aa82

Browse files
committed
address review comments
1 parent fd323ad commit aa0aa82

File tree

2 files changed

+97
-24
lines changed

2 files changed

+97
-24
lines changed

lib/src/rules/unused_top_members_in_executable_libraries.dart

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'dart:collection';
6+
57
import 'package:analyzer/dart/ast/ast.dart';
68
import 'package:analyzer/dart/ast/visitor.dart';
79
import 'package:analyzer/dart/element/element.dart';
@@ -15,11 +17,11 @@ const _desc = 'Unused top-level members in executable libraries.';
1517
const _details = r'''
1618
1719
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.
2022
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.
2325
2426
**BAD:**
2527
@@ -46,6 +48,7 @@ class UnusedTopMembersInExecutableLibraries extends LintRule {
4648
description: _desc,
4749
details: _details,
4850
group: Group.style,
51+
maturity: Maturity.experimental,
4952
);
5053

5154
@override
@@ -78,7 +81,8 @@ class _Visitor extends SimpleAstVisitor<void> {
7881
])
7982
.toSet();
8083

81-
if (!topDeclarations.any(_isEntryPoint)) return;
84+
var entryPoints = topDeclarations.where(_isEntryPoint).toList();
85+
if (entryPoints.isEmpty) return;
8286

8387
var declarationByElement = <Element, Declaration>{};
8488
for (var declaration in topDeclarations) {
@@ -98,26 +102,32 @@ class _Visitor extends SimpleAstVisitor<void> {
98102

99103
var dependencies = Map<Declaration, Set<Declaration>>.fromIterable(
100104
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(),
114127
);
115128

116-
var entryPoints = topDeclarations.where(_isEntryPoint);
117-
if (entryPoints.isEmpty) return;
118-
119129
var usedMembers = entryPoints.toSet();
120-
var toTraverse = usedMembers.toList();
130+
var toTraverse = Queue.from(usedMembers);
121131
while (toTraverse.isNotEmpty) {
122132
var declaration = toTraverse.removeLast();
123133
for (var dep in dependencies[declaration]!) {

test_data/rules/unused_top_members_in_executable_libraries.dart

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import 'package:meta/meta.dart';
88

9+
/// see [Comment]
910
main() // OK
1011
{
1112
_f5();
@@ -14,8 +15,16 @@ main() // OK
1415
f4(b);
1516
});
1617
f4(b);
18+
usageInTypeBound();
19+
usageInFunctionType();
20+
usageInDefaultValue();
21+
usageInAnnotation();
22+
Future<C5>.value(C5()).extensionUsage();
23+
accessors();
1724
}
1825

26+
class Comment {} // LINT
27+
1928
const a = 1; // LINT
2029
const b = 1; // OK
2130

@@ -44,8 +53,8 @@ void f2() // OK
4453
f1();
4554
}
4655

47-
void f3(Function f) {} //OK
48-
void f4(int p) {} //OK
56+
void f3(Function f) {} // OK
57+
void f4(int p) {} // OK
4958

5059
int id = 0; // OK
5160
void _f5() {
@@ -54,3 +63,57 @@ void _f5() {
5463

5564
@pragma('vm:entry-point')
5665
void f6() {} // OK
66+
67+
const entryPoint = pragma('vm:entry-point');
68+
@entryPoint
69+
void f7() {} // OK
70+
71+
@pragma('other') // LINT
72+
void f8() {}
73+
74+
// test accessors
75+
int get id9 => 0;
76+
void set id9(int value) {}
77+
void accessors() {
78+
id9 += 4; // usage
79+
}
80+
81+
// Usage in type bound
82+
class C1 {}
83+
84+
void usageInTypeBound<T extends C1>() {}
85+
86+
// Usage in Function type
87+
class C2 {}
88+
89+
void Function(C2)? usageInFunctionType() {}
90+
91+
// Usage in default value
92+
class C3 {
93+
const C3();
94+
}
95+
96+
void usageInDefaultValue([Object? p = const C3()]) {}
97+
98+
// Usage in annotation
99+
class C4 {
100+
const C4();
101+
}
102+
103+
@C4()
104+
void usageInAnnotation() {}
105+
106+
// Usage in type parameter in extension `on` clause.
107+
class C5 {}
108+
109+
extension UsedPublicExt on Future<C5> {
110+
extensionUsage() {}
111+
}
112+
113+
// Usage in type parameter in extension `on` clause.
114+
class C6 {} //LINT
115+
116+
extension UnusedPublicExt on C6 //LINT
117+
{
118+
m() {}
119+
}

0 commit comments

Comments
 (0)