Skip to content

Commit

Permalink
AvoidInfixSettings: consolidate AvoidInfix params
Browse files Browse the repository at this point in the history
  • Loading branch information
kitbellew committed Nov 28, 2023
1 parent 434406c commit 6132898
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 27 deletions.
19 changes: 12 additions & 7 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2852,22 +2852,27 @@ This rule replaces infix expressions `a op b` with proper method calls `a.op(b)`
> NB: The rule currently does not support right-associative operators (i.e.,
> those which end in `:`) which would have had to be rewritten as `b.op(a)`.
The rule takes the following parameters:
The rule takes the following parameters under `rewrite.avoidInfix`:

- `rewrite.neverInfix` parameter group which consists of `includeFilters` and `excludeFilters`,
two lists of regular expressions, which determine which operators are eligible for this rewrite
- (since 3.7.18) if a regular expression contains `\\.`, matching will be against
- `includeFilters` and `excludeFilters`, two lists of regular expressions, which
determine which operators are eligible for this rewrite
- for this rule to be enabled (that is, for the rewrite to be applied), an infix
expression must match `includeFilters` and not match `excludeFilters`
- (since 3.8.0) if a regular expression contains `\\.`, matching will be against
not only the infix operator but also its left-hand-side expression (with the
non-empty operator part following the last `\\.` in the pattern)
- (since 3.4.4) `rewrite.allowInfixPlaceholderArg` (default: `true`) will not rewrite infix
- (before 3.8.0) these two parameters were nested under `rewrite.neverInfix`
- `excludePlaceholderArg` (default: `true`) will not rewrite infix
expressions if the argument is a solo placeholder (`_` or `(_: Type)`)
- this parameter does not control any other cases with the infix argument containing a
placeholder character; some of them will never be rewritten as adding parentheses will
change their syntactic meaning, and others will be rewritten as usual
- (before 3.8.0 and since 3.4.4) this parameter was named
`rewrite.allowInfixPlaceholderArg`

```scala mdoc:scalafmt
rewrite.rules = [AvoidInfix]
rewrite.neverInfix.excludeFilters."+" = [ "map" ]
rewrite.avoidInfix.excludeFilters."+" = [ "map" ]
---
a success b
a error (b, c)
Expand All @@ -2885,7 +2890,7 @@ future recover {

```scala mdoc:scalafmt
rewrite.rules = [AvoidInfix]
rewrite.allowInfixPlaceholderArg = false
rewrite.avoidInfix.excludePlaceholderArg = false
---
_ foo _
_ bar (_: Int)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,22 @@ import metaconfig.generic.Surface

import java.util.regex.{Matcher, Pattern}

