From 0d96c1e0441009f43a8844d361a38d9cd712a061 Mon Sep 17 00:00:00 2001 From: subhramit Date: Wed, 18 Jun 2025 04:28:57 +0530 Subject: [PATCH 01/13] Build solution - without scope awareness Signed-off-by: subhramit --- .../internal/patch/ReplaceSymbolOps.scala | 49 ++++++++++++++++++- .../src/main/scala/test/ReplaceSymbol.scala | 4 ++ .../main/scala/com/geirsson/immutable.scala | 11 +++++ .../src/main/scala/test/ReplaceSymbol.scala | 7 +-- 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 scalafix-tests/output/src/main/scala/com/geirsson/immutable.scala diff --git a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala index 052dbaf50..1cf4552b5 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala @@ -10,8 +10,15 @@ import scalafix.patch.Patch import scalafix.patch.Patch.internal.ReplaceSymbol import scalafix.syntax._ import scalafix.v0._ +import scala.annotation.tailrec object ReplaceSymbolOps { + private case class ImportInfo( + globalImports: Seq[Import], + allImports: Seq[Import] = Seq.empty, + importedSymbols: Map[String, Symbol] = Map.empty + ) + private object Select { def unapply(arg: Ref): Option[(Ref, Name)] = arg match { case Term.Select(a: Ref, b) => Some(a -> b) @@ -20,10 +27,44 @@ object ReplaceSymbolOps { } } + private def extractImports(stats: Seq[Stat]): Seq[Import] = { + stats.collect { case i: Import => i } + } + + private def getGranularImports(tree: Tree): ImportInfo = { + @tailrec + def getTopLevelImports(ast: Tree): Seq[Import] = ast match { + case Pkg(_, Seq(pkg: Pkg)) => getTopLevelImports(pkg) + case Source(Seq(pkg: Pkg)) => getTopLevelImports(pkg) + case Pkg(_, stats) => extractImports(stats) + case Source(stats) => extractImports(stats) + case _ => Nil + } + + val globalImports = getTopLevelImports(tree) + // collect all imports throughout entire tree (scoped + global) + val allImports = tree.collect { case i: Import => i } + + // pre-compute imported symbols for O(1) collision detection + val importedSymbols = allImports.flatMap { importStat => + importStat.importers.flatMap { importer => + importer.importees.collect { + case Importee.Name(name) => name.value -> name.symbol.getOrElse(Symbol.None) + case Importee.Rename(_, rename) => rename.value -> rename.symbol.getOrElse(Symbol.None) + } + } + }.toMap + + ImportInfo(globalImports, allImports, importedSymbols) + } + def naiveMoveSymbolPatch( moveSymbols: Seq[ReplaceSymbol] )(implicit ctx: RuleCtx, index: SemanticdbIndex): Patch = { if (moveSymbols.isEmpty) return Patch.empty + + val importInfo = getGranularImports(ctx.tree) + val moves: Map[String, Symbol.Global] = moveSymbols.iterator.flatMap { case ReplaceSymbol( @@ -126,10 +167,14 @@ object ReplaceSymbolOps { if sig.name != parent.value => Patch.empty // do nothing because it was a renamed symbol case Some(_) => + val causesCollision = importInfo.importedSymbols.contains(to.signature.name) val addImport = - if (n.isDefinition) Patch.empty + if (n.isDefinition || causesCollision) Patch.empty else ctx.addGlobalImport(to) - addImport + ctx.replaceTree(n, to.signature.name) + if (causesCollision) + addImport + ctx.replaceTree(n, to.owner.syntax + to.signature.name) + else + addImport + ctx.replaceTree(n, to.signature.name) case _ => Patch.empty } diff --git a/scalafix-tests/input/src/main/scala/test/ReplaceSymbol.scala b/scalafix-tests/input/src/main/scala/test/ReplaceSymbol.scala index 5281f1dca..b76db14fa 100644 --- a/scalafix-tests/input/src/main/scala/test/ReplaceSymbol.scala +++ b/scalafix-tests/input/src/main/scala/test/ReplaceSymbol.scala @@ -12,6 +12,8 @@ patches.replaceSymbols = [ to = "com.geirsson.mutable.CoolBuffer" } { from = "scala.collection.mutable.HashMap" to = "com.geirsson.mutable.unsafe.CoolMap" } + { from = "scala.collection.immutable.TreeMap" + to = "com.geirsson.immutable.SortedMap" } { from = "scala.math.sqrt" to = "com.geirsson.fastmath.sqrt" } // normalized symbol renames all overloaded methods @@ -29,6 +31,7 @@ patches.replaceSymbols = [ */ package fix +import scala.collection.immutable.{SortedMap, TreeMap} import scala.collection.mutable.HashMap import scala.collection.mutable.ListBuffer import scala.collection.mutable @@ -42,6 +45,7 @@ object ReplaceSymbol { "blah".substring(1) "blah".substring(1, 2) val u: mutable.HashMap[Int, Int] = HashMap.empty[Int, Int] + val v: SortedMap[Int, Int] = TreeMap.empty[Int, Int] val x: ListBuffer[Int] = ListBuffer.empty[Int] val y: mutable.ListBuffer[Int] = mutable.ListBuffer.empty[Int] val z: scala.collection.mutable.ListBuffer[Int] = diff --git a/scalafix-tests/output/src/main/scala/com/geirsson/immutable.scala b/scalafix-tests/output/src/main/scala/com/geirsson/immutable.scala new file mode 100644 index 000000000..0e1ad286f --- /dev/null +++ b/scalafix-tests/output/src/main/scala/com/geirsson/immutable.scala @@ -0,0 +1,11 @@ +package com.geirsson + +import scala.collection.immutable.TreeMap + +object immutable { + type SortedMap[A, B] = TreeMap[A, B] + + object SortedMap { + def empty[A : Ordering, B]: SortedMap[A, B] = TreeMap.empty[A, B] + } +} diff --git a/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala b/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala index 55fc14b58..6929ae177 100644 --- a/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala +++ b/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala @@ -1,10 +1,10 @@ package fix - import com.geirsson.Future -import com.geirsson.{ fastmath, mutable } -import com.geirsson.mutable.{ CoolBuffer, unsafe } +import com.geirsson.{fastmath, mutable} +import com.geirsson.mutable.{CoolBuffer, unsafe} import com.geirsson.mutable.unsafe.CoolMap +import scala.collection.immutable.SortedMap object ReplaceSymbol { Future.successful(1 + 2) fastmath.sqrt(9) @@ -13,6 +13,7 @@ object ReplaceSymbol { "blah".substringFrom(1) "blah".substringBetween(1, 2) val u: unsafe.CoolMap[Int, Int] = CoolMap.empty[Int, Int] + val v: SortedMap[Int, Int] = com.geirsson.immutable.SortedMap.empty[Int, Int] val x: CoolBuffer[Int] = CoolBuffer.empty[Int] val y: mutable.CoolBuffer[Int] = mutable.CoolBuffer.empty[Int] val z: com.geirsson.mutable.CoolBuffer[Int] = From d960708c7b3f096bbee66d8ce30132af68bfc099 Mon Sep 17 00:00:00 2001 From: subhramit Date: Wed, 18 Jun 2025 04:50:33 +0530 Subject: [PATCH 02/13] Add implicit `SemanticDocument` Signed-off-by: subhramit --- .../main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala index 1cf4552b5..09cf02809 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala @@ -31,7 +31,7 @@ object ReplaceSymbolOps { stats.collect { case i: Import => i } } - private def getGranularImports(tree: Tree): ImportInfo = { + private def getGranularImports(tree: Tree)(implicit doc: SemanticDocument): ImportInfo = { @tailrec def getTopLevelImports(ast: Tree): Seq[Import] = ast match { case Pkg(_, Seq(pkg: Pkg)) => getTopLevelImports(pkg) @@ -63,7 +63,7 @@ object ReplaceSymbolOps { )(implicit ctx: RuleCtx, index: SemanticdbIndex): Patch = { if (moveSymbols.isEmpty) return Patch.empty - val importInfo = getGranularImports(ctx.tree) + val importInfo = getGranularImports(ctx.tree)(ctx.doc) val moves: Map[String, Symbol.Global] = moveSymbols.iterator.flatMap { From 125fbc56024300b9cf526110fbe71e255222125f Mon Sep 17 00:00:00 2001 From: subhramit Date: Wed, 18 Jun 2025 04:56:29 +0530 Subject: [PATCH 03/13] Use `SemanticdbIndex` instead Signed-off-by: subhramit --- .../scalafix/internal/patch/ReplaceSymbolOps.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala index 09cf02809..11f9c2b00 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala @@ -30,8 +30,8 @@ object ReplaceSymbolOps { private def extractImports(stats: Seq[Stat]): Seq[Import] = { stats.collect { case i: Import => i } } - - private def getGranularImports(tree: Tree)(implicit doc: SemanticDocument): ImportInfo = { + + private def getGranularImports(tree: Tree)(implicit index: SemanticdbIndex): ImportInfo = { @tailrec def getTopLevelImports(ast: Tree): Seq[Import] = ast match { case Pkg(_, Seq(pkg: Pkg)) => getTopLevelImports(pkg) @@ -62,8 +62,8 @@ object ReplaceSymbolOps { moveSymbols: Seq[ReplaceSymbol] )(implicit ctx: RuleCtx, index: SemanticdbIndex): Patch = { if (moveSymbols.isEmpty) return Patch.empty - - val importInfo = getGranularImports(ctx.tree)(ctx.doc) + + val importInfo = getGranularImports(ctx.tree)(index) val moves: Map[String, Symbol.Global] = moveSymbols.iterator.flatMap { @@ -172,7 +172,7 @@ object ReplaceSymbolOps { if (n.isDefinition || causesCollision) Patch.empty else ctx.addGlobalImport(to) if (causesCollision) - addImport + ctx.replaceTree(n, to.owner.syntax + to.signature.name) + addImport + ctx.replaceTree(n, s"${to.owner.syntax}.${to.signature.name}") else addImport + ctx.replaceTree(n, to.signature.name) case _ => From a8e39db5d53ff8524119f38e8a48b869cb6a3db5 Mon Sep 17 00:00:00 2001 From: subhramit Date: Wed, 18 Jun 2025 04:59:06 +0530 Subject: [PATCH 04/13] Better name for method Signed-off-by: subhramit --- .../main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala index 11f9c2b00..696d9688c 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala @@ -31,7 +31,7 @@ object ReplaceSymbolOps { stats.collect { case i: Import => i } } - private def getGranularImports(tree: Tree)(implicit index: SemanticdbIndex): ImportInfo = { + private def extractImportInfo(tree: Tree)(implicit index: SemanticdbIndex): ImportInfo = { @tailrec def getTopLevelImports(ast: Tree): Seq[Import] = ast match { case Pkg(_, Seq(pkg: Pkg)) => getTopLevelImports(pkg) @@ -63,7 +63,7 @@ object ReplaceSymbolOps { )(implicit ctx: RuleCtx, index: SemanticdbIndex): Patch = { if (moveSymbols.isEmpty) return Patch.empty - val importInfo = getGranularImports(ctx.tree)(index) + val importInfo = extractImportInfo(ctx.tree)(index) val moves: Map[String, Symbol.Global] = moveSymbols.iterator.flatMap { From 2de7be16329ac1c3853b6cacf78d46fe42617805 Mon Sep 17 00:00:00 2001 From: subhramit Date: Wed, 18 Jun 2025 05:01:53 +0530 Subject: [PATCH 05/13] Simpler concat Signed-off-by: subhramit --- .../scala/scalafix/internal/patch/ReplaceSymbolOps.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala index 696d9688c..6617d1118 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala @@ -30,7 +30,7 @@ object ReplaceSymbolOps { private def extractImports(stats: Seq[Stat]): Seq[Import] = { stats.collect { case i: Import => i } } - + private def extractImportInfo(tree: Tree)(implicit index: SemanticdbIndex): ImportInfo = { @tailrec def getTopLevelImports(ast: Tree): Seq[Import] = ast match { @@ -62,7 +62,7 @@ object ReplaceSymbolOps { moveSymbols: Seq[ReplaceSymbol] )(implicit ctx: RuleCtx, index: SemanticdbIndex): Patch = { if (moveSymbols.isEmpty) return Patch.empty - + val importInfo = extractImportInfo(ctx.tree)(index) val moves: Map[String, Symbol.Global] = @@ -172,7 +172,7 @@ object ReplaceSymbolOps { if (n.isDefinition || causesCollision) Patch.empty else ctx.addGlobalImport(to) if (causesCollision) - addImport + ctx.replaceTree(n, s"${to.owner.syntax}.${to.signature.name}") + addImport + ctx.replaceTree(n, to.owner.syntax + to.signature.name) else addImport + ctx.replaceTree(n, to.signature.name) case _ => From 12569bbf669bbb445081259cdedacd2f03978170 Mon Sep 17 00:00:00 2001 From: subhramit Date: Wed, 18 Jun 2025 05:06:12 +0530 Subject: [PATCH 06/13] Revert IDE formatting Signed-off-by: subhramit --- scalafix-tests/input/src/main/scala/test/ReplaceSymbol.scala | 2 +- scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scalafix-tests/input/src/main/scala/test/ReplaceSymbol.scala b/scalafix-tests/input/src/main/scala/test/ReplaceSymbol.scala index b76db14fa..a74f7322b 100644 --- a/scalafix-tests/input/src/main/scala/test/ReplaceSymbol.scala +++ b/scalafix-tests/input/src/main/scala/test/ReplaceSymbol.scala @@ -31,7 +31,7 @@ patches.replaceSymbols = [ */ package fix -import scala.collection.immutable.{SortedMap, TreeMap} +import scala.collection.immutable.{ SortedMap, TreeMap } import scala.collection.mutable.HashMap import scala.collection.mutable.ListBuffer import scala.collection.mutable diff --git a/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala b/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala index 6929ae177..2a072a004 100644 --- a/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala +++ b/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala @@ -1,7 +1,7 @@ package fix import com.geirsson.Future -import com.geirsson.{fastmath, mutable} -import com.geirsson.mutable.{CoolBuffer, unsafe} +import com.geirsson.{ fastmath, mutable } +import com.geirsson.mutable.{ CoolBuffer, unsafe } import com.geirsson.mutable.unsafe.CoolMap import scala.collection.immutable.SortedMap From 100b6d4cf7eb7a62a2a0cb397bb9cd0176123388 Mon Sep 17 00:00:00 2001 From: subhramit Date: Wed, 18 Jun 2025 05:07:08 +0530 Subject: [PATCH 07/13] Revert IDE formatting Signed-off-by: subhramit --- scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala b/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala index 2a072a004..d5c4a1397 100644 --- a/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala +++ b/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala @@ -1,4 +1,5 @@ package fix + import com.geirsson.Future import com.geirsson.{ fastmath, mutable } import com.geirsson.mutable.{ CoolBuffer, unsafe } From 26b2f88f4babdc8339cdf3a44d20a1c617f2960e Mon Sep 17 00:00:00 2001 From: Subhramit Basu Date: Wed, 18 Jun 2025 00:05:57 +0000 Subject: [PATCH 08/13] scalafmt --- .../internal/patch/ReplaceSymbolOps.scala | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala index 6617d1118..572ce82c9 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala @@ -14,10 +14,10 @@ import scala.annotation.tailrec object ReplaceSymbolOps { private case class ImportInfo( - globalImports: Seq[Import], - allImports: Seq[Import] = Seq.empty, - importedSymbols: Map[String, Symbol] = Map.empty - ) + globalImports: Seq[Import], + allImports: Seq[Import] = Seq.empty, + importedSymbols: Map[String, Symbol] = Map.empty + ) private object Select { def unapply(arg: Ref): Option[(Ref, Name)] = arg match { @@ -31,7 +31,9 @@ object ReplaceSymbolOps { stats.collect { case i: Import => i } } - private def extractImportInfo(tree: Tree)(implicit index: SemanticdbIndex): ImportInfo = { + private def extractImportInfo( + tree: Tree + )(implicit index: SemanticdbIndex): ImportInfo = { @tailrec def getTopLevelImports(ast: Tree): Seq[Import] = ast match { case Pkg(_, Seq(pkg: Pkg)) => getTopLevelImports(pkg) @@ -49,8 +51,10 @@ object ReplaceSymbolOps { val importedSymbols = allImports.flatMap { importStat => importStat.importers.flatMap { importer => importer.importees.collect { - case Importee.Name(name) => name.value -> name.symbol.getOrElse(Symbol.None) - case Importee.Rename(_, rename) => rename.value -> rename.symbol.getOrElse(Symbol.None) + case Importee.Name(name) => + name.value -> name.symbol.getOrElse(Symbol.None) + case Importee.Rename(_, rename) => + rename.value -> rename.symbol.getOrElse(Symbol.None) } } }.toMap @@ -167,7 +171,8 @@ object ReplaceSymbolOps { if sig.name != parent.value => Patch.empty // do nothing because it was a renamed symbol case Some(_) => - val causesCollision = importInfo.importedSymbols.contains(to.signature.name) + val causesCollision = + importInfo.importedSymbols.contains(to.signature.name) val addImport = if (n.isDefinition || causesCollision) Patch.empty else ctx.addGlobalImport(to) From e0aefe8bd3c8bee3352d2d5cbb956f82536dce98 Mon Sep 17 00:00:00 2001 From: subhramit Date: Wed, 18 Jun 2025 05:51:51 +0530 Subject: [PATCH 09/13] Fix test Signed-off-by: subhramit --- scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala b/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala index d5c4a1397..24f745d68 100644 --- a/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala +++ b/scalafix-tests/output/src/main/scala/test/ReplaceSymbol.scala @@ -1,11 +1,11 @@ package fix +import scala.collection.immutable.SortedMap import com.geirsson.Future import com.geirsson.{ fastmath, mutable } import com.geirsson.mutable.{ CoolBuffer, unsafe } import com.geirsson.mutable.unsafe.CoolMap -import scala.collection.immutable.SortedMap object ReplaceSymbol { Future.successful(1 + 2) fastmath.sqrt(9) From 97dd899c3633a5bcc6b17ddc97cb947cedcedd33 Mon Sep 17 00:00:00 2001 From: Subhramit Basu Date: Wed, 18 Jun 2025 00:46:09 +0000 Subject: [PATCH 10/13] scalafixall --- .../main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala index 572ce82c9..2618d3670 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala @@ -1,5 +1,7 @@ package scalafix.internal.patch +import scala.annotation.tailrec + import scala.meta._ import scala.meta.internal.trees._ @@ -10,7 +12,6 @@ import scalafix.patch.Patch import scalafix.patch.Patch.internal.ReplaceSymbol import scalafix.syntax._ import scalafix.v0._ -import scala.annotation.tailrec object ReplaceSymbolOps { private case class ImportInfo( From aac4d5d036d87f46444fd6f0a2a80ae957696b29 Mon Sep 17 00:00:00 2001 From: Subhramit Basu Date: Wed, 18 Jun 2025 01:13:27 +0000 Subject: [PATCH 11/13] Fix scope issue --- .../scalafix/internal/patch/ReplaceSymbolOps.scala | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala index 2618d3670..3d821b76a 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala @@ -16,8 +16,7 @@ import scalafix.v0._ object ReplaceSymbolOps { private case class ImportInfo( globalImports: Seq[Import], - allImports: Seq[Import] = Seq.empty, - importedSymbols: Map[String, Symbol] = Map.empty + globalImportedSymbols: Map[String, Symbol] = Map.empty ) private object Select { @@ -45,11 +44,10 @@ object ReplaceSymbolOps { } val globalImports = getTopLevelImports(tree) - // collect all imports throughout entire tree (scoped + global) - val allImports = tree.collect { case i: Import => i } - // pre-compute imported symbols for O(1) collision detection - val importedSymbols = allImports.flatMap { importStat => + // pre-compute global imported symbols for O(1) collision detection + // since ctx.addGlobalImport adds imports at global scope + val globalImportedSymbols = globalImports.flatMap { importStat => importStat.importers.flatMap { importer => importer.importees.collect { case Importee.Name(name) => @@ -60,7 +58,7 @@ object ReplaceSymbolOps { } }.toMap - ImportInfo(globalImports, allImports, importedSymbols) + ImportInfo(globalImports, globalImportedSymbols) } def naiveMoveSymbolPatch( @@ -173,7 +171,7 @@ object ReplaceSymbolOps { Patch.empty // do nothing because it was a renamed symbol case Some(_) => val causesCollision = - importInfo.importedSymbols.contains(to.signature.name) + importInfo.globalImportedSymbols.contains(to.signature.name) val addImport = if (n.isDefinition || causesCollision) Patch.empty else ctx.addGlobalImport(to) From 3374091c664a320b04964e902bf091716b93571b Mon Sep 17 00:00:00 2001 From: Subhramit Basu Date: Wed, 18 Jun 2025 01:23:19 +0000 Subject: [PATCH 12/13] Remove optional assignment --- .../main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala index 3d821b76a..0b5d4f2d1 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala @@ -16,7 +16,7 @@ import scalafix.v0._ object ReplaceSymbolOps { private case class ImportInfo( globalImports: Seq[Import], - globalImportedSymbols: Map[String, Symbol] = Map.empty + globalImportedSymbols: Map[String, Symbol] ) private object Select { From 85cd8bce5796735b2fd80d66859e345bcc45ff3d Mon Sep 17 00:00:00 2001 From: subhramit Date: Wed, 18 Jun 2025 07:04:37 +0530 Subject: [PATCH 13/13] IntelliJ rename - method name `getGlobalImports` Signed-off-by: subhramit --- .../scala/scalafix/internal/patch/ReplaceSymbolOps.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala index 0b5d4f2d1..19ab9ea99 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/patch/ReplaceSymbolOps.scala @@ -35,15 +35,15 @@ object ReplaceSymbolOps { tree: Tree )(implicit index: SemanticdbIndex): ImportInfo = { @tailrec - def getTopLevelImports(ast: Tree): Seq[Import] = ast match { - case Pkg(_, Seq(pkg: Pkg)) => getTopLevelImports(pkg) - case Source(Seq(pkg: Pkg)) => getTopLevelImports(pkg) + def getGlobalImports(ast: Tree): Seq[Import] = ast match { + case Pkg(_, Seq(pkg: Pkg)) => getGlobalImports(pkg) + case Source(Seq(pkg: Pkg)) => getGlobalImports(pkg) case Pkg(_, stats) => extractImports(stats) case Source(stats) => extractImports(stats) case _ => Nil } - val globalImports = getTopLevelImports(tree) + val globalImports = getGlobalImports(tree) // pre-compute global imported symbols for O(1) collision detection // since ctx.addGlobalImport adds imports at global scope