Skip to content

Commit 6eee581

Browse files
tanishikingbjaglin
authored andcommitted
Support OrganizeImports.removeUnused in Scala 3
Once this PR scala/scala3#17835 has merged and released, scalafix-organize-imports should be able to run OrganizeImports.removeUnused based on the diagnostics information in SemanticDB emit from Scala3 compiler. In order to make OrganizeImports rule to work with Scala 3, this commit added a few adjustments to the rule.
1 parent a87a188 commit 6eee581

File tree

7 files changed

+31
-24
lines changed

7 files changed

+31
-24
lines changed

docs/rules/OrganizeImports.md

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,11 @@ do not rewrite import statements in ways that conflict with
5252

5353
Known limitations:
5454

55-
1. The [`removeUnused`](OrganizeImports.md#removeunused) option must be
56-
explicitly set to `false` - the rule currently doesn’t remove unused
57-
imports as it is currently not supported by the compiler.
58-
59-
2. Usage of [deprecated package
55+
1. Usage of [deprecated package
6056
objects](http://dotty.epfl.ch/docs/reference/dropped-features/package-objects.html)
6157
may result in incorrect imports.
6258

63-
3. The
59+
2. The
6460
[`groupExplicitlyImportedImplicitsSeparately`](OrganizeImports.md#groupexplicitlyimportedimplicitsseparately)
6561
option has no effect.
6662

@@ -1279,12 +1275,9 @@ Remove unused imports.
12791275
> using Scala compilation diagnostics information, and the compilation phase
12801276
> happens before Scalafix rules get applied.
12811277
1282-
> The `removeUnused` option is currently not supported for source files
1283-
> compiled with Scala 3, as the [compiler cannot issue warnings for unused
1284-
> imports
1285-
> yet](https://docs.scala-lang.org/scala3/guides/migration/options-lookup.html#warning-settings).
1286-
> As a result, you must set `removeUnused` to `false` when running the
1287-
> rule on source files compiled with Scala 3.
1278+
> The `removeUnused` option is not supported for source files compiled with
1279+
> early versions of Scala 3 as these do not export SemanticDB diagnostics for
1280+
> unused imports. You must compile with Scala 3.4.0 or later to use it.
12881281
12891282
### Value type
12901283

@@ -1299,7 +1292,7 @@ Boolean
12991292
```conf
13001293
OrganizeImports {
13011294
groups = ["javax?\\.", "scala.", "*"]
1302-
removeUnused = true // not supported in Scala 3
1295+
removeUnused = true
13031296
}
13041297
```
13051298

scalafix-rules/src/main/scala/scalafix/internal/rule/OrganizeImports.scala

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,9 @@ object OrganizeImports {
863863
scalacOptions: List[String],
864864
scalaVersion: String
865865
): Configured[Rule] = {
866-
val hasCompilerSupport = scalaVersion.startsWith("2")
866+
val hasCompilerSupport =
867+
Seq("3.0", "3.1", "3.2", "3.3")
868+
.forall(v => !scalaVersion.startsWith(v))
867869

868870
val hasWarnUnused = hasCompilerSupport && {
869871
val warnUnusedPrefix = Set("-Wunused", "-Ywarn-unused")
@@ -911,17 +913,17 @@ object OrganizeImports {
911913
)
912914
else if (hasCompilerSupport)
913915
Configured.error(
914-
"The Scala compiler option \"-Ywarn-unused\" is required to use OrganizeImports with"
916+
"A Scala compiler option is required to use OrganizeImports with"
915917
+ " \"OrganizeImports.removeUnused\" set to true. To fix this problem, update your"
916-
+ " build to use at least one Scala compiler option like -Ywarn-unused-import (2.11"
917-
+ " only), -Ywarn-unused, -Xlint:unused (2.12.2 or above) or -Wunused (2.13 only)."
918+
+ " build to add `-Ywarn-unused` (2.12), `-Wunused:imports` (2.13), or"
919+
+ " `-Wunused:import` (3.4+)."
918920
)
919921
else
920922
Configured.error(
921-
"\"OrganizeImports.removeUnused\" is not supported on Scala 3 as the compiler is"
922-
+ " not providing enough information. Run the rule with"
923-
+ " \"OrganizeImports.removeUnused\" set to false to organize imports while keeping"
924-
+ " potentially unused imports."
923+
"\"OrganizeImports.removeUnused\"" + s"is not supported on $scalaVersion as the compiler is"
924+
+ " not providing enough information. Please upgrade the Scala compiler to 3.4.0 or greater."
925+
+ " Otherwise, run the rule with \"OrganizeImports.removeUnused\" set to false"
926+
+ " to organize imports while keeping potentially unused imports."
925927
)
926928
}
927929

@@ -1105,12 +1107,24 @@ object OrganizeImports {
11051107
class UnusedImporteePositions(implicit doc: SemanticDocument) {
11061108
private val positions: Seq[Position] =
11071109
doc.diagnostics.toSeq.collect {
1108-
case d if d.message == "Unused import" => d.position
1110+
// Scala2 says "Unused import" while Scala3 says "unused import"
1111+
case d if d.message.toLowerCase == "unused import" => d.position
11091112
}
11101113

11111114
/** Returns true if the importee was marked as unused by the compiler */
1112-
def apply(importee: Importee): Boolean =
1113-
positions contains positionOf(importee)
1115+
def apply(importee: Importee): Boolean = {
1116+
// positionOf returns the position of `bar` for `import foo.{bar => baz}`
1117+
// this position matches with the diagnostics from Scala2, but Scala3
1118+
// diagnostics has a position for `bar => baz`, which doesn't match
1119+
// with the return value of `positionOf`.
1120+
// We could adjust the behavior of `positionOf` based on Scala version,
1121+
// but this implementation just checking the unusedImporteePosition
1122+
// includes the importee pos, for simplicity.
1123+
val pos = positionOf(importee)
1124+
positions.exists { unused =>
1125+
unused.start <= pos.start && pos.end <= unused.end
1126+
}
1127+
}
11141128
}
11151129

11161130
implicit private class SymbolExtension(symbol: Symbol) {

0 commit comments

Comments
 (0)