@@ -368,7 +368,7 @@ object CheckUnused:
368368
369369 /** Register an import */
370370 def registerImport (imp : tpd.Import )(using Context ): Unit =
371- if ! tpd.languageImport(imp.expr).nonEmpty && ! imp.isGeneratedByEnum then
371+ if ! tpd.languageImport(imp.expr).nonEmpty && ! imp.isGeneratedByEnum && ! isTransparentAndInline(imp) then
372372 impInScope.top += imp
373373 unusedImport ++= imp.selectors.filter { s =>
374374 ! shouldSelectorBeReported(imp, s) && ! isImportExclusion(s)
@@ -432,6 +432,7 @@ object CheckUnused:
432432 else
433433 exists
434434 }
435+
435436 // if there's an outer scope
436437 if usedInScope.nonEmpty then
437438 // we keep the symbols not referencing an import in this scope
@@ -450,6 +451,7 @@ object CheckUnused:
450451 */
451452 def getUnused (using Context ): UnusedResult =
452453 popScope()
454+
453455 val sortedImp =
454456 if ctx.settings.WunusedHas .imports || ctx.settings.WunusedHas .strictNoImplicitWarn then
455457 unusedImport.map(d => d.srcPos -> WarnTypes .Imports ).toList
@@ -460,34 +462,39 @@ object CheckUnused:
460462 localDefInScope
461463 .filterNot(d => d.symbol.usedDefContains)
462464 .filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name})
465+ .filterNot(d => containsSyntheticSuffix(d.symbol))
463466 .map(d => d.namePos -> WarnTypes .LocalDefs ).toList
464467 else
465468 Nil
466469 val sortedExplicitParams =
467470 if ctx.settings.WunusedHas .explicits then
468471 explicitParamInScope
469472 .filterNot(d => d.symbol.usedDefContains)
473+ .filterNot(d => containsSyntheticSuffix(d.symbol))
470474 .map(d => d.namePos -> WarnTypes .ExplicitParams ).toList
471475 else
472476 Nil
473477 val sortedImplicitParams =
474478 if ctx.settings.WunusedHas .implicits then
475479 implicitParamInScope
476480 .filterNot(d => d.symbol.usedDefContains)
481+ .filterNot(d => containsSyntheticSuffix(d.symbol))
477482 .map(d => d.namePos -> WarnTypes .ImplicitParams ).toList
478483 else
479484 Nil
480485 val sortedPrivateDefs =
481486 if ctx.settings.WunusedHas .privates then
482487 privateDefInScope
483488 .filterNot(d => d.symbol.usedDefContains)
489+ .filterNot(d => containsSyntheticSuffix(d.symbol))
484490 .map(d => d.namePos -> WarnTypes .PrivateMembers ).toList
485491 else
486492 Nil
487493 val sortedPatVars =
488494 if ctx.settings.WunusedHas .patvars then
489495 patVarsInScope
490496 .filterNot(d => d.symbol.usedDefContains)
497+ .filterNot(d => containsSyntheticSuffix(d.symbol))
491498 .filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name})
492499 .map(d => d.namePos -> WarnTypes .PatVars ).toList
493500 else
@@ -500,6 +507,23 @@ object CheckUnused:
500507 end getUnused
501508 // ============================ HELPERS ====================================
502509
510+
511+ /**
512+ * Checks if import selects a def that is transparent and inline
513+ */
514+ private def isTransparentAndInline (imp : tpd.Import )(using Context ): Boolean =
515+ imp.selectors.exists { sel =>
516+ val qual = imp.expr
517+ val importedMembers = qual.tpe.member(sel.name).alternatives.map(_.symbol)
518+ importedMembers.exists(s => s.is(Transparent ) && s.is(Inline ))
519+ }
520+
521+ /**
522+ * Heuristic to detect synthetic suffixes in names of symbols
523+ */
524+ private def containsSyntheticSuffix (symbol : Symbol )(using Context ): Boolean =
525+ symbol.name.mangledString.contains(" $" )
526+
503527 /**
504528 * Is the the constructor of synthetic package object
505529 * Should be ignored as it is always imported/used in package
0 commit comments