How to get rid of Dropped Class Shadowing in Scala 3 Migration

Scala 3 dropped class shadowing, so we need to rename some traits to migrate to scala3.

It is not an easy task when there are many such traits.

class Base {
  trait Card { }
}

class Sub extends Base {
  trait Card extends super.card{ }
}

Stage 1

We should initially refactor the base modules in a way that allows refactoring of the submodules without causing any disruptions.

class Base {
   //mark for scalafix
  @Scala2Only
  trait Card { 
    //new name
    private def useInsted:"BaseCard" = "BaseCard"
  }
  // type to rename
  type BaseCard = Card
}

Stage 2

Run scala fix on submodules.
It will remove deprecated names:

class Sub extends Base {
  trait Card extends BaseCard
}

Scalafix example:

package fix

import scalafix.v1.{XtensionTreeScalafix, _}

import scala.meta._

class UpdateAvi extends SemanticRule("UpdateAvi") {
  override def fix(implicit doc: SemanticDocument): Patch = {
    Patch.fromIterable {
      doc.tree.collect { case traitDef: Defn.Trait =>
        traitDef.templ.inits.flatMap { init =>
          val newInitNameOpt = findReplacementName(
            parentSymbol = init.tpe.symbol
          )
          newInitNameOpt.map { newInitName =>
            Patch.replaceTree(init.tpe, newInitName)
          }
        }
      }.flatten
    }
  }

  private def findReplacementName(parentSymbol: Symbol)(implicit doc: SemanticDocument): Option[String] = {
    parentSymbol.info.flatMap { info =>
      lazy val hasAnnotate = (name: String) => info.annotations.exists(_.tpe.toString() == name)

      if (hasAnnotate("Scala2OnlyDvi")) {
        Some(s"Dvi${parentSymbol.displayName}")
      } else if (hasAnnotate("Scala2Only")) {
        info.signature match {
          case ClassSignature(_, _, _, declarations) =>
            declarations.collectFirst {
              case decl if decl.displayName == "useInstead" =>
                decl.signature.asInstanceOf[MethodSignature].returnType.asInstanceOf[ConstantType].constant.asInstanceOf[StringConstant].value
            }
          case _ => None
        }
      } else None
    }
  }
}

Stage 3

Remove deprecaded code in base modules:

class Base {
  trait BaseCard{ }
}