@@ -3,6 +3,8 @@ package scalafix.internal.rule
3
3
import scala .annotation .tailrec
4
4
import scala .collection .mutable
5
5
import scala .collection .mutable .ArrayBuffer
6
+ import scala .util .Failure
7
+ import scala .util .Success
6
8
import scala .util .Try
7
9
8
10
import scala .meta .Import
@@ -28,6 +30,7 @@ import metaconfig.ConfEncoder
28
30
import metaconfig .ConfOps
29
31
import metaconfig .Configured
30
32
import metaconfig .internal .ConfGet
33
+ import scalafix .internal .config .ScalaVersion
31
34
import scalafix .internal .rule .ImportMatcher .*
32
35
import scalafix .internal .rule .ImportMatcher .---
33
36
import scalafix .internal .rule .ImportMatcher .parse
@@ -72,7 +75,8 @@ class OrganizeImports(config: OrganizeImportsConfig)
72
75
73
76
override def fix (implicit doc : SemanticDocument ): Patch = {
74
77
unusedImporteePositions ++= doc.diagnostics.collect {
75
- case d if d.message == " Unused import" => d.position
78
+ // Scala2 says "Unused import" while Scala3 says "unused import"
79
+ case d if d.message.toLowerCase == " unused import" => d.position
76
80
}
77
81
78
82
val (globalImports, localImports) = collectImports(doc.tree)
@@ -88,8 +92,16 @@ class OrganizeImports(config: OrganizeImportsConfig)
88
92
diagnostics.map(Patch .lint).asPatch + globalImportsPatch + localImportsPatch
89
93
}
90
94
91
- private def isUnused (importee : Importee ): Boolean =
92
- unusedImporteePositions contains positionOf(importee)
95
+ private def isUnused (importee : Importee ): Boolean = {
96
+ // positionOf returns the position of `bar` for `import foo.{bar => baz}`
97
+ // this position matches with the diagnostics from Scala2,
98
+ // but Scala3 diagnostics has a position for `bar => baz`, which doesn't match with
99
+ // the return value of `positionOf`.
100
+ // We could adjust the behavior of `positionOf` based on Scala version,
101
+ // but this implementation just checking the unusedImporteePosition includes the importee pos, for simplicity.
102
+ val pos = positionOf(importee)
103
+ unusedImporteePositions.exists(unused => unused.start <= pos.start && pos.end <= unused.end)
104
+ }
93
105
94
106
private def organizeGlobalImports (
95
107
imports : Seq [Import ]
@@ -707,32 +719,40 @@ object OrganizeImports {
707
719
scalacOptions : List [String ],
708
720
scalaVersion : String
709
721
): Configured [Rule ] = {
710
- val hasCompilerSupport = scalaVersion.startsWith(" 2" )
711
-
712
- val hasWarnUnused = hasCompilerSupport && {
713
- val warnUnusedPrefix = Set (" -Wunused" , " -Ywarn-unused" )
714
- val warnUnusedString = Set (" -Xlint" , " -Xlint:unused" )
715
- scalacOptions exists { option =>
716
- (warnUnusedPrefix exists option.startsWith) || (warnUnusedString contains option)
717
- }
718
- }
722
+ ScalaVersion .from(scalaVersion).map { v =>
723
+ v.isScala2 || (
724
+ v.isScala3 &&
725
+ v.minor.getOrElse(0 ) >= 3 &&
726
+ v.patch.getOrElse(0 ) >= 1
727
+ )
728
+ } match {
729
+ case Failure (exception) => Configured .error(exception.getMessage())
730
+ case Success (hasCompilerSupport) =>
731
+ val hasWarnUnused = hasCompilerSupport && {
732
+ val warnUnusedPrefix = Set (" -Wunused" , " -Ywarn-unused" )
733
+ val warnUnusedString = Set (" -Xlint" , " -Xlint:unused" )
734
+ scalacOptions exists { option =>
735
+ (warnUnusedPrefix exists option.startsWith) || (warnUnusedString contains option)
736
+ }
737
+ }
719
738
720
- if (! conf.removeUnused || hasWarnUnused)
721
- Configured .ok(new OrganizeImports (conf))
722
- else if (hasCompilerSupport)
723
- Configured .error(
724
- " The Scala compiler option \" -Ywarn-unused\" is required to use OrganizeImports with"
725
- + " \" OrganizeImports.removeUnused\" set to true. To fix this problem, update your"
726
- + " build to use at least one Scala compiler option like -Ywarn-unused-import (2.11"
727
- + " only), -Ywarn-unused, -Xlint:unused (2.12.2 or above) or -Wunused (2.13 only)."
728
- )
729
- else
730
- Configured .error(
731
- " \" OrganizeImports.removeUnused\" is not supported on Scala 3 as the compiler is"
732
- + " not providing enough information. Run the rule with"
733
- + " \" OrganizeImports.removeUnused\" set to false to organize imports while keeping"
734
- + " potentially unused imports."
735
- )
739
+ if (! conf.removeUnused || hasWarnUnused)
740
+ Configured .ok(new OrganizeImports (conf))
741
+ else if (hasCompilerSupport)
742
+ Configured .error(
743
+ " The Scala compiler option \" -Ywarn-unused\" is required to use OrganizeImports with"
744
+ + " \" OrganizeImports.removeUnused\" set to true. To fix this problem, update your"
745
+ + " build to use at least one Scala compiler option like -Ywarn-unused-import (2.11"
746
+ + " only), -Ywarn-unused, -Xlint:unused (2.12.2 or above) or -Wunused (2.13 only)."
747
+ )
748
+ else
749
+ Configured .error(
750
+ " \" OrganizeImports.removeUnused\" " + s " is not supported on $scalaVersion as the compiler is "
751
+ + " not providing enough information. Please upgrade Scala 3 version to 3.3.1 or greater."
752
+ + " Otherwise, run the rule with \" OrganizeImports.removeUnused\" set to false"
753
+ + " to organize imports while keeping potentially unused imports."
754
+ )
755
+ }
736
756
}
737
757
738
758
private def buildImportMatchers (
0 commit comments