Skip to content

Commit 8abeeac

Browse files
Coverage: escape strings before serializing statements, fix #15384
1 parent 743f3cc commit 8abeeac

File tree

16 files changed

+109
-38
lines changed

16 files changed

+109
-38
lines changed

Diff for: compiler/src/dotty/tools/dotc/coverage/Location.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ object Location:
3131

3232
val ownerDenot = ctx.owner.denot
3333
val enclosingClass = ownerDenot.enclosingClass
34-
val packageName = ownerDenot.enclosingPackageClass.name.toSimpleName.toString
34+
val packageName = ownerDenot.enclosingPackageClass.fullName.toSimpleName.toString
3535
val className = enclosingClass.name.toSimpleName.toString
3636
val methodName = ownerDenot.enclosingMethod.name.toSimpleName.toString
3737

Diff for: compiler/src/dotty/tools/dotc/coverage/Serializer.scala

+32-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package coverage
44
import java.nio.file.{Path, Paths, Files}
55
import java.io.Writer
66
import scala.language.unsafeNulls
7+
import scala.collection.mutable.StringBuilder
78

89
/**
910
* Serializes scoverage data.
@@ -62,25 +63,49 @@ object Serializer:
6263
def writeStatement(stmt: Statement, writer: Writer): Unit =
6364
// Note: we write 0 for the count because we have not measured the actual coverage at this point
6465
writer.write(s"""${stmt.id}
65-
|${getRelativePath(stmt.location.sourcePath)}
66-
|${stmt.location.packageName}
67-
|${stmt.location.className}
66+
|${getRelativePath(stmt.location.sourcePath).escaped}
67+
|${stmt.location.packageName.escaped}
68+
|${stmt.location.className.escaped}
6869
|${stmt.location.classType}
69-
|${stmt.location.fullClassName}
70-
|${stmt.location.methodName}
70+
|${stmt.location.fullClassName.escaped}
71+
|${stmt.location.methodName.escaped}
7172
|${stmt.start}
7273
|${stmt.end}
7374
|${stmt.line}
74-
|${stmt.symbolName}
75+
|${stmt.symbolName.escaped}
7576
|${stmt.treeName}
7677
|${stmt.branch}
7778
|0
7879
|${stmt.ignored}
79-
|${stmt.desc}
80+
|${stmt.desc.escaped}
8081
|\f
8182
|""".stripMargin)
8283

8384
writeHeader(writer)
8485
coverage.statements.toSeq
8586
.sortBy(_.id)
8687
.foreach(stmt => writeStatement(stmt, writer))
88+
89+
/** Makes a String suitable for output in the coverage statement data as a single line.
90+
* Escaped characters: '\\' (backslash), '\n', '\r', '\f'
91+
*/
92+
extension (str: String) def escaped: String =
93+
val builder = StringBuilder(str.length)
94+
var i = 0
95+
while
96+
i < str.length
97+
do
98+
str.charAt(i) match
99+
case '\\' =>
100+
builder ++= "\\\\"
101+
case '\n' =>
102+
builder ++= "\\n"
103+
case '\r' =>
104+
builder ++= "\\r"
105+
case '\f' =>
106+
builder ++= "\\f"
107+
case c =>
108+
builder += c
109+
i += 1
110+
end while
111+
builder.result()

Diff for: tests/coverage/pos/Enum.scoverage.check

+5-6
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Apply
8484
false
8585
0
8686
false
87-
println("Example 1: \n"+emptyList)
87+
println("Example 1: \\n"+emptyList)
8888

8989
4
9090
Enum.scala
@@ -101,7 +101,7 @@ Apply
101101
false
102102
0
103103
false
104-
"Example 1: \n"+emptyList
104+
"Example 1: \\n"+emptyList
105105

106106
5
107107
Enum.scala
@@ -118,7 +118,7 @@ Apply
118118
false
119119
0
120120
false
121-
println(s"${list}\n")
121+
println(s"${list}\\n")
122122

123123
6
124124
Enum.scala
@@ -135,7 +135,7 @@ Apply
135135
false
136136
0
137137
false
138-
s"${list}\n"
138+
s"${list}\\n"
139139

140140
7
141141
Enum.scala
@@ -169,8 +169,7 @@ Apply
169169
false
170170
0
171171
false
172-
for p <- Planet.values do
173-
println(s"Your weight on $p is ${p.surfaceWeight(mass)}")
172+
for p <- Planet.values do\n println(s"Your weight on $p is ${p.surfaceWeight(mass)}")
174173

