From b5383e44c1feaa92212aa78029e21a08301847ac Mon Sep 17 00:00:00 2001 From: Gabriele Petronella Date: Sun, 10 Sep 2017 17:45:53 +0200 Subject: [PATCH 1/5] s/rewrites/rules and update scalafix version in the README --- scalafix/README.md | 2 +- .../{rewrites => rules}/src/main/scala/fix/Cats_v1_0_0.scala | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename scalafix/{rewrites => rules}/src/main/scala/fix/Cats_v1_0_0.scala (100%) diff --git a/scalafix/README.md b/scalafix/README.md index 39a3aa34e8..8dd1e5db8a 100644 --- a/scalafix/README.md +++ b/scalafix/README.md @@ -5,7 +5,7 @@ Install the scalafix sbt plugin (globally or in a specific project): ```scala -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.5.0-M3") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.5.0-RC2") ``` run diff --git a/scalafix/rewrites/src/main/scala/fix/Cats_v1_0_0.scala b/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala similarity index 100% rename from scalafix/rewrites/src/main/scala/fix/Cats_v1_0_0.scala rename to scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala From 81c18da70580fe229d6256102558e99b8e1e0c41 Mon Sep 17 00:00:00 2001 From: Gabriele Petronella Date: Sun, 10 Sep 2017 18:52:03 +0200 Subject: [PATCH 2/5] More s/rewrite/rule --- scalafix/README.md | 4 ++-- scalafix/build.sbt | 4 ++-- .../src/main/scala/fix/v1_0_0/RemoveCartesianBuilder.scala | 2 +- .../src/main/scala/fix/v1_0_0/RemoveCartesianBuilder2.scala | 2 +- scalafix/input/src/main/scala/fix/v1_0_0/RemoveSplit.scala | 2 +- scalafix/input/src/main/scala/fix/v1_0_0/RemoveUnapply.scala | 4 ++-- .../input/src/main/scala/fix/v1_0_0/RenameFreeSuspend.scala | 4 ++-- .../main/scala/fix/v1_0_0/RenameInjectProdAndCoproduct.scala | 4 ++-- .../src/main/scala/fix/v1_0_0/RenameReducibleMethods.scala | 4 ++-- .../src/main/scala/fix/v1_0_0/RenameTupleApplySyntax.scala | 2 +- .../input/src/main/scala/fix/v1_0_0/SimplifyEitherTLift.scala | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/scalafix/README.md b/scalafix/README.md index 8dd1e5db8a..744d657a71 100644 --- a/scalafix/README.md +++ b/scalafix/README.md @@ -1,4 +1,4 @@ -# Scalafix rewrites for cats +# Scalafix rules for cats ## Try this! @@ -14,7 +14,7 @@ run sbt scalafix github:typelevel/cats/v1.0.0 ``` -## Available rewrites +## Available rules - [x] All Unapply enabled methods, e.g. sequenceU, traverseU, etc. are removed. Unapply enabled syntax ops are also removed. Please use the partial unification SI-2712 fix instead. The easiest way might be this sbt-plugin. diff --git a/scalafix/build.sbt b/scalafix/build.sbt index 96740db285..c588890dd4 100644 --- a/scalafix/build.sbt +++ b/scalafix/build.sbt @@ -2,7 +2,7 @@ val V = _root_.scalafix.Versions scalaVersion in ThisBuild := V.scala212 -lazy val rewrites = project.settings( +lazy val rules = project.settings( libraryDependencies += "ch.epfl.scala" %% "scalafix-core" % V.version ) @@ -35,5 +35,5 @@ lazy val tests = project classDirectory.in(input, Compile).value ) ) - .dependsOn(input, rewrites) + .dependsOn(input, rules) .enablePlugins(BuildInfoPlugin) diff --git a/scalafix/input/src/main/scala/fix/v1_0_0/RemoveCartesianBuilder.scala b/scalafix/input/src/main/scala/fix/v1_0_0/RemoveCartesianBuilder.scala index 8f206fa10a..5bdd45f37c 100644 --- a/scalafix/input/src/main/scala/fix/v1_0_0/RemoveCartesianBuilder.scala +++ b/scalafix/input/src/main/scala/fix/v1_0_0/RemoveCartesianBuilder.scala @@ -1,5 +1,5 @@ /* -rewrite = "scala:fix.v1_0_0.RemoveCartesianBuilder" +rule = "scala:fix.v1_0_0.RemoveCartesianBuilder" */ package fix package to1_0_0 diff --git a/scalafix/input/src/main/scala/fix/v1_0_0/RemoveCartesianBuilder2.scala b/scalafix/input/src/main/scala/fix/v1_0_0/RemoveCartesianBuilder2.scala index 9e78bdf847..0d32840989 100644 --- a/scalafix/input/src/main/scala/fix/v1_0_0/RemoveCartesianBuilder2.scala +++ b/scalafix/input/src/main/scala/fix/v1_0_0/RemoveCartesianBuilder2.scala @@ -1,5 +1,5 @@ /* -rewrite = "scala:fix.v1_0_0.RemoveCartesianBuilder" +rule = "scala:fix.v1_0_0.RemoveCartesianBuilder" */ package fix package to1_0_0 diff --git a/scalafix/input/src/main/scala/fix/v1_0_0/RemoveSplit.scala b/scalafix/input/src/main/scala/fix/v1_0_0/RemoveSplit.scala index a796a7b009..7b593ffd5c 100644 --- a/scalafix/input/src/main/scala/fix/v1_0_0/RemoveSplit.scala +++ b/scalafix/input/src/main/scala/fix/v1_0_0/RemoveSplit.scala @@ -1,5 +1,5 @@ /* -rewrite = "scala:fix.v1_0_0.RemoveSplit" +rule = "scala:fix.v1_0_0.RemoveSplit" */ package fix package to1_0_0 diff --git a/scalafix/input/src/main/scala/fix/v1_0_0/RemoveUnapply.scala b/scalafix/input/src/main/scala/fix/v1_0_0/RemoveUnapply.scala index 15370b5ec7..30e712a8af 100644 --- a/scalafix/input/src/main/scala/fix/v1_0_0/RemoveUnapply.scala +++ b/scalafix/input/src/main/scala/fix/v1_0_0/RemoveUnapply.scala @@ -1,5 +1,5 @@ -/* -rewrite = "scala:fix.v1_0_0.RemoveUnapply" +/* +rule = "scala:fix.v1_0_0.RemoveUnapply" */ package fix package to1_0_0 diff --git a/scalafix/input/src/main/scala/fix/v1_0_0/RenameFreeSuspend.scala b/scalafix/input/src/main/scala/fix/v1_0_0/RenameFreeSuspend.scala index ffa3e26a38..d478c32098 100644 --- a/scalafix/input/src/main/scala/fix/v1_0_0/RenameFreeSuspend.scala +++ b/scalafix/input/src/main/scala/fix/v1_0_0/RenameFreeSuspend.scala @@ -1,5 +1,5 @@ -/* -rewrite = "scala:fix.v1_0_0.RenameFreeSuspend" +/* +rule = "scala:fix.v1_0_0.RenameFreeSuspend" */ package fix package to1_0_0 diff --git a/scalafix/input/src/main/scala/fix/v1_0_0/RenameInjectProdAndCoproduct.scala b/scalafix/input/src/main/scala/fix/v1_0_0/RenameInjectProdAndCoproduct.scala index 08599b5fbf..5c69b50fc9 100644 --- a/scalafix/input/src/main/scala/fix/v1_0_0/RenameInjectProdAndCoproduct.scala +++ b/scalafix/input/src/main/scala/fix/v1_0_0/RenameInjectProdAndCoproduct.scala @@ -1,5 +1,5 @@ -/* -rewrite = "scala:fix.v1_0_0.RenameInjectProdAndCoproduct" +/* +rule = "scala:fix.v1_0_0.RenameInjectProdAndCoproduct" */ package fix package to1_0_0 diff --git a/scalafix/input/src/main/scala/fix/v1_0_0/RenameReducibleMethods.scala b/scalafix/input/src/main/scala/fix/v1_0_0/RenameReducibleMethods.scala index 4bbbb572da..38a00bb3ca 100644 --- a/scalafix/input/src/main/scala/fix/v1_0_0/RenameReducibleMethods.scala +++ b/scalafix/input/src/main/scala/fix/v1_0_0/RenameReducibleMethods.scala @@ -1,5 +1,5 @@ -/* -rewrite = "scala:fix.v1_0_0.RenameReducibleMethods" +/* +rule = "scala:fix.v1_0_0.RenameReducibleMethods" */ package fix package to1_0_0 diff --git a/scalafix/input/src/main/scala/fix/v1_0_0/RenameTupleApplySyntax.scala b/scalafix/input/src/main/scala/fix/v1_0_0/RenameTupleApplySyntax.scala index 02fd5a1779..bcc98f815d 100644 --- a/scalafix/input/src/main/scala/fix/v1_0_0/RenameTupleApplySyntax.scala +++ b/scalafix/input/src/main/scala/fix/v1_0_0/RenameTupleApplySyntax.scala @@ -1,5 +1,5 @@ /* -rewrite = "scala:fix.v1_0_0.RenameTupleApplySyntax" +rule = "scala:fix.v1_0_0.RenameTupleApplySyntax" */ package fix package to1_0_0 diff --git a/scalafix/input/src/main/scala/fix/v1_0_0/SimplifyEitherTLift.scala b/scalafix/input/src/main/scala/fix/v1_0_0/SimplifyEitherTLift.scala index 2fcee79eb0..c653b69bbc 100644 --- a/scalafix/input/src/main/scala/fix/v1_0_0/SimplifyEitherTLift.scala +++ b/scalafix/input/src/main/scala/fix/v1_0_0/SimplifyEitherTLift.scala @@ -1,5 +1,5 @@ /* -rewrite = "scala:fix.v1_0_0.SimplifyEitherTLift" +rule = "scala:fix.v1_0_0.SimplifyEitherTLift" */ package fix package to1_0_0 From ad3dfad63ab60ecd5a4bab1abbe7140729a4b21d Mon Sep 17 00:00:00 2001 From: Gabriele Petronella Date: Sun, 10 Sep 2017 20:42:54 +0200 Subject: [PATCH 3/5] Use Symbol and SymbolMatcher --- .../src/main/scala/fix/Cats_v1_0_0.scala | 124 +++++++++--------- 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala b/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala index 7ca608aadc..08ac2ed822 100644 --- a/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala +++ b/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala @@ -2,6 +2,7 @@ package fix package v1_0_0 import scalafix._ +import scalafix.util.SymbolMatcher import scalafix.syntax._ import scala.meta._ @@ -10,27 +11,13 @@ object Utils { private[fix] def rename( ctx: RuleCtx, t: Term.Name, - renames: Map[String, String])(implicit index: SemanticdbIndex): Patch = { + renames: Map[Symbol, String])(implicit index: SemanticdbIndex): Patch = { renames.collect { - case (target, rename) if t.isSymbol(target) => + case (target, rename) if SymbolMatcher.normalized(target).matches(t) => ctx.replaceTree(t, rename) }.asPatch } - implicit class TermNameOps(t: Name) { - def isSymbol(s: String)(implicit index: SemanticdbIndex): Boolean = - t.symbol.exists(_.normalized.syntax == s) - - def isOneOfSymbols(symbols: Set[String])( - implicit index: SemanticdbIndex): Boolean = - t.symbol.exists(s => symbols.contains(s.normalized.syntax)) - } - - implicit class OptionTermNameOps(t: Option[Name]) { - def isSymbol(s: String)(implicit index: SemanticdbIndex): Boolean = - t.flatMap(_.symbol).exists(_.normalized.syntax == s) - } - } import Utils._ @@ -38,34 +25,39 @@ import Utils._ case class RemoveCartesianBuilder(index: SemanticdbIndex) extends SemanticRule(index, "RemoveCartesianBuilder") { - private[this] val cartesianBuilders = - (1 to 22) - .map(arity => - s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.`|@|`.") - .toSet + - "_root_.cats.syntax.CartesianOps.`|@|`." - - private[this] val partialApplies = Set( - s"_root_.cats.syntax.CartesianOps.`*>`.", - s"_root_.cats.syntax.CartesianOps.`<*`." + private[this] val cartesianBuilders = SymbolMatcher.normalized( + Symbol("_root_.cats.syntax.CartesianOps.`|@|`.") :: + (1 to 22).toList.map(arity => + Symbol( + s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.`|@|`.")): _*) + + private[this] val partialApplies = SymbolMatcher.normalized( + Symbol(s"_root_.cats.syntax.CartesianOps.`*>`."), + Symbol(s"_root_.cats.syntax.CartesianOps.`<*`.") ) - private[this] val renames: Map[String, String] = + private[this] val renames: Map[Symbol, String] = (1 to 22) .map { arity => Seq( - s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.map." -> "mapN", - s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.imap." -> "imapN", - s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.contramap." -> "contramapN" + Symbol( + s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.map.") -> "mapN", + Symbol( + s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.imap.") -> "imapN", + Symbol( + s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.contramap.") -> "contramapN" ) } .flatten .toMap + private[this] val cartesianOps = + SymbolMatcher.normalized(renames.keys.toSeq: _*) + // Hackish way to work around duplicate fixes due to recursion val alreadyFixedOps = collection.mutable.Set.empty[Term.Name] private[this] def replaceOpWithComma(ctx: RuleCtx, op: Term.Name): Patch = - if (op.isOneOfSymbols(cartesianBuilders) && !alreadyFixedOps.contains(op)) { + if (op.matches(cartesianBuilders) && !alreadyFixedOps.contains(op)) { alreadyFixedOps += op // remove the space before |@| ctx.removeToken(ctx.tokenList.prev(op.tokens.head)) + @@ -97,14 +89,14 @@ case class RemoveCartesianBuilder(index: SemanticdbIndex) override def fix(ctx: RuleCtx): Patch = { ctx.tree.collect { - case t: Term.ApplyInfix if t.op.isOneOfSymbols(cartesianBuilders) => + case t: Term.ApplyInfix if t.op.matches(cartesianBuilders) => removeCartesianBuilderOp(ctx, t) - case t: Term.ApplyInfix if t.op.isOneOfSymbols(renames.keys.toSet) => + case t: Term.ApplyInfix if t.op.matches(cartesianOps) => wrapInParensIfNeeded(ctx, t.lhs) case t: Term.Name => rename(ctx, t, renames) case t @ q"import cats.syntax.cartesian._" => val usesPartialApplies = ctx.tree.collect { - case t: Term.Name if t.isOneOfSymbols(partialApplies) => () + case partialApplies(t: Term.Name) => () }.length > 0 if (usesPartialApplies) { ctx.addRight(t.tokens.last, "\n import cats.syntax.apply._") @@ -120,14 +112,14 @@ case class RemoveUnapply(index: SemanticdbIndex) extends SemanticRule(index, "RemoveUnapply") { private[this] val renames = Map( - "_root_.cats.Traverse.Ops.traverseU." -> "traverse", - "_root_.cats.Foldable.Ops.traverseU_." -> "traverse_", - "_root_.cats.Foldable.traverseU_." -> "traverse_", - "_root_.cats.Traverse.Ops.sequenceU." -> "sequence", - "_root_.cats.Foldable.Ops.sequenceU_." -> "sequence_", - "_root_.cats.Foldable.sequenceU_." -> "sequence_", - "_root_.cats.data.Func.appFuncU." -> "appFunc", - "_root_.cats.free.FreeT.liftTU." -> "liftT" + Symbol("_root_.cats.Traverse.Ops.traverseU.") -> "traverse", + Symbol("_root_.cats.Foldable.Ops.traverseU_.") -> "traverse_", + Symbol("_root_.cats.Foldable.traverseU_.") -> "traverse_", + Symbol("_root_.cats.Traverse.Ops.sequenceU.") -> "sequence", + Symbol("_root_.cats.Foldable.Ops.sequenceU_.") -> "sequence_", + Symbol("_root_.cats.Foldable.sequenceU_.") -> "sequence_", + Symbol("_root_.cats.data.Func.appFuncU.") -> "appFunc", + Symbol("_root_.cats.free.FreeT.liftTU.") -> "liftT" ) private[this] def importeeName(importee: Importee): Option[Name] = @@ -140,11 +132,12 @@ case class RemoveUnapply(index: SemanticdbIndex) private[this] def removeImportee( ctx: RuleCtx, importee: Importee, - fixes: Map[String, String]): Patch = - fixes.collect { - case (target, _) if importeeName(importee).isSymbol(target) => - ctx.removeImportee(importee) + fixes: Map[Symbol, String]): Patch = { + val importsToRemove = SymbolMatcher.normalized(fixes.keys.toSeq: _*) + importeeName(importee).collect { + case importsToRemove(n) => ctx.removeImportee(importee) }.asPatch + } override def fix(ctx: RuleCtx): Patch = { ctx.tree.collect { @@ -159,8 +152,8 @@ case class RenameFreeSuspend(index: SemanticdbIndex) extends SemanticRule(index, "RenameFreeSuspend") { private[this] val renames = Map( - "_root_.cats.free.Free.suspend." -> "defer", - "_root_.cats.free.TrampolineFunctions.suspend." -> "defer" + Symbol("_root_.cats.free.Free.suspend.") -> "defer", + Symbol("_root_.cats.free.TrampolineFunctions.suspend.") -> "defer" ) override def fix(ctx: RuleCtx): Patch = { @@ -176,12 +169,12 @@ case class RenameReducibleMethods(index: SemanticdbIndex) extends SemanticRule(index, "RenameReducibleMethods") { private[this] val renames = Map( - "_root_.cats.Reducible.traverse1_." -> "nonEmptyTraverse_", - "_root_.cats.Reducible.Ops.traverse1_." -> "nonEmptyTraverse_", - "_root_.cats.Reducible.intercalate1." -> "nonEmptyIntercalate", - "_root_.cats.Reducible.Ops.intercalate1." -> "nonEmptyIntercalate", - "_root_.cats.Reducible.sequence1_." -> "nonEmptySequence_", - "_root_.cats.Reducible.Ops.sequence1_." -> "nonEmptySequence_" + Symbol("_root_.cats.Reducible.traverse1_.") -> "nonEmptyTraverse_", + Symbol("_root_.cats.Reducible.Ops.traverse1_.") -> "nonEmptyTraverse_", + Symbol("_root_.cats.Reducible.intercalate1.") -> "nonEmptyIntercalate", + Symbol("_root_.cats.Reducible.Ops.intercalate1.") -> "nonEmptyIntercalate", + Symbol("_root_.cats.Reducible.sequence1_.") -> "nonEmptySequence_", + Symbol("_root_.cats.Reducible.Ops.sequence1_.") -> "nonEmptySequence_" ) override def fix(ctx: RuleCtx): Patch = { @@ -196,8 +189,12 @@ case class RenameReducibleMethods(index: SemanticdbIndex) case class SimplifyEitherTLift(index: SemanticdbIndex) extends SemanticRule(index, "SimplifyEitherTLift") { - private[this] val leftSymbol = "_root_.cats.data.EitherTFunctions.left." - private[this] val rightSymbol = "_root_.cats.data.EitherTFunctions.right." + private[this] val leftSymbol = SymbolMatcher.normalized( + Symbol("_root_.cats.data.EitherTFunctions.left.") + ) + private[this] val rightSymbol = SymbolMatcher.normalized( + Symbol("_root_.cats.data.EitherTFunctions.right.") + ) private[this] def removeWithLeadingComma(ctx: RuleCtx, t: Tree): Patch = (for { @@ -211,11 +208,9 @@ case class SimplifyEitherTLift(index: SemanticdbIndex) override def fix(ctx: RuleCtx): Patch = { ctx.tree.collect { - case Term.ApplyType(Term.Select(_, name), Seq(f, a, b)) - if name.isSymbol(leftSymbol) => + case Term.ApplyType(Term.Select(_, leftSymbol(name)), Seq(_, a, _)) => ctx.replaceTree(name, "leftT") + removeWithLeadingComma(ctx, a) - case Term.ApplyType(Term.Select(_, name), Seq(f, a, b)) - if name.isSymbol(rightSymbol) => + case Term.ApplyType(Term.Select(_, rightSymbol(name)), Seq(_, _, b)) => ctx.replaceTree(name, "pure") + removeWithLeadingComma(ctx, b) }.asPatch } @@ -241,13 +236,14 @@ case class RenameInjectProdAndCoproduct(index: SemanticdbIndex) case class RenameTupleApplySyntax(index: SemanticdbIndex) extends SemanticRule(index, "RenameTupleApplySyntax") { - private[this] val renames: Map[String, String] = + private[this] val renames: Map[Symbol, String] = (1 to 22) .map { arity => Seq( - s"_root_.cats.syntax.Tuple${arity}CartesianOps.map$arity." -> "mapN", - s"_root_.cats.syntax.Tuple${arity}CartesianOps.contramap$arity." -> "contramapN", - s"_root_.cats.syntax.Tuple${arity}CartesianOps.imap$arity." -> "imapN" + Symbol(s"_root_.cats.syntax.Tuple${arity}CartesianOps.map$arity.") -> "mapN", + Symbol( + s"_root_.cats.syntax.Tuple${arity}CartesianOps.contramap$arity.") -> "contramapN", + Symbol(s"_root_.cats.syntax.Tuple${arity}CartesianOps.imap$arity.") -> "imapN" ) } .flatten From 3864dc6b5ecc51574d84782d596e0ea067161d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93lafur=20P=C3=A1ll=20Geirsson?= Date: Mon, 11 Sep 2017 17:08:58 +0200 Subject: [PATCH 4/5] Refactor scalafix migration rewrite - ctx.replaceSymbols also renames - ctx.replaceSymbols also removes imports - Tree.is[Comma] instead of `.syntax == ","` - Tree.collectFirst/exists from contrib module. - tokenList.leading().takeWhile to strip leading whitespace --- .../src/main/scala/fix/Cats_v1_0_0.scala | 227 ++++++------------ 1 file changed, 76 insertions(+), 151 deletions(-) diff --git a/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala b/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala index 08ac2ed822..9673c00d12 100644 --- a/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala +++ b/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala @@ -3,23 +3,8 @@ package v1_0_0 import scalafix._ import scalafix.util.SymbolMatcher -import scalafix.syntax._ import scala.meta._ - -object Utils { - - private[fix] def rename( - ctx: RuleCtx, - t: Term.Name, - renames: Map[Symbol, String])(implicit index: SemanticdbIndex): Patch = { - renames.collect { - case (target, rename) if SymbolMatcher.normalized(target).matches(t) => - ctx.replaceTree(t, rename) - }.asPatch - } - -} -import Utils._ +import scala.meta.contrib._ // ref: https://github.com/typelevel/cats/pull/1745 case class RemoveCartesianBuilder(index: SemanticdbIndex) @@ -29,81 +14,62 @@ case class RemoveCartesianBuilder(index: SemanticdbIndex) Symbol("_root_.cats.syntax.CartesianOps.`|@|`.") :: (1 to 22).toList.map(arity => Symbol( - s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.`|@|`.")): _*) + s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.`|@|`.")): _* + ) private[this] val partialApplies = SymbolMatcher.normalized( Symbol(s"_root_.cats.syntax.CartesianOps.`*>`."), Symbol(s"_root_.cats.syntax.CartesianOps.`<*`.") ) - private[this] val renames: Map[Symbol, String] = - (1 to 22) - .map { arity => - Seq( - Symbol( - s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.map.") -> "mapN", - Symbol( - s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.imap.") -> "imapN", - Symbol( - s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.contramap.") -> "contramapN" - ) - } - .flatten - .toMap + private[this] val renames: Map[String, String] = (1 to 22).flatMap { arity => + Seq( + s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.map." -> "mapN", + s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.imap." -> "imapN", + s"_root_.cats.syntax.CartesianBuilder.CartesianBuilder$arity.contramap." -> "contramapN" + ) + }.toMap private[this] val cartesianOps = - SymbolMatcher.normalized(renames.keys.toSeq: _*) + SymbolMatcher.normalized(renames.keys.map(Symbol.apply).toSeq: _*) - // Hackish way to work around duplicate fixes due to recursion - val alreadyFixedOps = collection.mutable.Set.empty[Term.Name] private[this] def replaceOpWithComma(ctx: RuleCtx, op: Term.Name): Patch = - if (op.matches(cartesianBuilders) && !alreadyFixedOps.contains(op)) { - alreadyFixedOps += op + // replace |@| with , + ctx.replaceTree(op, ",") ++ // remove the space before |@| - ctx.removeToken(ctx.tokenList.prev(op.tokens.head)) + - // replace |@| with , - ctx.replaceTree(op, ",") - } else { - Patch.empty - } - - private[this] def removeCartesianBuilderOp( - ctx: RuleCtx, - applyInfix: Term.ApplyInfix): Patch = { - applyInfix match { - case Term.ApplyInfix(lhs: Term.ApplyInfix, op, _, _) => - removeCartesianBuilderOp(ctx, lhs) + replaceOpWithComma(ctx, op) - case Term.ApplyInfix(_, op, _, _) => - replaceOpWithComma(ctx, op) - } - } + ctx.tokenList + .leading(op.tokens.head) + .takeWhile(_.is[Whitespace]) + .map(ctx.removeToken) private[this] def wrapInParensIfNeeded(ctx: RuleCtx, t: Term): Patch = { - if (t.tokens.head.is[Token.LeftParen] && t.tokens.last - .is[Token.RightParen]) { - Patch.empty - } else { - ctx.addLeft(t.tokens.head, "(") + ctx.addRight(t.tokens.last, ")") - } - } + for { + head <- t.tokens.headOption + if !head.is[Token.LeftParen] + last <- t.tokens.lastOption + if !last.is[Token.RightParen] + } yield + ctx.addLeft(head, "(") + + ctx.addRight(last, ")") + }.asPatch override def fix(ctx: RuleCtx): Patch = { ctx.tree.collect { - case t: Term.ApplyInfix if t.op.matches(cartesianBuilders) => - removeCartesianBuilderOp(ctx, t) - case t: Term.ApplyInfix if t.op.matches(cartesianOps) => - wrapInParensIfNeeded(ctx, t.lhs) - case t: Term.Name => rename(ctx, t, renames) + case Term.ApplyInfix(_, cartesianBuilders(op: Term.Name), _, _) => + replaceOpWithComma(ctx, op) + case Term.ApplyInfix(lhs, cartesianOps(_), _, _) => + wrapInParensIfNeeded(ctx, lhs) case t @ q"import cats.syntax.cartesian._" => - val usesPartialApplies = ctx.tree.collect { - case partialApplies(t: Term.Name) => () - }.length > 0 + val usesPartialApplies = ctx.tree.exists { + case partialApplies(_: Term.Name) => true + case _ => false + } if (usesPartialApplies) { ctx.addRight(t.tokens.last, "\n import cats.syntax.apply._") } else { ctx.replaceTree(t, "import cats.syntax.apply._") } - }.asPatch + }.asPatch + ctx.replaceSymbols(renames.toSeq: _*) } } @@ -111,78 +77,42 @@ case class RemoveCartesianBuilder(index: SemanticdbIndex) case class RemoveUnapply(index: SemanticdbIndex) extends SemanticRule(index, "RemoveUnapply") { - private[this] val renames = Map( - Symbol("_root_.cats.Traverse.Ops.traverseU.") -> "traverse", - Symbol("_root_.cats.Foldable.Ops.traverseU_.") -> "traverse_", - Symbol("_root_.cats.Foldable.traverseU_.") -> "traverse_", - Symbol("_root_.cats.Traverse.Ops.sequenceU.") -> "sequence", - Symbol("_root_.cats.Foldable.Ops.sequenceU_.") -> "sequence_", - Symbol("_root_.cats.Foldable.sequenceU_.") -> "sequence_", - Symbol("_root_.cats.data.Func.appFuncU.") -> "appFunc", - Symbol("_root_.cats.free.FreeT.liftTU.") -> "liftT" + override def fix(ctx: RuleCtx): Patch = ctx.replaceSymbols( + "_root_.cats.Traverse.Ops.traverseU." -> "traverse", + "_root_.cats.Foldable.Ops.traverseU_." -> "traverse_", + "_root_.cats.Foldable.traverseU_." -> "traverse_", + "_root_.cats.Traverse.Ops.sequenceU." -> "sequence", + "_root_.cats.Foldable.Ops.sequenceU_." -> "sequence_", + "_root_.cats.Foldable.sequenceU_." -> "sequence_", + "_root_.cats.data.Func.appFuncU." -> "appFunc", + "_root_.cats.free.FreeT.liftTU." -> "liftT" ) - - private[this] def importeeName(importee: Importee): Option[Name] = - importee match { - case Importee.Name(name) => Some(name) - case Importee.Rename(name, _) => Some(name) - case _ => None - } - - private[this] def removeImportee( - ctx: RuleCtx, - importee: Importee, - fixes: Map[Symbol, String]): Patch = { - val importsToRemove = SymbolMatcher.normalized(fixes.keys.toSeq: _*) - importeeName(importee).collect { - case importsToRemove(n) => ctx.removeImportee(importee) - }.asPatch - } - - override def fix(ctx: RuleCtx): Patch = { - ctx.tree.collect { - case t: Term.Name => rename(ctx, t, renames) - case t: Importee.Name => removeImportee(ctx, t, renames) - }.asPatch - } } // ref: https://github.com/typelevel/cats/pull/1709 case class RenameFreeSuspend(index: SemanticdbIndex) extends SemanticRule(index, "RenameFreeSuspend") { - private[this] val renames = Map( - Symbol("_root_.cats.free.Free.suspend.") -> "defer", - Symbol("_root_.cats.free.TrampolineFunctions.suspend.") -> "defer" + override def fix(ctx: RuleCtx): Patch = ctx.replaceSymbols( + "_root_.cats.free.Free.suspend." -> "defer", + "_root_.cats.free.TrampolineFunctions.suspend." -> "defer" ) - override def fix(ctx: RuleCtx): Patch = { - ctx.tree.collect { - case t: Term.Name => rename(ctx, t, renames) - }.asPatch - } - } // ref: https://github.com/typelevel/cats/pull/1611 case class RenameReducibleMethods(index: SemanticdbIndex) extends SemanticRule(index, "RenameReducibleMethods") { - private[this] val renames = Map( - Symbol("_root_.cats.Reducible.traverse1_.") -> "nonEmptyTraverse_", - Symbol("_root_.cats.Reducible.Ops.traverse1_.") -> "nonEmptyTraverse_", - Symbol("_root_.cats.Reducible.intercalate1.") -> "nonEmptyIntercalate", - Symbol("_root_.cats.Reducible.Ops.intercalate1.") -> "nonEmptyIntercalate", - Symbol("_root_.cats.Reducible.sequence1_.") -> "nonEmptySequence_", - Symbol("_root_.cats.Reducible.Ops.sequence1_.") -> "nonEmptySequence_" + override def fix(ctx: RuleCtx): Patch = ctx.replaceSymbols( + "_root_.cats.Reducible.traverse1_." -> "nonEmptyTraverse_", + "_root_.cats.Reducible.Ops.traverse1_." -> "nonEmptyTraverse_", + "_root_.cats.Reducible.intercalate1." -> "nonEmptyIntercalate", + "_root_.cats.Reducible.Ops.intercalate1." -> "nonEmptyIntercalate", + "_root_.cats.Reducible.sequence1_." -> "nonEmptySequence_", + "_root_.cats.Reducible.Ops.sequence1_." -> "nonEmptySequence_" ) - override def fix(ctx: RuleCtx): Patch = { - ctx.tree.collect { - case t: Term.Name => rename(ctx, t, renames) - }.asPatch - } - } // ref: https://github.com/typelevel/cats/pull/1614 @@ -198,11 +128,13 @@ case class SimplifyEitherTLift(index: SemanticdbIndex) private[this] def removeWithLeadingComma(ctx: RuleCtx, t: Tree): Patch = (for { - leadingComma <- ctx.tokenList.leading(t.tokens.head).find(_.syntax == ",") + leadingComma <- ctx.tokenList + .leading(t.tokens.head) + .find(_.is[Token.Comma]) } yield { - val leadingSpaces = ctx.tokenList.slice(leadingComma, t.tokens.head) - ctx.removeToken(leadingComma) + - leadingSpaces.map(ctx.removeToken).asPatch + + val leadingSpaces = ctx.tokenList.slice(leadingComma, t.tokens.last) + ctx.removeToken(leadingComma) ++ + leadingSpaces.map(ctx.removeToken) + ctx.removeTokens(t.tokens) }).asPatch @@ -222,13 +154,11 @@ case class SimplifyEitherTLift(index: SemanticdbIndex) case class RenameInjectProdAndCoproduct(index: SemanticdbIndex) extends SemanticRule(index, "RenameInjectProdAndCoproduct") { - override def fix(ctx: RuleCtx): Patch = { - ctx.replaceSymbols( - "_root_.cats.free.Inject." -> "_root_.cats.InjectK.", - "_root_.cats.data.Prod." -> "_root_.cats.data.Tuple2K.", - "_root_.cats.data.Coproduct." -> "_root_.cats.data.EitherK." - ) - } + override def fix(ctx: RuleCtx): Patch = ctx.replaceSymbols( + "_root_.cats.free.Inject." -> "_root_.cats.InjectK.", + "_root_.cats.data.Prod." -> "_root_.cats.data.Tuple2K.", + "_root_.cats.data.Coproduct." -> "_root_.cats.data.EitherK." + ) } @@ -236,25 +166,20 @@ case class RenameInjectProdAndCoproduct(index: SemanticdbIndex) case class RenameTupleApplySyntax(index: SemanticdbIndex) extends SemanticRule(index, "RenameTupleApplySyntax") { - private[this] val renames: Map[Symbol, String] = - (1 to 22) - .map { arity => + override def fix(ctx: RuleCtx): Patch = { + ctx.replaceSymbols( + (1 to 22).flatMap { arity => Seq( - Symbol(s"_root_.cats.syntax.Tuple${arity}CartesianOps.map$arity.") -> "mapN", - Symbol( - s"_root_.cats.syntax.Tuple${arity}CartesianOps.contramap$arity.") -> "contramapN", - Symbol(s"_root_.cats.syntax.Tuple${arity}CartesianOps.imap$arity.") -> "imapN" + s"_root_.cats.syntax.Tuple${arity}CartesianOps.map$arity." -> "mapN", + s"_root_.cats.syntax.Tuple${arity}CartesianOps.contramap$arity." -> "contramapN", + s"_root_.cats.syntax.Tuple${arity}CartesianOps.imap$arity." -> "imapN" ) + }: _* + ) ++ + ctx.tree.collect { + case t @ q"import cats.syntax.tuple._" => + ctx.replaceTree(t, "import cats.syntax.apply._") } - .flatten - .toMap - - override def fix(ctx: RuleCtx): Patch = { - ctx.tree.collect { - case t: Term.Name => rename(ctx, t, renames) - case t @ q"import cats.syntax.tuple._" => - ctx.replaceTree(t, "import cats.syntax.apply._") - }.asPatch } } From e6f59d15bdfe17b9eabba608dbcadbbd9bc2e3dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93lafur=20P=C3=A1ll=20Geirsson?= Date: Mon, 11 Sep 2017 17:53:24 +0200 Subject: [PATCH 5/5] s/last/head/ --- scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala b/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala index 9673c00d12..8cc86d5aef 100644 --- a/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala +++ b/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala @@ -132,7 +132,7 @@ case class SimplifyEitherTLift(index: SemanticdbIndex) .leading(t.tokens.head) .find(_.is[Token.Comma]) } yield { - val leadingSpaces = ctx.tokenList.slice(leadingComma, t.tokens.last) + val leadingSpaces = ctx.tokenList.slice(leadingComma, t.tokens.head) ctx.removeToken(leadingComma) ++ leadingSpaces.map(ctx.removeToken) + ctx.removeTokens(t.tokens)