All Downloads are FREE. Search and download functionalities are using the official Maven repository.

unused_code.RemoveUnusedCode.scala Maven / Gradle / Ivy

The newest version!
package unused_code

import scalafix.v1.XtensionSeqPatch
import metaconfig.Configured
import scalafix.Patch
import scalafix.v1.Configuration
import scalafix.v1.Rule
import scalafix.v1.SyntacticDocument
import scalafix.v1.SyntacticRule
import java.io.File
import java.nio.file.Paths
import scala.meta.XtensionCollectionLikeUI
import scala.meta.XtensionClassifiable
import scala.meta.inputs.Input
import scala.meta.Defn
import scala.meta.Pkg
import scala.meta.Source
import scala.meta.Tree

class RemoveUnusedCode(config: UnusedCodeScalafixConfig) extends SyntacticRule("RemoveUnusedCode") {

  def this() = this(UnusedCodeScalafixConfig.default)

  override def withConfiguration(config: Configuration): Configured[Rule] = {
    config.conf
      .getOrElse(UnusedCodeScalafixConfig.configKey)(this.config)
      .map(newConfig => new RemoveUnusedCode(newConfig))
  }

  private[this] lazy val unusedNames: Set[String] = {
    FindResults.loadFromFile(Paths.get(config.outputPath)).values.map(_.value).toSet
  }

  private[this] def isTopLevel(t: Tree) = {
    t.parent.exists(_.is[Pkg.Body]) || t.parent.exists(_.is[Source])
  }

  override def fix(implicit doc: SyntacticDocument): Patch = {
    val removeAll = doc.tree.collect { case src: Source =>
      src
    }.exists { src =>
      // https://github.com/scala/scala3/blob/93af7b8c7dde6b5a4c29/compiler/src/dotty/tools/dotc/parsing/Parsers.scala#L4601-L4605
      // https://github.com/scala/scala3/blob/93af7b8c7dde6b5a4c29/compiler/src/dotty/tools/dotc/parsing/Parsers.scala#L254-L258
      // https://github.com/scala/scala3/blob/93af7b8c7dde6b5a4c29/compiler/src/dotty/tools/dotc/parsing/Tokens.scala#L244-L248
      val topLevelValues = src.collect {
        case t: Defn.Class if isTopLevel(t) => t
        case t: Defn.Def if isTopLevel(t) => t
        case t: Defn.Enum if isTopLevel(t) => t
        case t: Defn.ExtensionGroup if isTopLevel(t) => t
        case t: Defn.Given if isTopLevel(t) => t
        case t: Defn.GivenAlias if isTopLevel(t) => t
        case t: Defn.Object if isTopLevel(t) => t
        case t: Defn.Trait if isTopLevel(t) => t
        case t: Defn.Type if isTopLevel(t) => t
        case t: Defn.Val if isTopLevel(t) => t
        case t: Defn.Var if isTopLevel(t) => t
        case t: Pkg.Object if isTopLevel(t) => t
      }
      val removeTrees = src.collect(UnusedCode.extractDefineValue).collect {
        case (tree, _, name) if unusedNames.contains(name) =>
          tree
      }
      topLevelValues == removeTrees
    }
    def patch = {
      doc.tree
        .collect(UnusedCode.extractDefineValue)
        .collect {
          case (tree, _, name) if unusedNames.contains(name) =>
            Patch.removeTokens(tree.tokens)
        }
        .asPatch
    }
    if (removeAll) {
      PartialFunction.condOpt(doc.input) {
        case Input.File(path, _) =>
          path.toNIO.toFile
        case Input.VirtualFile(path, _) =>
          new File(path)
      } match {
        case Some(file) if config.removeFile =>
          file.delete()
          Patch.empty
        case _ =>
          patch
      }
    } else {
      patch
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy