@@ -7,13 +7,13 @@ import dotty.tools.dotc.ast.untpd.ImportSelector
7
7
import dotty .tools .dotc .config .ScalaSettings
8
8
import dotty .tools .dotc .core .Contexts .*
9
9
import dotty .tools .dotc .core .Decorators .{em , i }
10
- import dotty .tools .dotc .core .Flags ._
10
+ import dotty .tools .dotc .core .Flags .*
11
11
import dotty .tools .dotc .core .Phases .Phase
12
12
import dotty .tools .dotc .core .StdNames
13
13
import dotty .tools .dotc .report
14
14
import dotty .tools .dotc .reporting .Message
15
15
import dotty .tools .dotc .typer .ImportInfo
16
- import dotty .tools .dotc .util .Property
16
+ import dotty .tools .dotc .util .{ Property , SrcPos }
17
17
import dotty .tools .dotc .core .Mode
18
18
import dotty .tools .dotc .core .Types .TypeTraverser
19
19
import dotty .tools .dotc .core .Types .Type
@@ -28,6 +28,7 @@ import dotty.tools.dotc.core.Types.ConstantType
28
28
import dotty .tools .dotc .core .NameKinds .WildcardParamName
29
29
import dotty .tools .dotc .core .Types .TermRef
30
30
import dotty .tools .dotc .core .Types .NameFilter
31
+ import dotty .tools .dotc .core .Symbols .Symbol
31
32
32
33
33
34
@@ -81,7 +82,7 @@ class CheckUnused extends MiniPhase:
81
82
ctx
82
83
83
84
override def prepareForIdent (tree : tpd.Ident )(using Context ): Context =
84
- if tree.symbol.exists then
85
+ if tree.symbol.exists then
85
86
_key.unusedDataApply(_.registerUsed(tree.symbol, Some (tree.name)))
86
87
else if tree.hasType then
87
88
_key.unusedDataApply(_.registerUsed(tree.tpe.classSymbol, Some (tree.name)))
@@ -103,7 +104,8 @@ class CheckUnused extends MiniPhase:
103
104
override def prepareForValDef (tree : tpd.ValDef )(using Context ): Context =
104
105
_key.unusedDataApply{ud =>
105
106
// do not register the ValDef generated for `object`
106
- if ! tree.symbol.is(Module ) then
107
+ traverseAnnotations(tree.symbol)
108
+ if ! tree.symbol.is(Module ) then
107
109
ud.registerDef(tree)
108
110
ud.addIgnoredUsage(tree.symbol)
109
111
}
@@ -112,18 +114,21 @@ class CheckUnused extends MiniPhase:
112
114
_key.unusedDataApply{ ud =>
113
115
import ud .registerTrivial
114
116
tree.registerTrivial
117
+ traverseAnnotations(tree.symbol)
115
118
ud.registerDef(tree)
116
119
ud.addIgnoredUsage(tree.symbol)
117
120
}
118
121
119
122
override def prepareForTypeDef (tree : tpd.TypeDef )(using Context ): Context =
120
123
_key.unusedDataApply{ ud =>
121
124
if ! tree.symbol.is(Param ) then // Ignore type parameter (as Scala 2)
125
+ traverseAnnotations(tree.symbol)
122
126
ud.registerDef(tree)
123
127
ud.addIgnoredUsage(tree.symbol)
124
128
}
125
129
126
130
override def prepareForBind (tree : tpd.Bind )(using Context ): Context =
131
+ traverseAnnotations(tree.symbol)
127
132
_key.unusedDataApply(_.registerPatVar(tree))
128
133
129
134
override def prepareForTypeTree (tree : tpd.TypeTree )(using Context ): Context =
@@ -232,6 +237,10 @@ class CheckUnused extends MiniPhase:
232
237
case AnnotatedType (_, annot) => dt(_.registerUsed(annot.symbol, None ))
233
238
case _ => traverseChildren(tp)
234
239
240
+ /** This traverse the annotations of the symbol */
241
+ private def traverseAnnotations (sym : Symbol )(using Context ): Unit =
242
+ sym.denot.annotations.foreach(annot => traverser.traverse(annot.tree))
243
+
235
244
/** Do the actual reporting given the result of the anaylsis */
236
245
private def reportUnused (res : UnusedData .UnusedResult )(using Context ): Unit =
237
246
import CheckUnused .WarnTypes
@@ -274,7 +283,6 @@ object CheckUnused:
274
283
private class UnusedData :
275
284
import dotty .tools .dotc .transform .CheckUnused .UnusedData .UnusedResult
276
285
import collection .mutable .{Set => MutSet , Map => MutMap , Stack => MutStack }
277
- import dotty .tools .dotc .core .Symbols .Symbol
278
286
import UnusedData .ScopeType
279
287
280
288
/** The current scope during the tree traversal */
@@ -289,6 +297,7 @@ object CheckUnused:
289
297
* See the `isAccessibleAsIdent` extension method below in the file
290
298
*/
291
299
private val usedInScope = MutStack (MutSet [(Symbol ,Boolean , Option [Name ])]())
300
+ private val usedInPosition = MutSet [(SrcPos , Name )]()
292
301
/* unused import collected during traversal */
293
302
private val unusedImport = MutSet [ImportSelector ]()
294
303
@@ -324,25 +333,21 @@ object CheckUnused:
324
333
execInNewScope
325
334
popScope()
326
335
327
- /** Register all annotations of this symbol's denotation */
328
- def registerUsedAnnotation (sym : Symbol )(using Context ): Unit =
329
- val annotSym = sym.denot.annotations.map(_.symbol)
330
- annotSym.foreach(s => registerUsed(s, None ))
331
-
332
336
/**
333
337
* Register a found (used) symbol along with its name
334
338
*
335
339
* The optional name will be used to target the right import
336
340
* as the same element can be imported with different renaming
337
341
*/
338
- def registerUsed (sym : Symbol , name : Option [Name ])(using Context ): Unit =
342
+ def registerUsed (sym : Symbol , name : Option [Name ])(using Context ): Unit =
339
343
if ! isConstructorOfSynth(sym) && ! doNotRegister(sym) then
340
344
if sym.isConstructor && sym.exists then
341
345
registerUsed(sym.owner, None ) // constructor are "implicitly" imported with the class
342
346
else
343
347
usedInScope.top += ((sym, sym.isAccessibleAsIdent, name))
344
348
usedInScope.top += ((sym.companionModule, sym.isAccessibleAsIdent, name))
345
349
usedInScope.top += ((sym.companionClass, sym.isAccessibleAsIdent, name))
350
+ name.map(n => usedInPosition += ((sym.sourcePos, n)))
346
351
347
352
/** Register a symbol that should be ignored */
348
353
def addIgnoredUsage (sym : Symbol )(using Context ): Unit =
@@ -363,22 +368,19 @@ object CheckUnused:
363
368
364
369
/** Register (or not) some `val` or `def` according to the context, scope and flags */
365
370
def registerDef (memDef : tpd.MemberDef )(using Context ): Unit =
366
- // register the annotations for usage
367
- registerUsedAnnotation(memDef.symbol)
368
371
if memDef.isValidMemberDef then
369
372
if memDef.isValidParam then
370
373
if memDef.symbol.isOneOf(GivenOrImplicit ) then
371
374
implicitParamInScope += memDef
372
375
else
373
376
explicitParamInScope += memDef
374
- else if currScopeType.top == ScopeType .Local then
377
+ else if currScopeType.top == ScopeType .Local then
375
378
localDefInScope += memDef
376
379
else if memDef.shouldReportPrivateDef then
377
380
privateDefInScope += memDef
378
381
379
382
/** Register pattern variable */
380
383
def registerPatVar (patvar : tpd.Bind )(using Context ): Unit =
381
- registerUsedAnnotation(patvar.symbol)
382
384
if ! patvar.symbol.isUnusedAnnot then
383
385
patVarsInScope += patvar
384
386
@@ -450,6 +452,7 @@ object CheckUnused:
450
452
if ctx.settings.WunusedHas .locals then
451
453
localDefInScope
452
454
.filterNot(d => d.symbol.usedDefContains)
455
+ .filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name})
453
456
.map(d => d.namePos -> WarnTypes .LocalDefs ).toList
454
457
else
455
458
Nil
@@ -478,6 +481,7 @@ object CheckUnused:
478
481
if ctx.settings.WunusedHas .patvars then
479
482
patVarsInScope
480
483
.filterNot(d => d.symbol.usedDefContains)
484
+ .filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name})
481
485
.map(d => d.namePos -> WarnTypes .PatVars ).toList
482
486
else
483
487
Nil
@@ -578,10 +582,10 @@ object CheckUnused:
578
582
else
579
583
false
580
584
581
- private def usedDefContains (using Context ): Boolean =
585
+ private def usedDefContains (using Context ): Boolean =
582
586
sym.everySymbol.exists(usedDef.apply)
583
587
584
- private def everySymbol (using Context ): List [Symbol ] =
588
+ private def everySymbol (using Context ): List [Symbol ] =
585
589
List (sym, sym.companionClass, sym.companionModule, sym.moduleClass).filter(_.exists)
586
590
587
591
end extension
@@ -614,10 +618,11 @@ object CheckUnused:
614
618
private def isValidParam (using Context ): Boolean =
615
619
val sym = memDef.symbol
616
620
(sym.is(Param ) || sym.isAllOf(PrivateParamAccessor | Local , butNot = CaseAccessor )) &&
617
- ! isSyntheticMainParam(sym) &&
618
- ! sym.shouldNotReportParamOwner
621
+ ! isSyntheticMainParam(sym) &&
622
+ ! sym.shouldNotReportParamOwner &&
623
+ (! sym.exists || ! sym.owner.isAllOf(Synthetic | PrivateLocal ))
619
624
620
- private def shouldReportPrivateDef (using Context ): Boolean =
625
+ private def shouldReportPrivateDef (using Context ): Boolean =
621
626
currScopeType.top == ScopeType .Template && ! memDef.symbol.isConstructor && memDef.symbol.is(Private , butNot = SelfName | Synthetic | CaseAccessor )
622
627
623
628
extension (imp : tpd.Import )
0 commit comments