|
| 1 | +package fix |
| 2 | + |
| 3 | +import fix.ImplicitConversions.LastImplicitTypeFunctionParams |
| 4 | +import scalafix.v1.{Patch, SemanticDocument, SemanticRule} |
| 5 | + |
| 6 | +import scala.meta._ |
| 7 | +import scala.meta.tokens.Token |
| 8 | + |
| 9 | +class ImplicitConversions extends SemanticRule("ImplicitConversions") { |
| 10 | + |
| 11 | + override def fix(implicit doc: SemanticDocument): Patch = { |
| 12 | + |
| 13 | + doc.tree.collect { |
| 14 | + case Defn.Def(_, _, _, LastImplicitTypeFunctionParams(typeFunctions), _, _) => |
| 15 | + typeFunctions.foldRight(Patch.empty) { case (tf, patches) => |
| 16 | + patches + Patch.replaceTree(tf, conversionCode(tf.params, tf.res)) |
| 17 | + } |
| 18 | + |
| 19 | + case d @ Defn.Def(mods, Term.Name(_), _, (firstParam :: Nil) :: Nil, ot @ Some(outType: Type.Name), _) |
| 20 | + if mods.exists(_.is[Mod.Implicit]) && firstParam.mods.forall(_.isNot[Mod.Implicit]) => |
| 21 | + (for { |
| 22 | + defkw <- d.tokens.find(_.is[Token.KwDef]).map(Patch.replaceToken(_, "val")) |
| 23 | + eqSign <- d.tokens.find(_.is[Token.Equals]) |
| 24 | + returnTypeTree <- ot |
| 25 | + retType <- firstParam.decltpe |
| 26 | + argTokens = d.tokens.dropWhile(_.isNot[Token.LeftParen]).dropRightWhile(_.isNot[Token.RightParen]) |
| 27 | + } yield defkw + |
| 28 | + Patch.removeTokens(argTokens) + |
| 29 | + Patch.addRight(eqSign, s" ${argTokens.toString()} =>") + |
| 30 | + Patch.replaceTree(returnTypeTree, conversionCode(retType, outType))).asPatch |
| 31 | + |
| 32 | + case Defn.Val(mods, _, Some(ts: Type.Function), _) if mods.exists(_.is[Mod.Implicit]) => |
| 33 | + ts.params match { |
| 34 | + case inType :: Nil => Patch.replaceTree(ts, conversionCode(inType, ts.res)) |
| 35 | + case _ => Patch.empty |
| 36 | + } |
| 37 | + }.asPatch |
| 38 | + } |
| 39 | + |
| 40 | + private def conversionCode(inType: Type, retType: Type): String = |
| 41 | + conversionCode(inType :: Nil, retType) |
| 42 | + |
| 43 | + private def conversionCode(inType: List[Type], retType: Type): String = { |
| 44 | + val inStr = inType match { |
| 45 | + case one :: Nil => one.toString() |
| 46 | + case many => many.map(_.toString()).mkString("(", ", ", ")") |
| 47 | + } |
| 48 | + s"Conversion[$inStr, $retType]" |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | +object ImplicitConversions { |
| 53 | + |
| 54 | + object LastImplicitTypeFunctionParams { |
| 55 | + def unapply(params: List[List[Term.Param]]): Option[List[Type.Function]] = { |
| 56 | + val lastParams = params.lastOption |
| 57 | + if (lastParams.exists(_.exists(_.mods.exists(_.is[Mod.Implicit])))) { |
| 58 | + val tfs = lastParams.toList |
| 59 | + .flatMap(_.map(_.decltpe)) |
| 60 | + .collect { case Some(tf: Type.Function) => tf } |
| 61 | + if (tfs.isEmpty) None |
| 62 | + else Some(tfs) |
| 63 | + } else None |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | +} |
0 commit comments