diff --git a/readme/ImplementingRewrites.scalatex b/readme/ImplementingRewrites.scalatex index 89a1b489e..e87a4cc8e 100644 --- a/readme/ImplementingRewrites.scalatex +++ b/readme/ImplementingRewrites.scalatex @@ -102,7 +102,7 @@ on parsed abstract syntax tree nodes. The public API for patch operations is available in PatchOps.scala - @hl.ref(wd/"scalafix-core"/"shared"/"src"/"main"/"scala"/"scalafix"/"patch"/"PatchOps.scala", start = "class SyntacticPatch") + @hl.ref(wd/"scalafix-core"/"shared"/"src"/"main"/"scala"/"scalafix"/"patch"/"PatchOps.scala", start = "trait PatchOps") Some things are typically easier to do on the token level and other things are easier to do on the tree level. diff --git a/scalafix-core/shared/src/main/scala/scalafix/package.scala b/scalafix-core/shared/src/main/scala/scalafix/package.scala index bd3dff9ea..a1c3f35c2 100644 --- a/scalafix-core/shared/src/main/scala/scalafix/package.scala +++ b/scalafix-core/shared/src/main/scala/scalafix/package.scala @@ -1,6 +1,4 @@ import scala.meta._ -import scalafix.patch.SemanticPatchOps -import scalafix.patch.SyntacticPatchOps package object scalafix { @@ -17,15 +15,6 @@ package object scalafix { type Patch = patch.Patch val Patch = patch.Patch - implicit class XtensionMirrorRewriteCtx(val ctx: RewriteCtx)( - implicit val mirror: Mirror) - extends SemanticPatchOps(ctx, mirror) { - def semanticOps: SemanticPatchOps = this - } - implicit class XtensionRewriteCtx(val ctx: RewriteCtx) - extends SyntacticPatchOps(ctx) { - def semanticOps: SyntacticPatchOps = this - } implicit class XtensionSeqPatch(patches: Iterable[Patch]) { def asPatch: Patch = Patch.fromIterable(patches) } diff --git a/scalafix-core/shared/src/main/scala/scalafix/patch/ImportPatchOps.scala b/scalafix-core/shared/src/main/scala/scalafix/patch/ImportPatchOps.scala index 0afb1ebfb..7774cf005 100644 --- a/scalafix-core/shared/src/main/scala/scalafix/patch/ImportPatchOps.scala +++ b/scalafix-core/shared/src/main/scala/scalafix/patch/ImportPatchOps.scala @@ -102,7 +102,7 @@ object ImportPatchOps { val trailingComma = if (hadLeadingComma) List(Patch.empty) else removeFirstComma(ctx.tokenList.trailing(tokens.last)) - PatchOps.removeTokens(tokens) ++ trailingComma ++ leadingComma + ctx.removeTokens(tokens) ++ trailingComma ++ leadingComma } val leadingNewlines = isRemovedImport.map { i => diff --git a/scalafix-core/shared/src/main/scala/scalafix/patch/PatchOps.scala b/scalafix-core/shared/src/main/scala/scalafix/patch/PatchOps.scala index b1bd9839c..a25b0fa2a 100644 --- a/scalafix-core/shared/src/main/scala/scalafix/patch/PatchOps.scala +++ b/scalafix-core/shared/src/main/scala/scalafix/patch/PatchOps.scala @@ -3,35 +3,25 @@ package scalafix package patch import scala.meta._ -import scalafix.patch.TokenPatch._ -import scalafix.patch.TreePatch._ import org.scalameta.FileLine -import org.scalameta.logger -object PatchOps { - def removeTokens(tokens: Tokens): Patch = tokens.foldLeft(Patch.empty)(_ + TokenPatch.Remove(_)) -} - -class SyntacticPatchOps(ctx: RewriteCtx) { - def removeImportee(importee: Importee): Patch = TreePatch.RemoveImportee(importee) - def replaceToken(token: Token, toReplace: String): Patch = - Add(token, "", toReplace, keepTok = false) - def removeTokens(tokens: Tokens): Patch = PatchOps.removeTokens(tokens) - def removeToken(token: Token): Patch = Add(token, "", "", keepTok = false) - def rename(from: Name, to: Name)(implicit fileLine: FileLine): Patch = - ctx.toks(from).headOption.fold(Patch.empty)(tok => Add(tok, "", to.value, keepTok = false)) - def addRight(tok: Token, toAdd: String): Patch = Add(tok, "", toAdd) - def addLeft(tok: Token, toAdd: String): Patch = Add(tok, toAdd, "") -} +trait PatchOps { + // Syntactic patch ops. + def removeImportee(importee: Importee): Patch + def replaceToken(token: Token, toReplace: String): Patch + def removeTokens(tokens: Tokens): Patch + def removeToken(token: Token): Patch + def rename(from: Name, to: Name)(implicit fileLine: FileLine): Patch + def addRight(tok: Token, toAdd: String): Patch + def addLeft(tok: Token, toAdd: String): Patch -class SemanticPatchOps(ctx: RewriteCtx, mirror: Mirror) { - def removeGlobalImport(symbol: Symbol): Patch = RemoveGlobalImport(symbol) - def addGlobalImport(importer: Importer): Patch = AddGlobalImport(importer) + // Semantic patch ops. + def removeGlobalImport(symbol: Symbol)(implicit mirror: Mirror): Patch + def addGlobalImport(importer: Importer)(implicit mirror: Mirror): Patch def replace(from: Symbol, to: Term.Ref, additionalImports: List[Importer] = Nil, - normalized: Boolean = true): Patch = - Replace(from, to, additionalImports, normalized) - def renameSymbol(from: Symbol, to: Name, normalize: Boolean = false): Patch = - RenameSymbol(from, to, normalize) + normalized: Boolean = true)(implicit mirror: Mirror): Patch + def renameSymbol(from: Symbol, to: Name, normalize: Boolean = true)( + implicit mirror: Mirror): Patch } diff --git a/scalafix-core/shared/src/main/scala/scalafix/rewrite/RewriteCtx.scala b/scalafix-core/shared/src/main/scala/scalafix/rewrite/RewriteCtx.scala index deb57c73e..898926682 100644 --- a/scalafix-core/shared/src/main/scala/scalafix/rewrite/RewriteCtx.scala +++ b/scalafix-core/shared/src/main/scala/scalafix/rewrite/RewriteCtx.scala @@ -1,6 +1,6 @@ package scalafix package rewrite -import scala.meta.Tree +import scala.meta._ import scala.meta.contrib.AssociatedComments import scala.meta.inputs.Input import scala.meta.io.AbsolutePath @@ -8,13 +8,20 @@ import scala.meta.tokens.Tokens import scalafix.syntax._ import scalafix.config.ScalafixConfig import scalafix.config.ScalafixReporter +import scalafix.patch.PatchOps +import scalafix.patch.TokenPatch +import scalafix.patch.TokenPatch.Add +import scalafix.patch.TreePatch +import scalafix.patch.TreePatch._ import scalafix.util.MatchingParens import scalafix.util.TokenList +import org.scalameta.FileLine import org.scalameta.logger /** Bundle of useful things when implementing [[Rewrite]]. */ -case class RewriteCtx(tree: Tree, config: ScalafixConfig) { - def syntax = +case class RewriteCtx(tree: Tree, config: ScalafixConfig) extends PatchOps { + ctx => + def syntax: String = s"""${tree.input.syntax} |${logger.revealWhitespace(tree.syntax.take(100))}""".stripMargin override def toString: String = syntax @@ -24,4 +31,34 @@ case class RewriteCtx(tree: Tree, config: ScalafixConfig) { lazy val matching: MatchingParens = MatchingParens(tokens) lazy val comments: AssociatedComments = AssociatedComments(tokens) val reporter: ScalafixReporter = config.reporter + + // Syntactic patch ops. + def removeImportee(importee: Importee): Patch = + TreePatch.RemoveImportee(importee) + def replaceToken(token: Token, toReplace: String): Patch = + Add(token, "", toReplace, keepTok = false) + def removeTokens(tokens: Tokens): Patch = + tokens.foldLeft(Patch.empty)(_ + TokenPatch.Remove(_)) + def removeToken(token: Token): Patch = Add(token, "", "", keepTok = false) + def rename(from: Name, to: Name)(implicit fileLine: FileLine): Patch = + ctx + .toks(from) + .headOption + .fold(Patch.empty)(tok => Add(tok, "", to.value, keepTok = false)) + def addRight(tok: Token, toAdd: String): Patch = Add(tok, "", toAdd) + def addLeft(tok: Token, toAdd: String): Patch = Add(tok, toAdd, "") + + // Semantic patch ops. + def removeGlobalImport(symbol: Symbol)(implicit mirror: Mirror): Patch = + RemoveGlobalImport(symbol) + def addGlobalImport(importer: Importer)(implicit mirror: Mirror): Patch = + AddGlobalImport(importer) + def replace(from: Symbol, + to: Term.Ref, + additionalImports: List[Importer] = Nil, + normalized: Boolean = true)(implicit mirror: Mirror): Patch = + Replace(from, to, additionalImports, normalized) + def renameSymbol(from: Symbol, to: Name, normalize: Boolean = false)( + implicit mirror: Mirror): Patch = + RenameSymbol(from, to, normalize) }