Skip to content

Commit

Permalink
Add Rewrite.init, fixes scalacenter#261.
Browse files Browse the repository at this point in the history
This method can be used to do any sort of preprocessing before fixing
files. For example, a rewrite that does dead-code elimination.could
build a call graph in `init`.
  • Loading branch information
olafurpg committed Aug 30, 2017
1 parent 84314da commit 04daff3
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,8 @@ case class ScalafixConfig(
reporter: ScalafixReporter = ScalafixReporter.default,
patches: ConfigRewritePatches = ConfigRewritePatches.default,
dialect: Dialect = Scala211,
// Custom configuration for rewrites.
// Feel free to read data from here if your custom rewrite needs
// configuration from the user.
x: Conf = Conf.Obj(),
explicitReturnTypes: ExplicitReturnTypesConfig = ExplicitReturnTypesConfig(),
lint: LintConfig = LintConfig.default
) {
def getRewriteConfig[T: ConfDecoder](key: String, default: T): T = {
x.getOrElse[T](key)(default).get
}

def withFreshReporters: ScalafixConfig = copy(
reporter = reporter.reset,
Expand All @@ -41,19 +33,15 @@ case class ScalafixConfig(
getOrElse("reporter")(reporter) |@|
getOrElse("patches")(patches)(patches.reader) |@|
getOrElse("dialect")(dialect) |@|
getOrElse("x")(x) |@|
getOrElse("explicitReturnTypes")(explicitReturnTypes) |@|
getOrElse("lint")(lint)(lint.reader)
).map {
case ((((((a, b), c), d), e), f), g) =>
case ((((a, b), c), d), e) =>
copy(
fatalWarnings = a,
reporter = b,
patches = c,
dialect = d,
x = e,
explicitReturnTypes = f,
lint = g
lint = e
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ trait ScalafixMetaconfigReaders {
hoconParser.fromInput(input).andThen { conf =>
scalafixConfigConfDecoder(decoder, extraRewrites)
.read(conf)
.andThen {
// Initialize configuration
case (rewrite, config) => rewrite.init(conf).map(_ -> config)
}
.andThen {
case (rewrite, config) =>
ConfigRewrite(config.patches, sctx).map { configRewrite =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,28 @@ import scala.meta.contrib._
import scala.meta.internal.scalafix.ScalafixScalametaHacks
import scalafix.Patch
import scalafix.SemanticCtx
import scalafix.internal.config.ExplicitReturnTypesConfig
import scalafix.internal.config.MemberKind
import scalafix.internal.config.MemberVisibility
import scalafix.rewrite.Rewrite
import scalafix.rewrite.RewriteCtx
import scalafix.rewrite.SemanticRewrite
import scalafix.syntax._
import scalafix.util.TokenOps
import metaconfig.Conf
import metaconfig.Configured

case class ExplicitReturnTypes(sctx: SemanticCtx)
case class ExplicitReturnTypes(
sctx: SemanticCtx,
config: ExplicitReturnTypesConfig = ExplicitReturnTypesConfig.default)
extends SemanticRewrite(sctx) {
def this(sctx: SemanticCtx) = this(sctx, ExplicitReturnTypesConfig.default)

override def init(config: Conf): Configured[Rewrite] =
config.dynamic.explicitReturnTypes.as[ExplicitReturnTypesConfig].map { c =>
ExplicitReturnTypes(sctx, c)
}

// Don't explicitly annotate vals when the right-hand body is a single call
// to `implicitly`. Prevents ambiguous implicit. Not annotating in such cases,
// this a common trick employed implicit-heavy code to workaround SI-2712.
Expand Down Expand Up @@ -75,7 +88,6 @@ case class ExplicitReturnTypes(sctx: SemanticCtx)

override def rewrite(ctx: RewriteCtx): Patch = {
import scala.meta._
import ctx._
def fix(defn: Defn, body: Term): Seq[Patch] = {
val lst = ctx.tokenList
import lst._
Expand All @@ -102,8 +114,7 @@ case class ExplicitReturnTypes(sctx: SemanticCtx)
defn: D,
mods: Traversable[Mod],
body: Term)(implicit ev: Extract[D, Mod]): Boolean = {
val config = ctx.config
import config.explicitReturnTypes._
import config._

def matchesMemberVisibility(): Boolean =
memberVisibility.contains(visibility(mods))
Expand All @@ -121,7 +132,7 @@ case class ExplicitReturnTypes(sctx: SemanticCtx)
matchesMemberVisibility()
}

tree
ctx.tree
.collect {
case t @ Defn.Val(mods, _, None, body)
if isRewriteCandidate(t, mods, body) =>
Expand Down
19 changes: 19 additions & 0 deletions scalafix-core/shared/src/main/scala/scalafix/rewrite/Rewrite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import scala.meta._
import scalafix.internal.config.ScalafixMetaconfigReaders
import scalafix.internal.config.ScalafixConfig
import scalafix.syntax._
import metaconfig.Conf
import metaconfig.ConfDecoder
import metaconfig.Configured

Expand All @@ -18,6 +19,19 @@ abstract class Rewrite(implicit val rewriteName: RewriteName) { self =>
*/
def rewrite(ctx: RewriteCtx): Patch

/** Initialize rewrite.
*
* This method is called once by scalafix before rewrite is called.
* Use this method to either read custom configuration or to build
* expensive indices.
*
* @param config The .scalafix.conf configuration.
* @return the initialized rewrite or an error. If no initialization is needed,
* return Configured.Ok(this).
*/
def init(config: Conf): Configured[Rewrite] =
Configured.Ok(this)

/** Combine this rewrite with another rewrite. */
final def andThen(other: Rewrite): Rewrite = Rewrite.merge(this, other)

Expand Down Expand Up @@ -105,6 +119,11 @@ object Rewrite {
/** Combine two rewrites into a single rewrite */
def merge(a: Rewrite, b: Rewrite): Rewrite = {
new Rewrite()(a.rewriteName + b.rewriteName) {
override def init(config: Conf): Configured[Rewrite] = {
a.init(config).product(b.init(config)).map {
case (x, y) => merge(x, y)
}
}
override def rewrite(ctx: RewriteCtx): Patch =
a.rewrite(ctx) + b.rewrite(ctx)
override def semanticOption: Option[SemanticCtx] =
Expand Down

0 comments on commit 04daff3

Please sign in to comment.