Skip to content

Commit

Permalink
Preserve the original source-level formatting when possible after exp…
Browse files Browse the repository at this point in the history
…loding imports (#280)
  • Loading branch information
johnspade committed Jul 26, 2022
1 parent de9a3d3 commit 97b20e5
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 14 deletions.
12 changes: 12 additions & 0 deletions input/src/main/scala/fix/ExplodeImportsFormatPreserving.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
rules = [OrganizeImports]
OrganizeImports.removeUnused = false
OrganizeImports.groupedImports = Explode
*/

package fix

import fix.ExplodeImports.FormatPreserving.g1.{ a, b }
import fix.ExplodeImports.FormatPreserving.g2.{ c => C, _ }

object ExplodeImportsFormatPreserving
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package fix

import fix.ExplodeImports.FormatPreserving.g1.a
import fix.ExplodeImports.FormatPreserving.g1.b
import fix.ExplodeImports.FormatPreserving.g2.{ c => C, _ }

object ExplodeImportsFormatPreserving
38 changes: 24 additions & 14 deletions rules/src/main/scala/fix/OrganizeImports.scala
Original file line number Diff line number Diff line change
Expand Up @@ -499,17 +499,7 @@ class OrganizeImports(config: OrganizeImportsConfig) extends SemanticRule("Organ
}
}

// Issue #127: After merging imports within an importer group, checks whether there are any
// input importers left untouched. For those importers, returns the original importer
// instance to preserve the original source level formatting.
locally {
val importerSyntaxMap = group.map { i => i.copy().syntax -> i }.toMap

newImporteeListsWithGivens filter (_.nonEmpty) map { importees =>
val newImporter = Importer(ref, importees)
importerSyntaxMap.getOrElse(newImporter.syntax, newImporter)
}
}
preserveOriginalImportersFormatting(group, newImporteeListsWithGivens, ref)
}

private def sortImportersSymbolsFirst(importers: Seq[Importer]): Seq[Importer] =
Expand Down Expand Up @@ -786,8 +776,10 @@ object OrganizeImports {
// source level formatting.
importer :: Nil

case Importer(ref, Importees(names, renames, unimports, givens, givenAll, wildcard))
if givenAll.isDefined || wildcard.isDefined =>
case importer @ Importer(
ref,
Importees(names, renames, unimports, givens, givenAll, wildcard)
) if givenAll.isDefined || wildcard.isDefined =>
// When a wildcard exists, all renames, unimports, and the wildcard must appear in the same
// importer, e.g.:
//
Expand All @@ -799,12 +791,30 @@ object OrganizeImports {
// import p.E
val importeesList =
(names ++ givens).map(_ :: Nil) :+ (renames ++ unimports ++ wildcard ++ givenAll)
importeesList filter (_.nonEmpty) map (Importer(ref, _))
preserveOriginalImportersFormatting(Seq(importer), importeesList, ref)

case importer =>
importer.importees map (i => importer.copy(importees = i :: Nil))
}

/**
* Issue #127: After merging or exploding imports, checks whether there are any input importers
* left untouched. For those importers, returns the original importer instance to preserve the
* original source level formatting.
*/
private def preserveOriginalImportersFormatting(
importers: Seq[Importer],
newImporteeLists: Seq[List[Importee]],
newImporterRef: Term.Ref
) = {
val importerSyntaxMap = importers.map { i => i.copy().syntax -> i }.toMap

newImporteeLists filter (_.nonEmpty) map { importees =>
val newImporter = Importer(newImporterRef, importees)
importerSyntaxMap.getOrElse(newImporter.syntax, newImporter)
}
}

/**
* Categorizes a list of `Importee`s into the following four groups:
*
Expand Down
60 changes: 60 additions & 0 deletions shared/src/main/scala/fix/ExplodeImports.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package fix

object ExplodeImports {
object Wildcard1 {
object a
object b
object c
object d
}

object Wildcard2 {
object a
object b
}

object Unimport1 {
object a
object b
object c
object d
}

object Unimport2 {
object a
object b
object c
object d
}

object Rename1 {
object a
object b
object c
object d
}

object Rename2 {
object a
object b
object c
}

object Dedup {
object a
object b
object c
}

object FormatPreserving {
object g1 {
object a
object b
}

object g2 {
object c
object d
}
}
}

0 comments on commit 97b20e5

Please sign in to comment.