From 4b4f85d7aa41360d1f1b91a2bef14cc1eb3251e6 Mon Sep 17 00:00:00 2001 From: Albert Meltzer <7529386+kitbellew@users.noreply.github.com> Date: Thu, 23 Nov 2023 09:09:48 -0800 Subject: [PATCH] NeverInfixPattern: implement own matching method Do not use FilterMatcher as it will be insufficient soon. --- .../scalafmt/config/NeverInfixPattern.scala | 52 +++++++++++++++---- .../org/scalafmt/rewrite/AvoidInfix.scala | 13 ++--- 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/NeverInfixPattern.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/NeverInfixPattern.scala index a71c1a8899..5fcbd0762c 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/NeverInfixPattern.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/NeverInfixPattern.scala @@ -3,28 +3,60 @@ package org.scalafmt.config import metaconfig._ import metaconfig.generic.Surface +import java.util.regex.{Matcher, Pattern} + case class NeverInfixPattern( - includeFilters: Seq[String], - excludeFilters: Seq[String] + private val includeFilters: Seq[NeverInfixPattern.Filter], // partial match + private val excludeFilters: Seq[NeverInfixPattern.Filter] // strict match ) { - lazy val matcher: FilterMatcher = new FilterMatcher( - FilterMatcher.mkRegexp(includeFilters), - FilterMatcher.mkRegexp(excludeFilters, true) - ) - private[config] def forSbt: Option[NeverInfixPattern] = // if the user customized these, we don't touch if (excludeFilters ne NeverInfixPattern.default.excludeFilters) None else Some(copy(excludeFilters = NeverInfixPattern.sbtExclude)) + + def matches(op: String): Boolean = + includeFilters.forall(_.matches(op)(_.find())) && + !excludeFilters.exists(_.matches(op)(_.matches())) } object NeverInfixPattern { + + private[config] case class Filter( + op: Pattern + ) { + private def pattern: String = { + op.pattern() + } + def matches(op: String)( + f: Matcher => Boolean + ): Boolean = + f(this.op.matcher(op)) + } + + private object Filter { + implicit lazy val surface: Surface[Filter] = generic.deriveSurface + implicit lazy val encoder: ConfEncoder[Filter] = + ConfEncoder.instance(x => Conf.Str(x.pattern)) + implicit lazy val decoder: ConfDecoderEx[Filter] = + ConfDecoderEx.fromPartial("String") { case (_, Conf.Str(x)) => parse(x) } + + private def parse(str: String): Configured[Filter] = { + val op = str + if (op.isEmpty) Configured.error(s"empty infix op [$str]") + else { + Configured.Ok(Filter(op.r.pattern)) + } + } + + def apply(value: String): Filter = parse(value).get + } + implicit lazy val surface: Surface[NeverInfixPattern] = generic.deriveSurface implicit lazy val codec: ConfCodecEx[NeverInfixPattern] = generic.deriveCodecEx(default).noTypos val default = NeverInfixPattern( - Seq("[\\w\\d_]+"), + Seq("[\\w\\d_]+").map(Filter.apply), Seq( "until", "to", @@ -52,10 +84,10 @@ object NeverInfixPattern { "allElementsOf", "inOrderElementsOf", "theSameElementsAs" - ) + ).map(Filter.apply) ) private val sbtExclude = Seq( "cross" - ) ++ default.excludeFilters + ).map(Filter.apply) ++ default.excludeFilters } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/AvoidInfix.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/AvoidInfix.scala index 314a37a1d6..2941be692a 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/AvoidInfix.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/rewrite/AvoidInfix.scala @@ -4,7 +4,6 @@ import scala.annotation.tailrec import scala.meta._ import scala.meta.internal.trees.PlaceholderChecks.hasPlaceholder -import org.scalafmt.config.FilterMatcher import org.scalafmt.config.RewriteSettings import org.scalafmt.util.InfixApp @@ -16,18 +15,11 @@ object AvoidInfix extends RewriteFactory { override def create(implicit ctx: RewriteCtx): RewriteSession = new AvoidInfix - def getMatcher(ctx: RewriteCtx): FilterMatcher = - ctx.style.rewrite.neverInfix.matcher - - def getMatcherIfEnabled(ctx: RewriteCtx): Option[FilterMatcher] = - if (ctx.style.rewrite.rules.contains(AvoidInfix)) Some(getMatcher(ctx)) - else None - } class AvoidInfix(implicit ctx: RewriteCtx) extends RewriteSession { - private val matcher = AvoidInfix.getMatcher(ctx) + private val matcher = ctx.style.rewrite.neverInfix // In a perfect world, we could just use // Tree.transform { @@ -88,7 +80,8 @@ class AvoidInfix(implicit ctx: RewriteCtx) extends RewriteSession { @tailrec private def checkMatchingInfix(ai: Term.ApplyInfix): Boolean = { val op = ai.op.value - InfixApp.isLeftAssoc(op) && matcher.matches(op) && (ai.argClause match { + InfixApp.isLeftAssoc(op) && matcher.matches(op) && + (ai.argClause match { case ac @ Term.ArgClause(arg :: Nil, _) if !isWrapped(ac) => !hasPlaceholder(arg, ctx.style.rewrite.allowInfixPlaceholderArg) case _ => true