case class NeverInfixPattern(
private val includeFilters: Seq[NeverInfixPattern.Filter], // partial match
private val excludeFilters: Seq[NeverInfixPattern.Filter] // strict match
case class AvoidInfixSettings(
private val includeFilters: Seq[AvoidInfixSettings.Filter], // partial match
private val excludeFilters: Seq[AvoidInfixSettings.Filter], // strict match
excludePlaceholderArg: Option[Boolean] = None
) {
private[config] def forSbt: Option[NeverInfixPattern] =
private[config] def forSbt: Option[AvoidInfixSettings] =
// if the user customized these, we don't touch
if (excludeFilters ne NeverInfixPattern.default.excludeFilters) None
else Some(copy(excludeFilters = NeverInfixPattern.sbtExclude))
if (excludeFilters ne AvoidInfixSettings.default.excludeFilters) None
else Some(copy(excludeFilters = AvoidInfixSettings.sbtExclude))

def matches(lhs: String, op: String): Boolean =
includeFilters.forall(_.matches(lhs, op)(_.find())) &&
!excludeFilters.exists(_.matches(lhs, op)(_.matches()))
}

object NeverInfixPattern {
object AvoidInfixSettings {

private[config] case class Filter(
lhs: Option[Pattern],
Expand Down Expand Up @@ -55,11 +56,11 @@ object NeverInfixPattern {
def apply(value: String): Filter = parse(value).get
}

implicit lazy val surface: Surface[NeverInfixPattern] =
implicit lazy val surface: Surface[AvoidInfixSettings] =
generic.deriveSurface
implicit lazy val codec: ConfCodecEx[NeverInfixPattern] =
implicit lazy val codec: ConfCodecEx[AvoidInfixSettings] =
generic.deriveCodecEx(default).noTypos
val default = NeverInfixPattern(
val default = AvoidInfixSettings(
Seq("[\\w\\d_]+").map(Filter.apply),
Seq(
"until",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,18 @@ case class RewriteSettings(
imports: Imports.Settings = Imports.Settings(),
preferCurlyFors: PreferCurlyFors.Settings = PreferCurlyFors.Settings(),
trailingCommas: TrailingCommas = TrailingCommas(),
allowInfixPlaceholderArg: Boolean = true,
neverInfix: NeverInfixPattern = NeverInfixPattern.default
@annotation.DeprecatedName(
"allowInfixPlaceholderArg",
"Use `avoidInfix.excludePlaceholderArg` instead",
"3.8.0"
)
private val allowInfixPlaceholderArg: Boolean = true,
@annotation.ExtraName("neverInfix")
avoidInfix: AvoidInfixSettings = AvoidInfixSettings.default
) {
def isAllowInfixPlaceholderArg: Boolean =
avoidInfix.excludePlaceholderArg.getOrElse(allowInfixPlaceholderArg)

def withoutRewrites: RewriteSettings =
copy(rules = Nil, trailingCommas = trailingCommas.withoutRewrites)

Expand All @@ -33,7 +42,7 @@ case class RewriteSettings(
}

private[config] def forSbt: RewriteSettings =
neverInfix.forSbt.fold(this)(x => copy(neverInfix = x))
avoidInfix.forSbt.fold(this)(x => copy(avoidInfix = x))
}

object RewriteSettings {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.scalafmt.util.InfixApp
object AvoidInfix extends RewriteFactory {

override def hasChanged(v1: RewriteSettings, v2: RewriteSettings): Boolean =
v2.neverInfix ne v1.neverInfix
v2.avoidInfix ne v1.avoidInfix

override def create(implicit ctx: RewriteCtx): RewriteSession =
new AvoidInfix
Expand All @@ -20,7 +20,7 @@ object AvoidInfix extends RewriteFactory {

class AvoidInfix(implicit ctx: RewriteCtx) extends RewriteSession {

private val matcher = ctx.style.rewrite.neverInfix
private val matcher = ctx.style.rewrite.avoidInfix

// In a perfect world, we could just use
// Tree.transform {
Expand Down Expand Up @@ -88,7 +88,7 @@ class AvoidInfix(implicit ctx: RewriteCtx) extends RewriteSession {
InfixApp.isLeftAssoc(op) && matcher.matches(lhs, op) &&
(ai.argClause match {
case ac @ Term.ArgClause(arg :: Nil, _) if !isWrapped(ac) =>
!hasPlaceholder(arg, ctx.style.rewrite.allowInfixPlaceholderArg)
!hasPlaceholder(arg, ctx.style.rewrite.isAllowInfixPlaceholderArg)
case _ => true
}) && (ai.lhs match {
case lhs: Term.ApplyInfix if hasPlaceholder(lhs, true) =>
Expand Down
8 changes: 4 additions & 4 deletions scalafmt-tests/src/test/resources/rewrite/AvoidInfix.stat
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ object a {
_.foo(bar).baz(qux)
}
<<< in lambda 2, !allowInfixPlaceholderArg
rewrite.allowInfixPlaceholderArg = false
rewrite.neverInfix {
rewrite.avoidInfix {
excludePlaceholderArg = false
includeFilters = [ "[^*]+" ]
excludeFilters = []
}
Expand Down Expand Up @@ -219,8 +219,8 @@ object a {
b.c(1./(2).+(3))
}
<<< in lambda 2, allowInfixPlaceholderArg
rewrite.allowInfixPlaceholderArg = true
rewrite.neverInfix {
rewrite.avoidInfix {
excludePlaceholderArg = true
includeFilters = [ "[^*]+" ]
excludeFilters = []
}
Expand Down

0 comments on commit 6132898

Please sign in to comment.