175174
9
176175
Enum.scala

Diff for: tests/coverage/pos/Escaping.scala

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package covtest.`\n`
2+
3+
class `\r\n\f`:
4+
def `\r\n\f`(`\\`: String) = `\\`.length

Diff for: tests/coverage/pos/Escaping.scoverage.check

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Coverage data, format version: 3.0
2+
# Statement data:
3+
# - id
4+
# - source path
5+
# - package name
6+
# - class name
7+
# - class type (Class, Object or Trait)
8+
# - full class name
9+
# - method name
10+
# - start offset
11+
# - end offset
12+
# - line number
13+
# - symbol name
14+
# - tree name
15+
# - is branch
16+
# - invocations count
17+
# - is ignored
18+
# - description (can be multi-line)
19+
# ' ' sign
20+
# ------------------------------------------
21+
0
22+
Escaping.scala
23+
covtest.\n
24+
\r\n\f
25+
Class
26+
covtest.\n.\r\n\f
27+
\r\n\f
28+
69
29+
80
30+
3
31+
length
32+
Apply
33+
false
34+
0
35+
false
36+
`\\\\`.length
37+
38+
1
39+
Escaping.scala
40+
covtest.\n
41+
\r\n\f
42+
Class
43+
covtest.\n.\r\n\f
44+
\r\n\f
45+
40
46+
48
47+
3
48+
\r\n\f
49+
DefDef
50+
false
51+
0
52+
false
53+
def `\\r\\
54+

Diff for: tests/coverage/pos/For.scoverage.check

+2-4
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ Apply
3333
false
3434
0
3535
false
36-
for i <- 1 to 10 do
37-
println(i)
36+
for i <- 1 to 10 do\n println(i)
3837

3938
1
4039
For.scala
@@ -136,8 +135,7 @@ Apply
136135
false
137136
0
138137
false
139-
for j <- 1 to 10 if f(j) do
140-
println(j)
138+
for j <- 1 to 10 if f(j) do\n println(j)
141139

142140
7
143141
For.scala

Diff for: tests/coverage/run/erased/test.scoverage.check

+1-2
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,5 @@ DefDef
203203
false
204204
0
205205
false
206-
@main
207-
def Test
206+
@main\ndef Test
208207

Diff for: tests/coverage/run/inheritance/test.scoverage.check

+1-2
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,5 @@ DefDef
135135
false
136136
0
137137
false
138-
@main
139-
def Test
138+
@main\ndef Test
140139

Diff for: tests/coverage/run/inline-def/test.scoverage.check

+1-2
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,5 @@ DefDef
169169
false
170170
0
171171
false
172-
@main
173-
def Test
172+
@main\ndef Test
174173

Diff for: tests/coverage/run/interpolation/test.scoverage.check

+2-2
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ Apply
288288
false
289289
0
290290
false
291-
println(raw"a\nb")
291+
println(raw"a\\nb")
292292

293293
16
294294
interpolation/test.scala
@@ -305,7 +305,7 @@ Apply
305305
false
306306
0
307307
false
308-
raw"a\nb"
308+
raw"a\\nb"
309309

310310
17
311311
interpolation/test.scala

Diff for: tests/coverage/run/java-methods/test.scoverage.check

+1-2
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,5 @@ DefDef
152152
false
153153
0
154154
false
155-
@main
156-
def Test
155+
@main\ndef Test
157156

Diff for: tests/coverage/run/lifting-bool/test.scoverage.check

+1-2
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,5 @@ DefDef
305305
false
306306
0
307307
false
308-
@main
309-
def Test
308+
@main\ndef Test
310309

Diff for: tests/coverage/run/lifting/test.scoverage.check

+1-2
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,5 @@ DefDef
475475
false
476476
0
477477
false
478-
@main
479-
def Test
478+
@main\ndef Test
480479

Diff for: tests/coverage/run/parameterless/test.scoverage.check

+1-2
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,5 @@ DefDef
339339
false
340340
0
341341
false
342-
@main
343-
def Test
342+
@main\ndef Test
344343

Diff for: tests/coverage/run/trait/test.scoverage.check

+1-2
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,5 @@ DefDef
186186
false
187187
0
188188
false
189-
@main
190-
def Test
189+
@main\ndef Test
191190

Diff for: tests/coverage/run/varargs/test_1.scoverage.check

+1-2
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,5 @@ DefDef
288288
false
289289
0
290290
false
291-
@main
292-
def Test
291+
@main\ndef Test
293292

0 commit comments

Comments
 (0)