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

FormatTokens: implement isEnclosedInParens #3214

Merged
merged 3 commits into from
May 16, 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 @@ -79,6 +79,7 @@ class FormatOps(
matching,
matchingOpt,
isEnclosedInMatching,
isEnclosedInParens,
findTokenWith,
tokenBefore,
tokenAfter,
Expand Down Expand Up @@ -556,7 +557,7 @@ class FormatOps(
@tailrec
private def findEnclosingInfix(child: InfixApp): InfixApp = {
val childTree = child.all
if (isEnclosedInMatching(childTree)) child
if (isEnclosedInParens(childTree)) child
else
childTree.parent match {
case Some(InfixApp(parent)) if !parent.isAssignment =>
Expand Down Expand Up @@ -712,12 +713,7 @@ class FormatOps(
val infixes = if (beforeLhs) res.toSeq else res.toSeq.tail
val filtered =
if (!style.newlines.afterInfixBreakOnNested) infixes
else
infixes.takeWhile { x =>
val close = getLastNonTrivialToken(x.lhs)
!close.is[T.RightParen] ||
!tokens.isCloseMatchingHead(close)(owners(close))
}
else infixes.takeWhile(x => !isEnclosedInParens(x.lhs))
if (filtered.isEmpty) None
else {
val res = filtered.foldLeft(Seq.empty[(T, Int)]) { case (out, ia) =>
Expand Down Expand Up @@ -842,9 +838,7 @@ class FormatOps(
}

private def getLastEnclosedToken(tree: Tree): T = {
val tokens = tree.tokens
val slice = if (isEnclosedInMatching(tree)) tokens.dropRight(1) else tokens
findLastNonTrivialToken(slice)
tokens.getLastExceptParen(tree.tokens).left
}

@tailrec
Expand All @@ -864,7 +858,7 @@ class FormatOps(
tree: Tree,
res: mutable.Buffer[InfixApp]
): Unit =
if (!isEnclosedInMatching(tree)) {
if (!isEnclosedInParens(tree)) {
asInfixApp(tree).foreach { ia =>
findNestedInfixes(ia.lhs, res)
res += ia
Expand All @@ -881,14 +875,14 @@ class FormatOps(
@tailrec
final def findLeftInfix(app: InfixApp): InfixApp =
app.lhs match {
case t @ InfixApp(ia) if !isEnclosedInMatching(t) =>
case t @ InfixApp(ia) if !isEnclosedInParens(t) =>
findLeftInfix(ia)
case _ => app
}

private def getInfixRhsAsInfix(app: InfixApp): Option[InfixApp] =
app.rhs match {
case Seq(t @ InfixApp(ia)) if !isEnclosedInMatching(t) => Some(ia)
case Seq(t @ InfixApp(ia)) if !isEnclosedInParens(t) => Some(ia)
case _ => None // multiple parameters to infix are always enclosed
}

Expand All @@ -901,7 +895,7 @@ class FormatOps(
if (maxPrecedence < elem.precedence)
maxPrecedence = elem.precedence
queue ++= (elem.lhs +: elem.rhs).collect {
case t @ InfixApp(ia) if !isEnclosedInMatching(t) => ia
case t @ InfixApp(ia) if !isEnclosedInParens(t) => ia
}
}
maxPrecedence
Expand Down Expand Up @@ -1496,7 +1490,7 @@ class FormatOps(
tree match {
case GetSelectLike(t) => Some(t)
case t @ SplitCallIntoParts(fun, _) if t ne fun =>
if (enclosed && isEnclosedInMatching(t)) None
if (enclosed && isEnclosedInParens(t)) None
else findPrevSelect(fun, enclosed)
case _ => None
}
Expand All @@ -1511,7 +1505,7 @@ class FormatOps(
tree: Tree,
select: Option[SelectLike] = None
): (Tree, Option[SelectLike]) =
if (isEnclosedInMatching(tree)) (tree, select)
if (isEnclosedInParens(tree)) (tree, select)
else
tree.parent match {
case Some(GetSelectLike(p)) =>
Expand All @@ -1534,7 +1528,7 @@ class FormatOps(
prevEnclosed match {
case Some(t) => (t, select)
case _ =>
val nextEnclosed = Some(tree).filter(isEnclosedInMatching)
val nextEnclosed = Some(tree).filter(isEnclosedInParens)
findLastApplyAndNextSelectPastEnclosed(p, select, nextEnclosed)
}
case _ => (prevEnclosed.getOrElse(tree), select)
Expand Down Expand Up @@ -1928,12 +1922,7 @@ class FormatOps(
val op = t.op.value
op != "->" && op != "→"
case _ => true
}) && {
val btoks = body.tokens
btoks.headOption.exists { head =>
head.is[T.LeftParen] && tokens.areMatching(head)(btoks.last)
}
}
}) && isEnclosedInParens(body)
}

// For using to be the soft kw it also has to be preceded by paren
Expand Down Expand Up @@ -2066,14 +2055,16 @@ class FormatOps(
danglingKeyword: Boolean = true,
indentOpt: Option[Int] = None
)(implicit fileLine: FileLine, style: ScalafmtConfig): Seq[Split] = {
val end = tokens.getLast(tree)
val treeTokens = tree.tokens
val end = tokens.getLast(treeTokens)
val slbExpire = nextNonCommentSameLine(end).left
val closeOpt =
if (isTuple(tree)) None
else {
val maybeClose = prevNonComment(end)
if (!tokens.isCloseMatchingHead(maybeClose.left)(tree)) None
else Some(prevNonCommentBefore(maybeClose).left)
tokens
.getClosingIfInParens(maybeClose)(tokens.getHead(treeTokens))
.map(prevNonComment(_).left)
}
def nlPolicy(implicit fileLine: FileLine) =
if (danglingKeyword)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,24 +83,39 @@ class FormatTokens(leftTok2tok: Map[TokenOps.TokenHash, Int])(
matchingParentheses.get(TokenOps.hash(token))
@inline def hasMatching(token: Token): Boolean =
matchingParentheses.contains(TokenOps.hash(token))
@inline def areMatching(t1: Token)(t2: Token): Boolean =
matchingOpt(t1).contains(t2)

def getClosingIfEnclosedInMatching(tokens: Tokens): Option[FormatToken] =
getHeadOpt(tokens).flatMap { head =>
matchingOpt(head.left).flatMap { last =>
val ft = getLastNonTrivial(tokens)
if (ft.left eq last) Some(ft) else None
}
@inline def areMatching(t1: Token)(t2: => Token): Boolean =
matchingOpt(t1) match {
case Some(x) => x eq t2
case _ => false
}

def isEnclosedInMatching(tokens: Tokens): Boolean =
getClosingIfEnclosedInMatching(tokens).isDefined
getHeadOpt(tokens).exists { head =>
areMatching(head.left)(getLastNonTrivial(tokens).left)
}
def isEnclosedInMatching(tree: Tree): Boolean =
isEnclosedInMatching(tree.tokens)

def isCloseMatchingHead(close: Token)(tree: => Tree): Boolean =
matchingOpt(close).exists(_ eq getHead(tree).left)
@inline private def areMatchingParens(close: Token)(open: => Token): Boolean =
close.is[Token.RightParen] && areMatching(close)(open)

def isEnclosedInParens(tokens: Tokens): Boolean =
getClosingIfInParens(tokens).isDefined
def isEnclosedInParens(tree: Tree): Boolean =
isEnclosedInParens(tree.tokens)

def getClosingIfInParens(
last: FormatToken
)(head: FormatToken): Option[FormatToken] =
if (areMatchingParens(last.left)(head.left)) Some(prev(last))
else None
def getClosingIfInParens(tokens: Tokens): Option[FormatToken] =
getHeadOpt(tokens).flatMap(getClosingIfInParens(getLastNonTrivial(tokens)))

def getLastExceptParen(tokens: Tokens): FormatToken = {
val last = getLastNonTrivial(tokens)
getClosingIfInParens(last)(getHead(tokens)).getOrElse(last)
}

@tailrec
final def findTokenWith[A](
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ class FormatWriter(formatOps: FormatOps) {
private def checkInsertBraces(locations: Array[FormatLocation]): Unit = {
def checkInfix(tree: Tree): Boolean = tree match {
case ai @ Term.ApplyInfix(lhs, op, _, rhs) =>
tokens.isEnclosedInMatching(ai) ||
tokens.isEnclosedInParens(ai) ||
tokens.prevNonCommentSameLine(tokens.tokenJustBefore(op)).noBreak &&
checkInfix(lhs) && (rhs.lengthCompare(1) != 0 || checkInfix(rhs.head))
case _ => true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1672,9 +1672,7 @@ class Router(formatOps: FormatOps) {
case x: Term.Match => SelectLike(x, getKwMatchAfterDot(t))
}
val prevSelect = findPrevSelect(thisSelect, enclosed)
val expireDropRight = if (isEnclosedInMatching(expireTree)) 1 else 0
val expireTreeSlice = expireTree.tokens.dropRight(expireDropRight)
val expire = findLastNonTrivialToken(expireTreeSlice)
val expire = tokens.getLastExceptParen(expireTree.tokens).left
val indentLen = style.indent.main

def breakOnNextDot: Policy =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,7 @@ class RedundantParens(ftoks: FormatTokens) extends FormatTokensRewrite.Rule {
}

private def breaksBeforeOpAndNotEnclosed(ia: InfixApp): Boolean = {
val allToks = ia.all.tokens
!ftoks.areMatching(allToks.head)(allToks.last) && breaksBeforeOp(ia)
!ftoks.isEnclosedInParens(ia.all) && breaksBeforeOp(ia)
}

private def breaksBeforeOp(ia: InfixApp): Boolean = {
Expand Down