From 22522f1f37e8654cfa898222f08b9b70ffa58c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93lafur=20P=C3=A1ll=20Geirsson?= Date: Sat, 28 Jan 2017 20:53:29 +0100 Subject: [PATCH 1/2] Make project build in intellij --- build.sbt | 28 +++++++++++++------ core/src/main/scala/scalafix/Scalafix.scala | 7 +---- .../scala/scalafix/rewrite/RewriteCtx.scala | 18 ++++++++++++ .../scala/scalafix/util/OrganizeImports.scala | 10 +++---- .../src/main/scala/scalafix/util/logger.scala | 1 + .../main/scala/scalafix}/Readme.scala | 2 -- .../src/test/scala/scalafix/ImportPatches.sc | 19 +++++++++++++ .../scala/scalafix/util/DiffAssertions.scala | 8 ++++-- 8 files changed, 68 insertions(+), 25 deletions(-) rename readme/{ => src/main/scala/scalafix}/Readme.scala (92%) create mode 100644 scalafix-nsc/src/test/scala/scalafix/ImportPatches.sc rename {scalafix-nsc/src/test => scalafix-testutils/src/main}/scala/scalafix/util/DiffAssertions.scala (92%) diff --git a/build.sbt b/build.sbt index ac545f56c..129cd232a 100644 --- a/build.sbt +++ b/build.sbt @@ -128,6 +128,7 @@ lazy val `scalafix-root` = project .aggregate( `scalafix-nsc`, `scalafix-tests`, + `scalafix-testutils`, core, // cli, // superseded by sbt plugin readme, @@ -158,11 +159,10 @@ lazy val `scalafix-nsc` = project scalaVersion := "2.11.8", crossScalaVersions := crossVersions, libraryDependencies ++= Seq( - "org.scala-lang" % "scala-compiler" % scalaVersion.value, - "org.scalameta" %% "scalameta" % Build.metaV % "provided", - "com.googlecode.java-diff-utils" % "diffutils" % "1.3.0" % "test", - "org.scalatest" %% "scalatest" % Build.testV % Test, - "com.lihaoyi" %% "ammonite-ops" % Build.ammoniteV % Test, + "org.scala-lang" % "scala-compiler" % scalaVersion.value, + "org.scalameta" %% "scalameta" % Build.metaV % "provided", + "org.scalatest" %% "scalatest" % Build.testV % Test, + "com.lihaoyi" %% "ammonite-ops" % Build.ammoniteV % Test, // integration property tests "org.typelevel" %% "catalysts-platform" % "0.0.5" % Test, "com.typesafe.slick" %% "slick" % "3.2.0-M2" % Test, @@ -198,12 +198,12 @@ lazy val `scalafix-nsc` = project }, exposePaths("scalafixNsc", Test) ) - .dependsOn(core) + .dependsOn(core, `scalafix-testutils` % Test) lazy val cli = project - .settings(allSettings) - .settings(packSettings) .settings( + allSettings, + packSettings, moduleName := "scalafix-cli", packJvmOpts := Map( "scalafix" -> jvmOptions, @@ -220,7 +220,7 @@ lazy val cli = project "com.martiansoftware" % "nailgun-server" % "0.9.1" ) ) - .dependsOn(core % "compile->compile;test->test") + .dependsOn(core, `scalafix-testutils` % Test) lazy val publishedArtifacts = Seq( publishLocal in `scalafix-nsc`, @@ -249,6 +249,16 @@ lazy val `scalafix-sbt` = project ) .enablePlugins(BuildInfoPlugin) +lazy val `scalafix-testutils` = project.settings( + allSettings, + scalaVersion := "2.11.8", + crossScalaVersions := crossVersions, + libraryDependencies ++= Seq( + "com.googlecode.java-diff-utils" % "diffutils" % "1.3.0", + "org.scalatest" %% "scalatest" % Build.testV + ) +) + lazy val `scalafix-tests` = project .settings( allSettings, diff --git a/core/src/main/scala/scalafix/Scalafix.scala b/core/src/main/scala/scalafix/Scalafix.scala index 5f43acbce..406b05a56 100644 --- a/core/src/main/scala/scalafix/Scalafix.scala +++ b/core/src/main/scala/scalafix/Scalafix.scala @@ -17,12 +17,7 @@ object Scalafix { config.parser.apply(code, config.dialect) match { case Parsed.Success(ast) => val tokens = ast.tokens - implicit val ctx = RewriteCtx( - config, - new TokenList(ast.tokens), - AssociatedComments(tokens), - semanticApi - ) + implicit val ctx = RewriteCtx.fromCode(ast, config, semanticApi) val patches = config.rewrites.flatMap(_.rewrite(ast, ctx)) Fixed.Success(Patch.apply(ast, patches)) case Parsed.Error(pos, msg, e) => diff --git a/core/src/main/scala/scalafix/rewrite/RewriteCtx.scala b/core/src/main/scala/scalafix/rewrite/RewriteCtx.scala index 6b20cdd4a..bf0fbd01b 100644 --- a/core/src/main/scala/scalafix/rewrite/RewriteCtx.scala +++ b/core/src/main/scala/scalafix/rewrite/RewriteCtx.scala @@ -1,11 +1,29 @@ package scalafix.rewrite +import scala.meta.Tree +import scala.meta.tokens.Tokens import scalafix.ScalafixConfig import scalafix.util.AssociatedComments import scalafix.util.TokenList case class RewriteCtx( config: ScalafixConfig, + tokens: Tokens, tokenList: TokenList, comments: AssociatedComments, semantic: Option[SemanticApi] ) + +object RewriteCtx { + def fromCode(ast: Tree, + config: ScalafixConfig = ScalafixConfig(), + semanticApi: Option[SemanticApi] = None): RewriteCtx = { + val tokens = ast.tokens(config.dialect) + RewriteCtx( + config, + tokens, + new TokenList(tokens), + AssociatedComments(tokens), + semanticApi + ) + } +} diff --git a/core/src/main/scala/scalafix/util/OrganizeImports.scala b/core/src/main/scala/scalafix/util/OrganizeImports.scala index 7bd4035c0..ccd579f6c 100644 --- a/core/src/main/scala/scalafix/util/OrganizeImports.scala +++ b/core/src/main/scala/scalafix/util/OrganizeImports.scala @@ -160,15 +160,14 @@ private[this] class OrganizeImports private (implicit ctx: RewriteCtx) { .mkString("\n\n") } - def getRemovePatches(oldImports: Seq[Import], - tokens: Tokens): Seq[TokenPatch.Remove] = { + def getRemovePatches(oldImports: Seq[Import]): Seq[TokenPatch.Remove] = { val toRemove = for { firstImport <- oldImports.headOption first <- firstImport.tokens.headOption lastImport <- oldImports.lastOption last <- lastImport.tokens.lastOption } yield { - tokens.toIterator + ctx.tokens.toIterator .dropWhile(_.start < first.start) .takeWhile { x => x.end <= last.end @@ -200,14 +199,13 @@ private[this] class OrganizeImports private (implicit ctx: RewriteCtx) { val oldImports = getGlobalImports(code) val globalImports = oldImports.flatMap(getCanonicalImports) val cleanedUpImports = cleanUpImports(globalImports, patches) - val tokens = code.tokens val tokenToEdit = oldImports.headOption .map(_.tokens.head) - .getOrElse(tokens.head) + .getOrElse(ctx.tokens.head) val toInsert = prettyPrint(cleanedUpImports) TokenPatch.AddLeft(tokenToEdit, toInsert) +: - getRemovePatches(oldImports, tokens) + getRemovePatches(oldImports) } } } diff --git a/core/src/main/scala/scalafix/util/logger.scala b/core/src/main/scala/scalafix/util/logger.scala index fc8a8f170..836091865 100644 --- a/core/src/main/scala/scalafix/util/logger.scala +++ b/core/src/main/scala/scalafix/util/logger.scala @@ -85,3 +85,4 @@ object logger { s"$line\n=> $t\n$line" } } + diff --git a/readme/Readme.scala b/readme/src/main/scala/scalafix/Readme.scala similarity index 92% rename from readme/Readme.scala rename to readme/src/main/scala/scalafix/Readme.scala index 496d1ce29..3464c6034 100644 --- a/readme/Readme.scala +++ b/readme/src/main/scala/scalafix/Readme.scala @@ -2,8 +2,6 @@ package scalafix import scalatags.Text.TypedTag import scalatags.Text.all._ -import scalatex._ -import scalatags.Text.all._ object Readme { def note = b("Note. ") diff --git a/scalafix-nsc/src/test/scala/scalafix/ImportPatches.sc b/scalafix-nsc/src/test/scala/scalafix/ImportPatches.sc new file mode 100644 index 000000000..ef11b86f8 --- /dev/null +++ b/scalafix-nsc/src/test/scala/scalafix/ImportPatches.sc @@ -0,0 +1,19 @@ +import scala.collection.immutable.Seq +import scala.meta._ +import scalafix.rewrite.RewriteCtx +import scalafix.util.CanonicalImport +import scalafix.util.Patch +import scalafix.util.TreePatch.AddGlobalImport + +val code = + """import scala.language.higherKinds + |import java.{util => ju} + |import scala.collection.mutable._ + | + |object a + """.stripMargin.parse[Source].get +implicit val ctx: RewriteCtx = RewriteCtx.fromCode(code) +val patch = AddGlobalImport(CanonicalImport.fromImportee(q"cats.data", importee"EitherT")) + +val x = Patch.apply(code, Seq(patch)) + diff --git a/scalafix-nsc/src/test/scala/scalafix/util/DiffAssertions.scala b/scalafix-testutils/src/main/scala/scalafix/util/DiffAssertions.scala similarity index 92% rename from scalafix-nsc/src/test/scala/scalafix/util/DiffAssertions.scala rename to scalafix-testutils/src/main/scala/scalafix/util/DiffAssertions.scala index ebc666212..8f5e8cbf8 100644 --- a/scalafix-nsc/src/test/scala/scalafix/util/DiffAssertions.scala +++ b/scalafix-testutils/src/main/scala/scalafix/util/DiffAssertions.scala @@ -15,6 +15,10 @@ trait DiffAssertions extends FunSuiteLike { def assertEqual[A](a: A, b: A): Unit = { assert(a === b) } + def header[T](t: T): String = { + val line = s"=" * (t.toString.length + 3) + s"$line\n=> $t\n$line" + } case class DiffFailure(title: String, expected: String, @@ -28,12 +32,12 @@ trait DiffAssertions extends FunSuiteLike { val sb = new StringBuilder if (obtained.length < 1000) { sb.append(s""" - #${logger.header("Obtained")} + #${header("Obtained")} #${trailingSpace(obtained)} """.stripMargin('#')) } sb.append(s""" - #${logger.header("Diff")} + #${header("Diff")} #${trailingSpace(compareContents(obtained, expected))} """.stripMargin('#')) sb.toString() From fd40924a64c50e5cbb12a56e8bc3406b4b8ae928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93lafur=20P=C3=A1ll=20Geirsson?= Date: Sat, 28 Jan 2017 21:28:17 +0100 Subject: [PATCH 2/2] Simplify import patch api. --- core/src/main/scala/scalafix/syntax/package.scala | 2 +- .../main/scala/scalafix/util/OrganizeImports.scala | 4 ++-- core/src/main/scala/scalafix/util/Patch.scala | 9 ++++++--- .../src/test/scala/scalafix/ImportPatches.sc | 14 +++++++++----- .../src/test/scala/scalafix/SemanticTests.scala | 4 ++++ 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/core/src/main/scala/scalafix/syntax/package.scala b/core/src/main/scala/scalafix/syntax/package.scala index f636164fd..a6807ba24 100644 --- a/core/src/main/scala/scalafix/syntax/package.scala +++ b/core/src/main/scala/scalafix/syntax/package.scala @@ -13,7 +13,7 @@ package object syntax { def supersedes(patch: ImportPatch): Boolean = i.ref.structure == patch.importer.ref.structure && (i.importee.is[Importee.Wildcard] || - i.importee.structure == patch.importer.importee.structure) + i.importee.structure == patch.importee.structure) } implicit class XtensionToken(token: Token) { diff --git a/core/src/main/scala/scalafix/util/OrganizeImports.scala b/core/src/main/scala/scalafix/util/OrganizeImports.scala index ccd579f6c..ea243eb16 100644 --- a/core/src/main/scala/scalafix/util/OrganizeImports.scala +++ b/core/src/main/scala/scalafix/util/OrganizeImports.scala @@ -185,9 +185,9 @@ private[this] class OrganizeImports private (implicit ctx: RewriteCtx) { patch match { case _: AddGlobalImport => if (is.exists(_.supersedes(patch))) is - else is :+ patch.importer + else is ++ getCanonicalImports(patch.toImport) case remove: RemoveGlobalImport => - is.filter(_.structure == remove.importer.structure) + is.filterNot(_.structure == remove.importer.structure) } patches.foldLeft(removeUnused(globalImports))(combine) } diff --git a/core/src/main/scala/scalafix/util/Patch.scala b/core/src/main/scala/scalafix/util/Patch.scala index 9338033e2..aac136d1e 100644 --- a/core/src/main/scala/scalafix/util/Patch.scala +++ b/core/src/main/scala/scalafix/util/Patch.scala @@ -19,11 +19,14 @@ abstract class TokenPatch(val tok: Token, val newTok: String) s"TokenPatch(${logger.reveal(tok.syntax)}, ${tok.structure}, $newTok)" } -abstract class ImportPatch(val importer: CanonicalImport) extends TreePatch +abstract class ImportPatch(val importer: Importer) extends TreePatch { + def importee: Importee = importer.importees.head + def toImport: Import = Import(Seq(importer)) +} object TreePatch { - case class RemoveGlobalImport(override val importer: CanonicalImport) + case class RemoveGlobalImport(override val importer: Importer) extends ImportPatch(importer) - case class AddGlobalImport(override val importer: CanonicalImport) + case class AddGlobalImport(override val importer: Importer) extends ImportPatch(importer) } diff --git a/scalafix-nsc/src/test/scala/scalafix/ImportPatches.sc b/scalafix-nsc/src/test/scala/scalafix/ImportPatches.sc index ef11b86f8..4ee6721cb 100644 --- a/scalafix-nsc/src/test/scala/scalafix/ImportPatches.sc +++ b/scalafix-nsc/src/test/scala/scalafix/ImportPatches.sc @@ -1,10 +1,12 @@ +// Small worksheet to demonstrate usage of import patches import scala.collection.immutable.Seq import scala.meta._ import scalafix.rewrite.RewriteCtx -import scalafix.util.CanonicalImport import scalafix.util.Patch import scalafix.util.TreePatch.AddGlobalImport - +import scalafix.util.TreePatch.RemoveGlobalImport +import scala.meta._ +import scalafix.util.logger val code = """import scala.language.higherKinds |import java.{util => ju} @@ -13,7 +15,9 @@ val code = |object a """.stripMargin.parse[Source].get implicit val ctx: RewriteCtx = RewriteCtx.fromCode(code) -val patch = AddGlobalImport(CanonicalImport.fromImportee(q"cats.data", importee"EitherT")) - -val x = Patch.apply(code, Seq(patch)) +val add = AddGlobalImport(importer"cats.data.EitherT") +val addRedundant = AddGlobalImport(importer"scala.collection.mutable._") +val remove = RemoveGlobalImport(importer"scala.language.higherKinds") +val x = Patch.apply(code, Seq(add, addRedundant, remove)) +logger.elem(x) diff --git a/scalafix-nsc/src/test/scala/scalafix/SemanticTests.scala b/scalafix-nsc/src/test/scala/scalafix/SemanticTests.scala index b0873cfc6..deb30c730 100644 --- a/scalafix-nsc/src/test/scala/scalafix/SemanticTests.scala +++ b/scalafix-nsc/src/test/scala/scalafix/SemanticTests.scala @@ -11,8 +11,12 @@ import scala.{meta => m} import scalafix.nsc.ScalafixNscPlugin import scalafix.rewrite.ExplicitImplicit import scalafix.rewrite.Rewrite +import scalafix.rewrite.RewriteCtx import scalafix.util.DiffAssertions import scalafix.util.FileOps +import scalafix.util.Patch +import scalafix.util.TreePatch.AddGlobalImport +import scalafix.util.TreePatch.RemoveGlobalImport import scalafix.util.logger import org.scalatest.FunSuite