Skip to content

Commit 3603b66

Browse files
committed
Fix colon after new line
1 parent e58013f commit 3603b66

File tree

4 files changed

+67
-57
lines changed

4 files changed

+67
-57
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 22 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -727,26 +727,13 @@ object Parsers {
727727
t
728728
end indentedToBraces
729729

730-
/** The region to eliminate when replacing an opening `(` or `{` that ends a line.
731-
* The `(` or `{` is at in.offset.
732-
*/
733-
def startingElimRegion(colonRequired: Boolean): (Offset, Offset) =
734-
val (start, end) = blankLinesAround(in.offset, in.offset + 1)
735-
if testChar(end, Chars.LF) then
736-
if testChar(start - 1, Chars.LF) && !colonRequired then
737-
(start, end + 1) // skip the whole line
738-
else (start, end) // skip the end of line
739-
else (start, in.offset + 1) // skip from last to end of token
740-
741-
/** The region to eliminate when replacing a closing `)` or `}` that starts a new line
742-
* The `)` or `}` precedes in.lastOffset.
743-
*/
744-
def closingElimRegion(): (Offset, Offset) =
745-
val (start, end) = blankLinesAround(in.lastOffset - 1, in.lastOffset)
730+
/** The region to eliminate when replacing a brace or parenthesis that ends a line */
731+
def elimRegion(offset: Offset): (Offset, Offset) =
732+
val (start, end) = blankLinesAround(offset, offset + 1)
746733
if testChar(end, Chars.LF) then
747734
if testChar(start - 1, Chars.LF) then (start, end + 1) // skip the whole line
748735
else (start, end) // skip the end of line
749-
else (in.lastOffset - 1, end) // skip from token to next
736+
else (offset, end) // skip from last to end of token
750737

751738
/** Expand the current span to the surrounding blank lines */
752739
def blankLinesAround(start: Offset, end: Offset): (Offset, Offset) =
@@ -763,21 +750,25 @@ object Parsers {
763750
* 6. the opening brace does not follow a closing `}`
764751
* 7. last token is not a leading operator
765752
* 8. not a block in a sequence of statements
753+
* 9. cannot rewrite to colon after a NEWLINE, e.g.
754+
* true ||
755+
* { // NEWLINE inserted between || and {
756+
* false
757+
* }
766758
*/
767759
def bracesToIndented[T](body: => T, inStatSeq: Boolean, rewriteWithColon: Boolean): T = {
768760
val lastSaved = in.last.saveCopy
761+
val lastOffsetSaved = in.lastOffset
769762
val underColonSyntax = possibleColonOffset == in.lastOffset
770763
val colonRequired = rewriteWithColon || underColonSyntax
771-
val (startOpening, endOpening) = startingElimRegion(colonRequired)
772-
val isOutermost = in.currentRegion.isOutermost
764+
val (startOpening, endOpening) = elimRegion(in.offset)
773765
def isBracesOrIndented(r: Region): Boolean = r match
774766
case r: Indented => true
775767
case r: InBraces => true
776768
case _ => false
777-
val followsLeadingOperator = lastSaved.isOperator && lastSaved.isAfterLineEnd
778769
var canRewrite = isBracesOrIndented(in.currentRegion) && // test (1)
779770
lastSaved.token != RBRACE && // test (6)
780-
!followsLeadingOperator && // test (7)
771+
!(lastSaved.isOperator && lastSaved.isAfterLineEnd) && // test (7)
781772
!inStatSeq // test (8)
782773
var innerIndent: Option[IndentWidth] = None
783774
val t = enclosed(LBRACE, {
@@ -791,23 +782,18 @@ object Parsers {
791782
canRewrite = false
792783
body
793784
})
794-
canRewrite &= (in.isAfterLineEnd || in.token == EOF || statCtdTokens.contains(in.token)) // test (5)
795-
def isOperatorFollowedByColon =
796-
lastSaved.name != null &&
797-
startOpening == lastSaved.offset + lastSaved.name.length &&
798-
Chars.isOperatorPart(lastSaved.name.last)
785+
canRewrite &= (in.isAfterLineEnd || in.token == EOF || statCtdTokens.contains(in.token)) && // test (5)
786+
(!colonRequired || !lastSaved.isNewLine) // test (9)
799787
if canRewrite && (!underColonSyntax || Feature.fewerBracesEnabled) then
800-
val openingPatchStr =
801-
if !colonRequired then ""
802-
else if isOperatorFollowedByColon then
803-
// surround previous ident with backticks
804-
patch(Span(lastSaved.offset, lastSaved.offset + lastSaved.name.length), s"`${lastSaved.name}`")
805-
" :"
806-
else ":"
807-
val (startClosing, endClosing) = closingElimRegion()
788+
val (startClosing, endClosing) = elimRegion(in.last.offset)
808789
// patch over the added indentation to remove braces
809-
patchOver(source, Span(startOpening, endOpening), openingPatchStr)
790+
patchOver(source, Span(startOpening, endOpening), "")
810791
patchOver(source, Span(startClosing, endClosing), "")
792+
if colonRequired then
793+
// add backticks around operator and add colon
794+
if lastSaved.isOperator then
795+
patch(Span(lastSaved.offset, lastSaved.offset + lastSaved.name.length), s"`${lastSaved.name}` :")
796+
else patch(Span(lastOffsetSaved), ":")
811797
// force outdentation of token after }
812798
maximumIndent = innerIndent
813799
else
@@ -883,7 +869,7 @@ object Parsers {
883869
val preFill = if (closingStartsLine || endStr.isEmpty) "" else " "
884870
val postFill = if (in.lastOffset == in.offset) " " else ""
885871
val (startClosing, endClosing) =
886-
if (closingStartsLine && endStr.isEmpty) closingElimRegion()
872+
if (closingStartsLine && endStr.isEmpty) elimRegion(in.last.offset)
887873
else (in.lastOffset - 1, in.lastOffset)
888874
patch(source, Span(startClosing, endClosing), s"$preFill$endStr$postFill")
889875
}

compiler/src/dotty/tools/dotc/rewrites/Rewrites.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ object Rewrites {
3131

3232
def apply(cs: Array[Char]): Array[Char] = {
3333
val delta = pbuf.map(_.delta).sum
34-
val patches = pbuf.toList.sortBy(_.span.start)
34+
val patches = pbuf.toList.sortBy(p => (p.span.start, p.span.end))
3535
if (patches.nonEmpty)
3636
patches.reduceLeft {(p1, p2) =>
3737
assert(p1.span.end <= p2.span.start, s"overlapping patches in $source: $p1 and $p2")

tests/rewrites/indent-comments.check

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
// Rewriting to indent should not remove the comments
2-
class A /** 1 */ : /** 2 */
3-
def m1 = /** 3 */ /** 4 */
4-
val x = if (true)
5-
/** 5 */
2+
class A: /* 1 */ /* 2 */
3+
def m1(b: Boolean) = /* 3 */ /* 4 */
4+
val x = if (b)
5+
/* 5 */
66
"true"
7-
/** 6 */
7+
/* 6 */
88
else
9-
/** 7 */
9+
/* 7 */
1010
"false"
11-
/** 8 */
12-
/** 9 */ x
13-
/** 10 */ /** 11 */
14-
/** 12 */
11+
/* 8 */
12+
/* 9 */ x.toBoolean
13+
/* 10 */ /* 11 */
14+
/* 12 */def m2 = // 12
15+
m1:// 14
16+
/* 15 */// 16
17+
true
18+
/* 17 */// 18
19+
// because of the missing indent before {
20+
// the scanner inserts a new line between || and {
21+
// cannot rewrite to indentation without messing the comments up
22+
true ||// 19
23+
/* 20 */{
24+
false
25+
}// 21

tests/rewrites/indent-comments.scala

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
11
// Rewriting to indent should not remove the comments
2-
class A /** 1 */ { /** 2 */
3-
def m1 = /** 3 */ { /** 4 */
4-
val x = if (true)
5-
/** 5 */ {
2+
class A /* 1 */ { /* 2 */
3+
def m1(b: Boolean) = /* 3 */ { /* 4 */
4+
val x = if (b)
5+
/* 5 */ {
66
"true"
7-
} /** 6 */
7+
} /* 6 */
88
else
9-
{ /** 7 */
9+
{ /* 7 */
1010
"false"
11-
/** 8 */ }
12-
/** 9 */ x
13-
/** 10 */ } /** 11 */
14-
/** 12 */ }
11+
/* 8 */ }
12+
/* 9 */ x.toBoolean
13+
/* 10 */ } /* 11 */
14+
/* 12 */def m2 = {// 12
15+
m1// 14
16+
/* 15 */{// 16
17+
true
18+
/* 17 */}// 18
19+
// because of the missing indent before {
20+
// the scanner inserts a new line between || and {
21+
// cannot rewrite to indentation without messing the comments up
22+
true ||// 19
23+
/* 20 */{
24+
false
25+
}// 21
26+
}
27+
}

0 commit comments

Comments
 (0)