diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Align.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Align.scala index 18a3556245..803f8b1f06 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Align.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/Align.scala @@ -1,5 +1,7 @@ package org.scalafmt.config +import scala.meta._ + import metaconfig._ import metaconfig.annotation.ExtraName import metaconfig.generic.Surface @@ -102,13 +104,17 @@ case class Align( "Enumerator.Val" -> "for", ), ) { - def getOpenParenTupleSite = openParenTupleSite.getOrElse(openParenCallSite) - def getOpenDelimSite(bracket: Boolean, defnSite: Boolean): Boolean = - if (defnSite) (if (bracket) openBracketDefnSite else None) - .getOrElse(openParenDefnSite) - else (if (bracket) openBracketCallSite else None) - .getOrElse(openParenCallSite) + def atDefnSite(owner: Tree): Boolean = (owner match { + case _: Type.ParamClause => openBracketDefnSite + case _ => None + }).getOrElse(openParenDefnSite) + + def atCallSite(owner: Tree): Boolean = (owner match { + case _: Member.Tuple => openParenTupleSite + case _: Type.ArgClause => openBracketCallSite + case _ => None + }).getOrElse(openParenCallSite) } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/DanglingParentheses.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/DanglingParentheses.scala index 0a367e7b20..a3be3d995e 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/config/DanglingParentheses.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/config/DanglingParentheses.scala @@ -31,8 +31,10 @@ case class DanglingParentheses( @inline def atDefnSite(lpOwner: Tree): Boolean = - (if (lpOwner.is[Type.ParamClause]) atBracketDefnSite else defnSite) && - isExcluded(lpOwner) + (lpOwner match { + case _: Type.ParamClause => atBracketDefnSite + case _ => defnSite + }) && isExcluded(lpOwner) @inline def atVerticalMultilineSite(lpOwner: Tree): Boolean = defnSite && diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala index d002c7c459..31d010181d 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/FormatOps.scala @@ -863,9 +863,10 @@ class FormatOps( allowForce: Boolean = true, )(implicit style: ScalafmtConfig, - cfg: Newlines.ConfigStyleElement, + clauseSiteFlags: ClauseSiteFlags, ): ConfigStyle = - if (allowForce && mustForceConfigStyle(ft)) ConfigStyle.Forced + if (allowForce && mustForceConfigStyle(ft)(clauseSiteFlags.configStyle)) + ConfigStyle.Forced else if (preserveConfigStyle(ft, breakBeforeClose)) ConfigStyle.Source else ConfigStyle.None @@ -873,11 +874,12 @@ class FormatOps( cfg: Newlines.ConfigStyleElement, ): Boolean = cfg.getForceIfOptimized && forceConfigStyle(ft.meta.idx) - def preserveConfigStyle( - ft: FormatToken, - breakBeforeClose: => Boolean, - )(implicit style: ScalafmtConfig, cfg: Newlines.ConfigStyleElement): Boolean = - cfg.prefer && couldPreserveConfigStyle(ft, breakBeforeClose) + def preserveConfigStyle(ft: FormatToken, breakBeforeClose: => Boolean)( + implicit + style: ScalafmtConfig, + clauseSiteFlags: ClauseSiteFlags, + ): Boolean = clauseSiteFlags.configStyle.prefer && + couldPreserveConfigStyle(ft, breakBeforeClose) def couldPreserveConfigStyle(ft: FormatToken, breakBeforeClose: => Boolean)( implicit style: ScalafmtConfig, @@ -2642,24 +2644,20 @@ class FormatOps( def getBinpackCallsiteFlags( ftAfterOpen: FormatToken, ftBeforeClose: FormatToken, - )(implicit style: ScalafmtConfig) = { + )(implicit style: ScalafmtConfig, clauseSiteFlags: ClauseSiteFlags) = { val literalArgList = styleMap.opensLiteralArgumentList(ftAfterOpen) val dangleForTrailingCommas = getMustDangleForTrailingCommas(ftBeforeClose) - implicit val configStyleFlags = style.configStyleCallSite val configStyle = if (dangleForTrailingCommas) ConfigStyle.None else mustUseConfigStyle(ftAfterOpen, ftBeforeClose.hasBreak, !literalArgList) - val shouldDangle = style.danglingParentheses - .atCallSite(ftAfterOpen.meta.leftOwner) val scalaJsStyle = style.newlines.source == Newlines.classic && - configStyle == ConfigStyle.None && !configStyleFlags.prefer && - !literalArgList && shouldDangle + configStyle == ConfigStyle.None && !literalArgList && + clauseSiteFlags.dangleCloseDelim && !clauseSiteFlags.configStyle.prefer BinpackCallsiteFlags( literalArgList = literalArgList, dangleForTrailingCommas = dangleForTrailingCommas, configStyle = configStyle, - shouldDangle = shouldDangle, scalaJsStyle = scalaJsStyle, ) } @@ -2676,10 +2674,11 @@ class FormatOps( isArgClauseSite(ftAfterClose.meta.rightOwner) if (continue) { val open = tokens.matching(ftAfterClose.right) - val styleAtOpen = styleMap.at(open) - val bpFlagsAfter = - getBinpackCallsiteFlags(tokens(open), ftAfterClose)(styleAtOpen) - scalaJsOptClose(ftAfterClose, bpFlagsAfter)(styleAtOpen) + implicit val style: ScalafmtConfig = styleMap.at(open) // override implicit + implicit val clauseSiteFlags: ClauseSiteFlags = ClauseSiteFlags + .atCallSite(ftAfterClose.meta.rightOwner) + val bpFlagsAfter = getBinpackCallsiteFlags(tokens(open), ftAfterClose) + scalaJsOptClose(ftAfterClose, bpFlagsAfter) } else ftBeforeClose.right } else ftBeforeClose.right @@ -2729,8 +2728,35 @@ object FormatOps { literalArgList: Boolean, dangleForTrailingCommas: Boolean, configStyle: ConfigStyle, - shouldDangle: Boolean, scalaJsStyle: Boolean, ) + case class ClauseSiteFlags( + configStyle: Newlines.ConfigStyleElement, + alignOpenDelim: Boolean = false, + dangleCloseDelim: Boolean = true, + ) + + object ClauseSiteFlags { + def apply(owner: Tree, defnSite: Boolean)(implicit + style: ScalafmtConfig, + ): ClauseSiteFlags = if (defnSite) atDefnSite(owner) else atCallSite(owner) + + def atDefnSite( + owner: Tree, + )(implicit style: ScalafmtConfig): ClauseSiteFlags = ClauseSiteFlags( + configStyle = style.configStyleDefnSite, + alignOpenDelim = style.align.atDefnSite(owner), + dangleCloseDelim = style.danglingParentheses.atDefnSite(owner), + ) + + def atCallSite( + owner: Tree, + )(implicit style: ScalafmtConfig): ClauseSiteFlags = ClauseSiteFlags( + configStyle = style.configStyleCallSite, + alignOpenDelim = style.align.atCallSite(owner), + dangleCloseDelim = style.danglingParentheses.atCallSite(owner), + ) + } + } diff --git a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala index f478ac7158..921d022fed 100644 --- a/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala +++ b/scalafmt-core/shared/src/main/scala/org/scalafmt/internal/Router.scala @@ -871,12 +871,11 @@ class Router(formatOps: FormatOps) { getMustDangleForTrailingCommas(beforeClose) val rightIsComment = right.is[T.Comment] - implicit val configStyleFlags = - if (defnSite) style.configStyleDefnSite else style.configStyleCallSite + implicit val clauseSiteFlags = ClauseSiteFlags(leftOwner, defnSite) def closeBreak = mustDangleForTrailingCommas || beforeClose.hasBreak val onlyConfigStyle = ConfigStyle.None != mustUseConfigStyle(ft, closeBreak) - val configStyleFlag = configStyleFlags.prefer + val configStyleFlag = clauseSiteFlags.configStyle.prefer val sourceIgnored = style.newlines.sourceIgnored val (onlyArgument, isSingleEnclosedArgument) = @@ -908,10 +907,7 @@ class Router(formatOps: FormatOps) { val mustDangle = onlyConfigStyle || expirationToken.is[T.Comment] || mustDangleForTrailingCommas - val shouldDangle = - if (defnSite) style.danglingParentheses.atDefnSite(leftOwner) - else style.danglingParentheses.atCallSite(leftOwner) - val wouldDangle = shouldDangle || + val wouldDangle = clauseSiteFlags.dangleCloseDelim || beforeClose.hasBreak && beforeClose.left.is[T.Comment] val newlinePolicy: Policy = @@ -933,10 +929,7 @@ class Router(formatOps: FormatOps) { else getNoSplit(ft, !isBracket) val noSplitIndent = if (rightIsComment) indent else Num(0) - val align = !rightIsComment && { - if (tupleSite) style.align.getOpenParenTupleSite - else style.align.getOpenDelimSite(isBracket, defnSite) - } && + val align = !rightIsComment && clauseSiteFlags.alignOpenDelim && (!handleImplicit || style.newlines.forceAfterImplicitParamListModifier) val alignTuple = align && tupleSite && !onlyConfigStyle @@ -1100,18 +1093,19 @@ class Router(formatOps: FormatOps) { val baseNoSplitMod = Space(style.spaces.inParentheses) if (close eq right) Seq(Split(baseNoSplitMod, 0)) else { + implicit val clauseSiteFlags = ClauseSiteFlags.atDefnSite(leftOwner) + val isBracket = open.is[T.LeftBracket] val indent = Indent(style.indent.getDefnSite(leftOwner), close, Before) - val align = style.align.getOpenDelimSite(isBracket, true) val noSplitIndents = - if (align) getOpenParenAlignIndents(close) else Seq(indent) + if (clauseSiteFlags.alignOpenDelim) getOpenParenAlignIndents(close) + else Seq(indent) val bracketPenalty = if (isBracket) Some(Constants.BracketPenalty) else None val penalizeBrackets = bracketPenalty .map(p => PenalizeAllNewlines(close, p + 3)) val beforeClose = tokens.justBefore(close) - implicit val configStyleFlags = style.configStyleDefnSite val onlyConfigStyle = getMustDangleForTrailingCommas(beforeClose) || ConfigStyle.None != mustUseConfigStyle(ft, beforeClose.hasBreak) @@ -1128,8 +1122,8 @@ class Router(formatOps: FormatOps) { val nlOnly = onlyConfigStyle || style.newlines.keepBreak(newlines) || tokens.isRightCommentWithBreak(ft) val mustDangle = onlyConfigStyle || - style.danglingParentheses.atDefnSite(leftOwner) && - (style.newlines.sourceIgnored || !configStyleFlags.prefer) + clauseSiteFlags.dangleCloseDelim && + (style.newlines.sourceIgnored || !clauseSiteFlags.configStyle.prefer) val slbOrNL = nlOnly || style.newlines.source == Newlines.unfold || mustDangle def noSplitPolicy: Policy = @@ -1183,7 +1177,8 @@ class Router(formatOps: FormatOps) { val singleArgAsInfix = if (isSingleArg) firstArg.flatMap(asInfixApp) else None - val flags = getBinpackCallsiteFlags(ft, beforeClose)(style) + implicit val clauseSiteFlags = ClauseSiteFlags.atCallSite(leftOwner) + val flags = getBinpackCallsiteFlags(ft, beforeClose) val singleLineOnly = style.binPack.literalsSingleLine && flags.literalArgList @@ -1247,10 +1242,8 @@ class Router(formatOps: FormatOps) { } val trigger = leftOwner.parent.flatMap(iter) Seq(trigger.fold(indent)(x => Indent.before(indent, x))) - } else if ( - if (isTuple(leftOwner)) style.align.getOpenParenTupleSite - else style.align.getOpenDelimSite(false, false) - ) getOpenParenAlignIndents(close) + } else if (clauseSiteFlags.alignOpenDelim) + getOpenParenAlignIndents(close) else Seq(indent) def optClose = Some(scalaJsOptClose(beforeClose, flags)) @@ -1316,7 +1309,7 @@ class Router(formatOps: FormatOps) { else if (scalaJsStyleNL) configStylePolicy else if ( flags.dangleForTrailingCommas || - flags.shouldDangle && + clauseSiteFlags.dangleCloseDelim && (style.newlines.sourceIgnored || !style.configStyleCallSite.prefer) ) bothPolicies else binPackOnelinePolicyOpt