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

Commit 7502bb1

Browse files
committed
address review comments
1 parent 5023beb commit 7502bb1

File tree

2 files changed

+38
-31
lines changed

2 files changed

+38
-31
lines changed

lib/src/rules/unreachable_from_main.dart

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ const _desc = 'Unreachable top-level members in executable libraries.';
1717
const _details = r'''
1818
1919
Top-level members in an executable library should be used directly inside this
20-
library. Executable libraries are usually never imported and it's better to
21-
avoid defining unused members.
20+
library. An executable library is a library that contains a `main` top-level
21+
function or that contains a top-level function annotated with
22+
`@pragma('vm:entry-point')`). Executable libraries are usually never imported
23+
and it's better to avoid defining unused members.
2224
2325
This rule assumes that an executable library isn't imported by other files
2426
except to execute its `main` function.
@@ -100,6 +102,8 @@ class _Visitor extends SimpleAstVisitor<void> {
100102
}
101103
}
102104

105+
// The following map contains for every declaration the set of the
106+
// declarations it references.
103107
var dependencies = Map<Declaration, Set<Declaration>>.fromIterable(
104108
topDeclarations,
105109
value: (declaration) =>
@@ -113,21 +117,22 @@ class _Visitor extends SimpleAstVisitor<void> {
113117
],
114118
])
115119
.whereNotNull()
116-
.map((e) {
117-
while (e.enclosingElement2 != null &&
118-
e.enclosingElement2 is! CompilationUnitElement) {
119-
e = e.enclosingElement2!;
120-
}
121-
return e;
122-
})
120+
.map((e) => e.thisOrAncestorMatching((a) =>
121+
a.enclosingElement2 == null ||
122+
a.enclosingElement2 is CompilationUnitElement))
123123
.map((e) => declarationByElement[e])
124124
.whereNotNull()
125125
.where((e) => e != declaration)
126126
.toSet(),
127127
);
128128

129129
var usedMembers = entryPoints.toSet();
130-
var toTraverse = Queue.from(usedMembers);
130+
// The following variable will be used to visit every reachable declaration
131+
// starting from entry-points. At every loop an element is removed. This
132+
// element is marked as used and we add its dependencies in the declaration
133+
// list to traverse. Once this list is empty `usedMembers` contains every
134+
// declarations reachable from an entry-point.
135+
var toTraverse = Queue.of(usedMembers);
131136
while (toTraverse.isNotEmpty) {
132137
var declaration = toTraverse.removeLast();
133138
for (var dep in dependencies[declaration]!) {
@@ -163,26 +168,17 @@ class _Visitor extends SimpleAstVisitor<void> {
163168
(e.name.name == 'main' || e.metadata.any(_isPragmaVmEntry));
164169

165170
bool _isPragmaVmEntry(Annotation annotation) {
166-
var elementAnnotation = annotation.elementAnnotation;
167-
if (elementAnnotation != null) {
168-
var value = elementAnnotation.computeConstantValue();
169-
if (value != null) {
170-
var type = value.type;
171-
if (type != null) {
172-
var element = type.element;
173-
if (element != null) {
174-
var library = element.library;
175-
if (library != null && library.isDartCore ||
176-
element.name == 'pragma') {
177-
var name = value.getField('name');
178-
return name != null &&
179-
name.hasKnownValue &&
180-
name.toStringValue() == 'vm:entry-point';
181-
}
182-
}
183-
}
184-
}
185-
}
186-
return false;
171+
var value = annotation.elementAnnotation?.computeConstantValue();
172+
if (value == null) return false;
173+
var element = value.type?.element;
174+
if (element == null || !element.isPragma) return false;
175+
var name = value.getField('name');
176+
return name != null &&
177+
name.hasKnownValue &&
178+
name.toStringValue() == 'vm:entry-point';
187179
}
188180
}
181+
182+
extension on Element {
183+
bool get isPragma => (library?.isDartCore ?? false) && name == 'pragma';
184+
}

test_data/rules/unreachable_from_main.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,18 @@ main() // OK
2121
usageInAnnotation();
2222
Future<C5>.value(C5()).extensionUsage();
2323
accessors();
24+
print(c2);
2425
}
2526

2627
class Comment {} // LINT
2728

2829
const a = 1; // LINT
2930
const b = 1; // OK
3031

32+
final int //
33+
c1 = 1, // LINT
34+
c2 = 2; // OK
35+
3136
int v = 1; // LINT
3237

3338
typedef A = String; // LINT
@@ -117,3 +122,9 @@ extension UnusedPublicExt on C6 //LINT
117122
{
118123
m() {}
119124
}
125+
126+
class C7 // LINT
127+
{
128+
C7();
129+
C7.named();
130+
}

0 commit comments

Comments
 (0)