Skip to content

Instantly share code, notes, and snippets.

@xuwei-k
Last active October 25, 2024 22:36
Show Gist options
  • Save xuwei-k/ec14900c3539fe71fbe9c0fe4c94eb25 to your computer and use it in GitHub Desktop.
Save xuwei-k/ec14900c3539fe71fbe9c0fe4c94eb25 to your computer and use it in GitHub Desktop.
package fix
import scala.meta._
import scalafix.v1._
class ImplicitClassExtension extends SyntacticRule("ImplicitClassExtension") {
val exclude: Seq[String] = Seq(
// 書き換えるとoverload衝突する場合や、呼び出しの優先順位変わってエラーになるものなど、
// 下記の条件で除外しきれなかった例外的なものをfile単位で除くためにここに記述
)
override def fix(implicit doc: SyntacticDocument): Patch = {
doc.input match {
case f: Input.VirtualFile if exclude.exists(f.path.contains) =>
Patch.empty
case _ =>
doc.tree.collect {
case t: Defn.Class
if (t.mods.sizeIs == 1) && // implicit以外のmodあると失敗する場合がある(詳細未検証)なので一旦除外
t.mods.exists(_.is[Mod.Implicit]) && // implicitが付与されているか?を確認
(t.ctor.paramClauses.sizeIs == 1) && // 複数のparam clauseがあるとダメだっけ?
t.tparamClause.values.map(_.tbounds).forall(x => x.lo.isEmpty && x.hi.isEmpty) && // context boundなどはダメ?
t.tparamClause.values.forall(_.cbounds.isEmpty) &&
t.templ.stats.nonEmpty && // 滅多にないが何故か稀にbodyが空のもの書き換えるとエラーになるので
t.templ.stats.forall(
_.is[Defn.Def] // 詳細な正確な条件は深く考えてないが、implicit class内部には置けてもextensionにおけないものがあるので、とりあえずdefだけで絞る
) =>
Seq(
Patch.removeTokens(t.name.tokens),
t.ctor.paramClauses
.flatMap(_.values).map(p =>
p.mods.collect {
case m: Mod.ValParam =>
Patch.removeTokens(m.tokens)
case m: Mod.Private =>
Patch.removeTokens(m.tokens)
}.asPatch
).asPatch,
Option
.when(t.templ.inits.nonEmpty) {
Seq(
Patch.removeToken(
t.templ.tokens.find(_.is[Token.KwExtends]).get
),
t.templ.inits.map(_.tokens).map(Patch.removeTokens).asPatch
).asPatch
}.asPatch,
Patch.removeToken(
t.tokens.find(_.is[Token.KwImplicit]).get
),
Patch.replaceToken(
t.tokens.find(_.is[Token.KwClass]).get,
"extension"
)
).asPatch
}.asPatch
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment