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 7ca608aadc0..b7e7dedb02e 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(f, a, b)) => 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(f, a, 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