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

scalafix.internal.rule.RuleCtxImpl.scala Maven / Gradle / Ivy

package scalafix.internal.rule

import scala.meta._
import scala.meta.contrib.AssociatedComments
import scala.meta.tokens.Tokens
import scalafix.LintMessage
import scalafix._
import scalafix.internal.config.ScalafixConfig
import scalafix.internal.config.ScalafixMetaconfigReaders
import scalafix.internal.diff.DiffDisable
import scalafix.internal.patch.EscapeHatch
import scalafix.internal.util.SymbolOps.Root
import scalafix.patch.LintPatch
import scalafix.patch.TokenPatch
import scalafix.patch.TokenPatch.Add
import scalafix.patch.TreePatch
import scalafix.patch.TreePatch.AddGlobalImport
import scalafix.patch.TreePatch.RemoveGlobalImport
import scalafix.rule.RuleCtx
import scalafix.rule.RuleName
import scalafix.syntax._
import scalafix.util.MatchingParens
import scalafix.util.SemanticdbIndex
import scalafix.util.TokenList

import org.scalameta.FileLine
import org.scalameta.logger

case class RuleCtxImpl(
    tree: Tree,
    config: ScalafixConfig,
    diffDisable: DiffDisable)
    extends RuleCtx {
  ctx =>
  def syntax: String =
    s"""${tree.input.syntax}
       |${logger.revealWhitespace(tree.syntax.take(100))}""".stripMargin
  override def toString: String = syntax
  def toks(t: Tree): Tokens = t.tokens(config.dialect)
  lazy val tokens: Tokens = tree.tokens(config.dialect)
  lazy val tokenList: TokenList = TokenList(tokens)
  lazy val matchingParens: MatchingParens = MatchingParens(tokens)
  lazy val comments: AssociatedComments = AssociatedComments(tokens)
  lazy val input: Input = tokens.head.input
  lazy val escapeHatch: EscapeHatch = EscapeHatch(tree, comments)

  // Debug utilities
  def index(implicit index: SemanticdbIndex): SemanticdbIndex =
    index.withDocuments(index.documents.filter(_.input == input))
  def debugIndex()(
      implicit index: SemanticdbIndex,
      fileLine: FileLine): Unit = {
    val db = this.index(index)
    debug(sourcecode.Text(db.documents.head, "index"))
  }
  def debug(values: sourcecode.Text[Any]*)(
      implicit fileLine: FileLine): Unit = {
    // alias for org.scalameta.logger.
    logger.elem(values: _*)
  }

  def printLintMessage(msg: LintMessage): Unit = {
    val category = msg.category.withConfig(config.lint)

    config.lint.reporter.handleMessage(
      msg.format(config.lint.explain),
      msg.position,
      category.severity.toSeverity
    )
  }

  def filter(
      patchesByName: Map[RuleName, Patch],
      index: SemanticdbIndex): (Patch, List[LintMessage]) =
    escapeHatch.filter(patchesByName, this, index, diffDisable)

  def lint(msg: LintMessage): Patch =
    LintPatch(msg)

  // Syntactic patch ops.
  def removeImportee(importee: Importee): Patch =
    TreePatch.RemoveImportee(importee)
  def addGlobalImport(importer: Importer): Patch =
    AddGlobalImport(importer)
  def replaceToken(token: Token, toReplace: String): Patch =
    Add(token, "", toReplace, keepTok = false)
  def removeTokens(tokens: Tokens): Patch =
    doRemoveTokens(tokens)
  def removeTokens(tokens: Iterable[Token]): Patch =
    doRemoveTokens(tokens)
  private def doRemoveTokens(tokens: Iterable[Token]): Patch =
    tokens.foldLeft(Patch.empty)(_ + TokenPatch.Remove(_))
  def removeToken(token: Token): Patch = Add(token, "", "", keepTok = false)
  def replaceTree(from: Tree, to: String): Patch = {
    val tokens = toks(from)
    removeTokens(tokens) + tokens.headOption.map(x => addRight(x, to))
  }
  def addRight(tok: Token, toAdd: String): Patch = Add(tok, "", toAdd)
  def addRight(tree: Tree, toAdd: String): Patch =
    toks(tree).lastOption.fold(Patch.empty)(addRight(_, toAdd))
  def addLeft(tok: Token, toAdd: String): Patch = Add(tok, toAdd, "")
  def addLeft(tree: Tree, toAdd: String): Patch =
    toks(tree).headOption.fold(Patch.empty)(addLeft(_, toAdd))

  // Semantic patch ops.
  def removeGlobalImport(symbol: Symbol)(
      implicit index: SemanticdbIndex): Patch =
    RemoveGlobalImport(symbol)
  def addGlobalImport(symbol: Symbol)(implicit index: SemanticdbIndex): Patch =
    TreePatch.AddGlobalSymbol(symbol)
  def replaceSymbol(fromSymbol: Symbol.Global, toSymbol: Symbol.Global)(
      implicit index: SemanticdbIndex): Patch =
    TreePatch.ReplaceSymbol(fromSymbol, toSymbol)
  def replaceSymbols(toReplace: (String, String)*)(
      implicit index: SemanticdbIndex): Patch =
    toReplace.foldLeft(Patch.empty) {
      case (a, (from, to)) =>
        val (fromSymbol, toSymbol) =
          ScalafixMetaconfigReaders.parseReplaceSymbol(from, to).get
        a + ctx.replaceSymbol(fromSymbol, toSymbol)
    }
  def replaceSymbols(toReplace: Seq[(String, String)])(
      implicit noop: DummyImplicit,
      index: SemanticdbIndex): Patch = {
    replaceSymbols(toReplace: _*)
  }
  def renameSymbol(fromSymbol: Symbol.Global, toName: String)(
      implicit index: SemanticdbIndex): Patch =
    TreePatch.ReplaceSymbol(fromSymbol, Root(Signature.Term(toName)))

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy