@@ -24,6 +24,7 @@ import reporting._
24
24
import io .{AbstractFile , NoAbstractFile , PlainFile , Path }
25
25
import scala .io .Codec
26
26
import collection .mutable
27
+ import parsing .Parsers
27
28
import printing ._
28
29
import config .{JavaPlatform , SJSPlatform , Platform , ScalaSettings , ScalaRelease }
29
30
import classfile .ReusableDataReader
@@ -1025,6 +1026,7 @@ object Contexts:
1025
1026
/** Collect information about the run for purposes of additional diagnostics.
1026
1027
*/
1027
1028
class Usages :
1029
+ import rewrites .Rewrites .patch
1028
1030
private val selectors = mutable.Map .empty[ImportInfo , Set [untpd.ImportSelector ]].withDefaultValue(Set .empty)
1029
1031
private val importInfos = mutable.Map .empty[CompilationUnit , List [(ImportInfo , Symbol )]].withDefaultValue(Nil )
1030
1032
@@ -1048,19 +1050,56 @@ object Contexts:
1048
1050
end if
1049
1051
def checkUsed (info : ImportInfo , owner : Symbol ): Unit =
1050
1052
val used = selectors(info)
1053
+ var needsPatch = false
1051
1054
def cull (toCheck : List [untpd.ImportSelector ]): Unit =
1052
1055
toCheck match
1053
1056
case selector :: rest =>
1054
1057
cull(rest) // reverse
1055
1058
if ! selector.isMask && ! used(selector) then
1056
1059
unusages ::= ((info, owner, selector))
1060
+ needsPatch = true
1057
1061
case _ =>
1058
1062
cull(info.selectors)
1063
+ val decidingFactor = false // whether to apply patches
1064
+ if decidingFactor && needsPatch && ! ctx.settings.rewrite.value.isEmpty then
1065
+ val retained = info.selectors.filter(sel => sel.isMask || used(sel))
1066
+ val infoPos = info.qualifier.sourcePos
1067
+ val lineText = infoPos.lineContent
1068
+ val src = ctx.compilationUnit.source
1069
+ val lineSpan = src.lineSpan(infoPos.start)
1070
+ val selectorSpan = info.selectors.map(_.span).reduce(_ union _)
1071
+ val lineSource = SourceFile .virtual(name = " import-line.scala" , content = lineText)
1072
+ val parser = Parsers .Parser (lineSource)
1073
+ val lineTree = parser.parse()
1074
+ val PackageDef (_, pieces) = lineTree : @ unchecked
1075
+ // patch if there's just one import on the line, i.e., not import a.b, c.d
1076
+ if pieces.length == 1 then
1077
+ if retained.isEmpty then
1078
+ patch(src, lineSpan, " " ) // line deletion
1079
+ else if retained.size == 1 && info.selectors.size > 1 then
1080
+ var starting = info.selectors.head.span.start
1081
+ while starting > lineSpan.start && src.content()(starting) != '{' do starting -= 1
1082
+ var ending = info.selectors.last.span.end
1083
+ while ending <= lineSpan.end && src.content()(ending) != '}' do ending += 1
1084
+ if ending < lineSpan.end then ending += 1 // past the close brace
1085
+ val widened = selectorSpan.withStart(starting).withEnd(ending)
1086
+ patch(src, widened, toText(retained)) // try to remove braces
1087
+ else
1088
+ patch(src, selectorSpan, toText(retained))
1059
1089
end checkUsed
1060
1090
importInfos.remove(ctx.compilationUnit).foreach(_.foreach(checkUsed))
1061
1091
unusages
1062
1092
end unused
1063
1093
1094
+ // just the selectors, no need to add braces
1095
+ private def toText (retained : List [untpd.ImportSelector ])(using Context ): String =
1096
+ def selected (sel : untpd.ImportSelector ) =
1097
+ if sel.isGiven then " given"
1098
+ else if sel.isWildcard then " *"
1099
+ else if sel.name == sel.rename then sel.name.show
1100
+ else s " ${sel.name.show} as ${sel.rename.show}"
1101
+ retained.map(selected).mkString(" , " )
1102
+
1064
1103
def clear ()(using Context ): Unit =
1065
1104
importInfos.clear()
1066
1105
selectors.clear()
0 commit comments