@@ -62,12 +62,6 @@ class OrganizeImports(
62
62
63
63
private val wildcardGroupIndex : Int = matchers indexOf *
64
64
65
- private val unusedImporteePositions : mutable.Set [Position ] =
66
- mutable.Set .empty[Position ]
67
-
68
- private val diagnostics : ArrayBuffer [Diagnostic ] =
69
- ArrayBuffer .empty[Diagnostic ]
70
-
71
65
def this () = this (OrganizeImportsConfig ())
72
66
73
67
override def description : String = " Organize import statements"
@@ -95,43 +89,49 @@ class OrganizeImports(
95
89
}
96
90
97
91
private def fixWithImplicitDialect (implicit doc : SemanticDocument ): Patch = {
98
- unusedImporteePositions ++= doc.diagnostics.collect {
99
- case d if d.message == " Unused import" => d.position
100
- }
92
+
93
+ val diagnostics : ArrayBuffer [Diagnostic ] = ArrayBuffer .empty[Diagnostic ]
94
+
95
+ val unusedImporteePositions = new UnusedImporteePositions
101
96
102
97
val (globalImports, localImports) = collectImports(doc.tree)
103
98
104
99
val globalImportsPatch =
105
100
if (globalImports.isEmpty) Patch .empty
106
- else organizeGlobalImports(globalImports)
101
+ else
102
+ organizeGlobalImports(unusedImporteePositions, diagnostics)(
103
+ globalImports
104
+ )
107
105
108
106
val localImportsPatch =
109
107
if (! config.removeUnused || localImports.isEmpty) Patch .empty
110
- else removeUnused (localImports)
108
+ else removeUnusedImports(unusedImporteePositions) (localImports)
111
109
112
110
diagnostics.map(Patch .lint).asPatch + globalImportsPatch + localImportsPatch
113
111
}
114
112
115
- private def isUnused (importee : Importee ): Boolean =
116
- unusedImporteePositions contains positionOf(importee)
117
-
118
113
private def organizeGlobalImports (
114
+ unusedImporteePositions : UnusedImporteePositions ,
115
+ diagnostics : ArrayBuffer [Diagnostic ]
116
+ )(
119
117
imports : Seq [Import ]
120
118
)(implicit doc : SemanticDocument ): Patch = {
121
- val noUnused = imports flatMap (_.importers) flatMap (removeUnused(_).toSeq)
119
+ val noUnused = imports flatMap (_.importers) flatMap (
120
+ removeUnusedImporters(unusedImporteePositions)(_).toSeq
121
+ )
122
122
123
123
val (implicits, noImplicits) =
124
124
if (! config.groupExplicitlyImportedImplicitsSeparately) (Nil , noUnused)
125
125
else partitionImplicits(noUnused)
126
126
127
127
val (fullyQualifiedImporters, relativeImporters) =
128
- noImplicits partition isFullyQualified
128
+ noImplicits partition isFullyQualified(diagnostics)
129
129
130
130
// Organizes all the fully-qualified global importers.
131
131
val fullyQualifiedGroups : Seq [ImportGroup ] = {
132
132
val expanded =
133
133
if (config.expandRelative) relativeImporters map expandRelative else Nil
134
- groupImporters(fullyQualifiedImporters ++ expanded)
134
+ groupImporters(diagnostics)( fullyQualifiedImporters ++ expanded)
135
135
}
136
136
137
137
// Moves relative imports (when `config.expandRelative` is false) and
@@ -165,39 +165,49 @@ class OrganizeImports(
165
165
(insertionPatch + removalPatch).atomic
166
166
}
167
167
168
- private def removeUnused (imports : Seq [Import ]): Patch =
168
+ private def removeUnusedImports (
169
+ unusedImporteePositions : UnusedImporteePositions
170
+ )(
171
+ imports : Seq [Import ]
172
+ ): Patch =
169
173
Patch .fromIterable {
170
174
imports flatMap (_.importers) flatMap { case Importer (_, importees) =>
171
175
val hasUsedWildcard = importees exists { i =>
172
- i.is[Importee .Wildcard ] && ! isUnused (i)
176
+ i.is[Importee .Wildcard ] && ! unusedImporteePositions (i)
173
177
}
174
178
175
179
importees collect {
176
- case i @ Importee .Rename (_, to) if isUnused(i) && hasUsedWildcard =>
180
+ case i @ Importee .Rename (_, to)
181
+ if unusedImporteePositions(i) && hasUsedWildcard =>
177
182
// Unimport the identifier instead of removing the importee since
178
183
// unused renamed may still impact compilation by shadowing an
179
184
// identifier.
180
185
//
181
186
// See https://github.com/scalacenter/scalafix/issues/614
182
187
Patch .replaceTree(to, " _" ).atomic
183
188
184
- case i if isUnused (i) =>
189
+ case i if unusedImporteePositions (i) =>
185
190
Patch .removeImportee(i).atomic
186
191
}
187
192
}
188
193
}
189
194
190
- private def removeUnused (importer : Importer ): Option [Importer ] =
195
+ private def removeUnusedImporters (
196
+ unusedImporteePositions : UnusedImporteePositions
197
+ )(
198
+ importer : Importer
199
+ ): Option [Importer ] =
191
200
if (! config.removeUnused) Some (importer)
192
201
else {
193
202
val hasUsedWildcard = importer.importees exists { i =>
194
- i.is[Importee .Wildcard ] && ! isUnused (i)
203
+ i.is[Importee .Wildcard ] && ! unusedImporteePositions (i)
195
204
}
196
205
197
206
var rewritten = false
198
207
199
208
val noUnused = importer.importees.flatMap {
200
- case i @ Importee .Rename (from, _) if isUnused(i) && hasUsedWildcard =>
209
+ case i @ Importee .Rename (from, _)
210
+ if unusedImporteePositions(i) && hasUsedWildcard =>
201
211
// Unimport the identifier instead of removing the importee since
202
212
// unused renamed may still impact compilation by shadowing an
203
213
// identifier.
@@ -206,7 +216,7 @@ class OrganizeImports(
206
216
rewritten = true
207
217
Importee .Unimport (from) :: Nil
208
218
209
- case i if isUnused (i) =>
219
+ case i if unusedImporteePositions (i) =>
210
220
rewritten = true
211
221
Nil
212
222
@@ -240,6 +250,8 @@ class OrganizeImports(
240
250
}
241
251
242
252
private def isFullyQualified (
253
+ diagnostics : ArrayBuffer [Diagnostic ]
254
+ )(
243
255
importer : Importer
244
256
)(implicit doc : SemanticDocument ): Boolean = {
245
257
val topQualifier = topQualifierOf(importer.ref)
@@ -312,10 +324,16 @@ class OrganizeImports(
312
324
)
313
325
}
314
326
315
- private def groupImporters (importers : Seq [Importer ]): Seq [ImportGroup ] =
327
+ private def groupImporters (
328
+ diagnostics : ArrayBuffer [Diagnostic ]
329
+ )(
330
+ importers : Seq [Importer ]
331
+ ): Seq [ImportGroup ] =
316
332
importers
317
333
.groupBy(matchImportGroup) // Groups imports by importer prefix.
318
- .mapValues(deduplicateImportees _ andThen organizeImportGroup)
334
+ .mapValues(
335
+ deduplicateImportees _ andThen organizeImportGroup(diagnostics)
336
+ )
319
337
.map { case (index, imports) => ImportGroup (index, imports) }
320
338
.toSeq
321
339
.sortBy(_.index)
@@ -333,13 +351,17 @@ class OrganizeImports(
333
351
}
334
352
}
335
353
336
- private def organizeImportGroup (importers : Seq [Importer ]): Seq [Importer ] = {
354
+ private def organizeImportGroup (
355
+ diagnostics : ArrayBuffer [Diagnostic ]
356
+ )(
357
+ importers : Seq [Importer ]
358
+ ): Seq [Importer ] = {
337
359
val importeesSorted = locally {
338
360
config.groupedImports match {
339
361
case GroupedImports .Merge =>
340
- mergeImporters(importers, aggressive = false )
362
+ mergeImporters(diagnostics)( importers, aggressive = false )
341
363
case GroupedImports .AggressiveMerge =>
342
- mergeImporters(importers, aggressive = true )
364
+ mergeImporters(diagnostics)( importers, aggressive = true )
343
365
case GroupedImports .Explode =>
344
366
explodeImportees(importers)
345
367
case GroupedImports .Keep =>
@@ -363,6 +385,8 @@ class OrganizeImports(
363
385
}
364
386
365
387
private def mergeImporters (
388
+ diagnostics : ArrayBuffer [Diagnostic ]
389
+ )(
366
390
importers : Seq [Importer ],
367
391
aggressive : Boolean
368
392
): Seq [Importer ] =
@@ -1078,6 +1102,17 @@ object OrganizeImports {
1078
1102
}
1079
1103
}
1080
1104
1105
+ class UnusedImporteePositions (implicit doc : SemanticDocument ) {
1106
+ private val positions : Seq [Position ] =
1107
+ doc.diagnostics.toSeq.collect {
1108
+ case d if d.message == " Unused import" => d.position
1109
+ }
1110
+
1111
+ /** Returns true if the importee was marked as unused by the compiler */
1112
+ def apply (importee : Importee ): Boolean =
1113
+ positions contains positionOf(importee)
1114
+ }
1115
+
1081
1116
implicit private class SymbolExtension (symbol : Symbol ) {
1082
1117
1083
1118
/**
0 commit comments