@@ -17,6 +17,13 @@ const _desc = 'Unreachable top-level members in executable libraries.';
17
17
18
18
const _details = r'''
19
19
Top-level members and static members in an executable library should be used
20
+ '''
21
+ // TODO(srawlins): Lasse
22
+ // [suggests](https://github.com/dart-lang/linter/issues/3625#issuecomment-1735355630)
23
+ // changing this to use "statically resolved" members, which I love. But it
24
+ // will mean reporting additionally on extension instance members and extension
25
+ // type instance members, so land carefully.
26
+ '''
20
27
directly inside this library. An executable library is a library that contains
21
28
a `main` top-level function or that contains a top-level function annotated with
22
29
`@pragma('vm:entry-point')`). Executable libraries are not usually imported
@@ -106,6 +113,11 @@ class _DeclarationGatherer {
106
113
containerElement: null ,
107
114
members: declaration.members,
108
115
);
116
+ } else if (declaration is ExtensionTypeDeclaration ) {
117
+ _addMembers (
118
+ containerElement: null ,
119
+ members: declaration.members,
120
+ );
109
121
} else if (declaration is MixinDeclaration ) {
110
122
_addMembers (
111
123
containerElement: declaration.declaredElement,
@@ -241,9 +253,9 @@ class _ReferenceVisitor extends RecursiveAstVisitor {
241
253
242
254
@override
243
255
void visitConstructorDeclaration (ConstructorDeclaration node) {
244
- // If a constructor does not have an explicit super-initializer (or
245
- // redirection?) then it has an implicit super-initializer to the
246
- // super-type's unnamed constructor.
256
+ // If a constructor in a class declaration does not have an explicit
257
+ // super-initializer (or redirection?) then it has an implicit
258
+ // super-initializer to the super- type's unnamed constructor.
247
259
var hasSuperInitializer =
248
260
node.initializers.any ((e) => e is SuperConstructorInvocation );
249
261
if (! hasSuperInitializer) {
@@ -264,6 +276,13 @@ class _ReferenceVisitor extends RecursiveAstVisitor {
264
276
super .visitConstructorName (node);
265
277
}
266
278
279
+ @override
280
+ void visitExtensionTypeDeclaration (ExtensionTypeDeclaration node) {
281
+ _addNamedTypes (node.implementsClause? .interfaces);
282
+
283
+ super .visitExtensionTypeDeclaration (node);
284
+ }
285
+
267
286
@override
268
287
void visitNamedType (NamedType node) {
269
288
var element = node.element;
@@ -274,14 +293,18 @@ class _ReferenceVisitor extends RecursiveAstVisitor {
274
293
var nodeIsInTypeArgument =
275
294
node.thisOrAncestorOfType <TypeArgumentList >() != null ;
276
295
277
- // Any reference to a typedef is reachable, since structural typing is used
278
- // to match against objects.
279
- //
280
- // The return type of an external variable declaration is reachable, since
281
- // the external implementation can instantiate it.
282
- if (node.type? .alias != null ||
283
- nodeIsInTypeArgument ||
284
- node.isInExternalVariableTypeOrFunctionReturnType) {
296
+ if (
297
+ // Any reference to a typedef marks it as reachable, since structural
298
+ // typing is used to match against objects.
299
+ node.type? .alias != null ||
300
+ // Any reference to an extension type marks it as reachable, since
301
+ // casting can be used to instantiate the type.
302
+ node.type? .element is ExtensionTypeElement ||
303
+ nodeIsInTypeArgument ||
304
+ // A reference to any type in an external variable declaration marks
305
+ // that type as reachable, since the external implementation can
306
+ // instantiate it.
307
+ node.isInExternalVariableTypeOrFunctionReturnType) {
285
308
_addDeclaration (element);
286
309
}
287
310
@@ -378,7 +401,8 @@ class _ReferenceVisitor extends RecursiveAstVisitor {
378
401
return ;
379
402
}
380
403
if (enclosingElement is InterfaceElement ||
381
- enclosingElement is ExtensionElement ) {
404
+ enclosingElement is ExtensionElement ||
405
+ enclosingElement is ExtensionTypeElement ) {
382
406
var declarationElement = element.declaration;
383
407
var declaration = declarationMap[declarationElement];
384
408
if (declaration != null ) {
0 commit comments