Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FormatOps: enclosing parens owned by enclosed tree #3395

Merged
merged 1 commit into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2063,14 +2063,14 @@ class FormatOps(
indentOpt: Option[Int] = None
)(implicit fileLine: FileLine, style: ScalafmtConfig): Seq[Split] = {
val treeTokens = tree.tokens
val end = tokens.getLast(treeTokens)
val end = tokens.getLast(treeTokens, tree)
val slbExpire = nextNonCommentSameLine(end).left
val closeOpt =
if (isTuple(tree)) None
else {
val maybeClose = prevNonComment(end)
tokens
.getClosingIfInParens(maybeClose)(tokens.getHead(treeTokens))
.getClosingIfInParens(maybeClose)(tokens.getHead(treeTokens, tree))
.map(prevNonComment(_).left)
}
def nlPolicy(implicit fileLine: FileLine) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ class FormatTokens(leftTok2tok: Map[TokenOps.TokenHash, Int])(
}
def getClosingIfInParens(tree: Tree): Option[FormatToken] = {
val tokens = tree.tokens
getHeadOpt(tokens).flatMap(getClosingIfInParens(getLastNonTrivial(tokens)))
getHeadOpt(tokens, tree)
.flatMap(getClosingIfInParens(getLastNonTrivial(tokens, tree)))
}

def getLastExceptParen(tokens: Tokens): FormatToken = {
Expand Down Expand Up @@ -159,35 +160,61 @@ class FormatTokens(leftTok2tok: Map[TokenOps.TokenHash, Int])(
final def prevNonCommentBefore(curr: FormatToken): FormatToken =
prevNonComment(prev(curr))

def getHead(tokens: Tokens): FormatToken =
@tailrec
final def getOnOrBeforeOwned(ft: FormatToken, tree: Tree): FormatToken = {
val prevFt = prevNonCommentBefore(ft)
if (prevFt == ft || prevFt.meta.leftOwner != tree) ft
else getOnOrBeforeOwned(prevFt, tree)
}

@tailrec
final def getOnOrAfterOwned(ft: FormatToken, tree: Tree): FormatToken = {
val nextFt = next(nextNonComment(ft))
if (nextFt == ft || nextFt.meta.leftOwner != tree) ft
else getOnOrAfterOwned(nextFt, tree)
}

private def getHead(tokens: Tokens): FormatToken =
after(tokens.head)
def getHead(tree: Tree): FormatToken =
getHead(tree.tokens)
def getHead(tokens: Tokens, tree: Tree): FormatToken =
getOnOrBeforeOwned(getHead(tokens), tree)
@inline def getHead(tree: Tree): FormatToken =
getHead(tree.tokens, tree)

def getHeadOpt(tokens: Tokens): Option[FormatToken] =
private def getHeadOpt(tokens: Tokens): Option[FormatToken] =
tokens.headOption.map(after)
def getHeadOpt(tree: Tree): Option[FormatToken] =
getHeadOpt(tree.tokens)
def getHeadOpt(tokens: Tokens, tree: Tree): Option[FormatToken] =
getHeadOpt(tokens).map(getOnOrBeforeOwned(_, tree))
@inline def getHeadOpt(tree: Tree): Option[FormatToken] =
getHeadOpt(tree.tokens, tree)

def getLast(tokens: Tokens): FormatToken =
private def getLast(tokens: Tokens): FormatToken =
apply(TokenOps.findLastVisibleToken(tokens))
def getLast(tree: Tree): FormatToken =
getLast(tree.tokens)
def getLast(tokens: Tokens, tree: Tree): FormatToken =
getOnOrAfterOwned(getLast(tokens), tree)
@inline def getLast(tree: Tree): FormatToken =
getLast(tree.tokens, tree)

def getLastOpt(tokens: Tokens): Option[FormatToken] =
private def getLastOpt(tokens: Tokens): Option[FormatToken] =
TokenOps.findLastVisibleTokenOpt(tokens).map(apply)
def getLastOpt(tree: Tree): Option[FormatToken] =
getLastOpt(tree.tokens)
def getLastOpt(tokens: Tokens, tree: Tree): Option[FormatToken] =
getLastOpt(tokens).map(getOnOrAfterOwned(_, tree))
@inline def getLastOpt(tree: Tree): Option[FormatToken] =
getLastOpt(tree.tokens, tree)

def getLastNonTrivial(tokens: Tokens): FormatToken =
private def getLastNonTrivial(tokens: Tokens): FormatToken =
apply(TokenOps.findLastNonTrivialToken(tokens))
def getLastNonTrivial(tokens: Tokens, tree: Tree): FormatToken =
getOnOrAfterOwned(getLastNonTrivial(tokens), tree)
def getLastNonTrivial(tree: Tree): FormatToken =
getLastNonTrivial(tree.tokens)
getLastNonTrivial(tree.tokens, tree)

def getLastNonTrivialOpt(tokens: Tokens): Option[FormatToken] =
private def getLastNonTrivialOpt(tokens: Tokens): Option[FormatToken] =
TokenOps.findLastNonTrivialTokenOpt(tokens).map(apply)
def getLastNonTrivialOpt(tokens: Tokens, tree: Tree): Option[FormatToken] =
getLastNonTrivialOpt(tokens).map(getOnOrAfterOwned(_, tree))
def getLastNonTrivialOpt(tree: Tree): Option[FormatToken] =
getLastNonTrivialOpt(tree.tokens)
getLastNonTrivialOpt(tree.tokens, tree)

/* the following methods return the first format token such that
* its `right` is after the parameter and is not a comment */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -946,8 +946,9 @@ object TreeOps {
ownersMap += hash(tok) -> tree

val allTokens = topSourceTree.tokens(baseStyle.dialect)
var prevParens: List[Token] = Nil

def treeAt(elemIdx: Int, elem: Tree): Int = {
def treeAt(elemIdx: Int, elem: Tree, outerPrevLPs: Int): Int = {
if (TreeOps.isInfixApp(elem)) infixCount += 1

val endPos = elem.pos.end
Expand Down Expand Up @@ -978,6 +979,8 @@ object TreeOps {
var nextChild = firstChild
var nextChildStart = firstChildStart
var children = rest
var prevChild: Tree = null
var prevLPs = outerPrevLPs

@tailrec
def tokenAt(idx: Int): Int = {
Expand All @@ -986,7 +989,9 @@ object TreeOps {
val tok = allTokens(idx)
if (nextChild == null && elemIdx != 0 && tok.start >= endPos) idx
else if (nextChild != null && tok.end > nextChildStart) {
val nextIdx = treeAt(idx, nextChild)
if (prevChild != null) prevLPs = 0
prevChild = nextChild
val nextIdx = treeAt(idx, nextChild, prevLPs)
children match {
case Nil =>
nextChild = null
Expand All @@ -997,7 +1002,41 @@ object TreeOps {
}
tokenAt(nextIdx)
} else {
setOwner(tok, elem)
def excludeRightParen: Boolean = elem match {
case t: Term.If => prevChild eq t.cond // `expr` after `mods`
case _: Term.While | _: Term.For | _: Term.ForYield =>
prevChild eq firstChild // `expr` is first
case _: Term.Tuple | _: Type.Tuple | _: Pat.Tuple |
_: Term.ApplyInfix | _: Pat.ExtractInfix | _: Term.Apply |
_: Pat.Extract | _: Term.Do | _: Term.AnonymousFunction =>
nextChild == null
case _: Decl.Def | _: Decl.Given | _: Type.FunctionType |
_: Defn.Def | _: Defn.Macro | _: Defn.Given |
_: Defn.GivenAlias | _: Defn.ExtensionGroup =>
nextChild != null // body is next
case _: Init | _: Ctor => true
case _ => false
}

if (prevParens.nonEmpty && tok.is[RightParen]) {
if (prevChild == null || prevLPs == 0 || excludeRightParen)
setOwner(tok, elem)
else {
prevLPs -= 1
setOwner(tok, prevChild)
setOwner(prevParens.head, prevChild)
}
prevParens = prevParens.tail
} else {
setOwner(tok, elem)
if (!tok.is[Trivia] && nextChild != null) {
prevChild = null
if (tok.is[LeftParen]) {
prevLPs += 1
prevParens = tok :: prevParens
} else prevLPs = 0
}
}
tokenAt(idx + 1)
}
}
Expand All @@ -1006,7 +1045,7 @@ object TreeOps {
}
}

treeAt(0, topSourceTree)
treeAt(0, topSourceTree, 0)

val checkedNewlines = baseStyle.newlines.checkInfixConfig(infixCount)
val initStyle =
Expand Down