From 3bd7293781fee4b8560bcc16b2c26394ac2a2802 Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Sun, 23 Oct 2022 16:21:02 +0200 Subject: [PATCH] Coverage: escape strings before serializing statements, fix #15384 --- .../dotty/tools/dotc/coverage/Location.scala | 2 +- .../tools/dotc/coverage/Serializer.scala | 39 +++++++++++--- tests/coverage/pos/Enum.scoverage.check | 11 ++-- tests/coverage/pos/Escaping.scala | 4 ++ tests/coverage/pos/Escaping.scoverage.check | 54 +++++++++++++++++++ tests/coverage/pos/For.scoverage.check | 6 +-- .../coverage/run/erased/test.scoverage.check | 3 +- .../run/inheritance/test.scoverage.check | 3 +- .../run/inline-def/test.scoverage.check | 3 +- .../run/interpolation/test.scoverage.check | 4 +- .../run/java-methods/test.scoverage.check | 3 +- .../run/lifting-bool/test.scoverage.check | 3 +- .../coverage/run/lifting/test.scoverage.check | 3 +- .../run/parameterless/test.scoverage.check | 3 +- tests/coverage/run/trait/test.scoverage.check | 3 +- .../run/varargs/test_1.scoverage.check | 3 +- 16 files changed, 109 insertions(+), 38 deletions(-) create mode 100644 tests/coverage/pos/Escaping.scala create mode 100644 tests/coverage/pos/Escaping.scoverage.check diff --git a/compiler/src/dotty/tools/dotc/coverage/Location.scala b/compiler/src/dotty/tools/dotc/coverage/Location.scala index c949010342c8..c565c2bb1116 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Location.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Location.scala @@ -31,7 +31,7 @@ object Location: val ownerDenot = ctx.owner.denot val enclosingClass = ownerDenot.enclosingClass - val packageName = ownerDenot.enclosingPackageClass.name.toSimpleName.toString + val packageName = ownerDenot.enclosingPackageClass.fullName.toSimpleName.toString val className = enclosingClass.name.toSimpleName.toString val methodName = ownerDenot.enclosingMethod.name.toSimpleName.toString diff --git a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala index 4169f8b94130..26efa8934e00 100644 --- a/compiler/src/dotty/tools/dotc/coverage/Serializer.scala +++ b/compiler/src/dotty/tools/dotc/coverage/Serializer.scala @@ -4,6 +4,7 @@ package coverage import java.nio.file.{Path, Paths, Files} import java.io.Writer import scala.language.unsafeNulls +import scala.collection.mutable.StringBuilder /** * Serializes scoverage data. @@ -62,21 +63,21 @@ object Serializer: def writeStatement(stmt: Statement, writer: Writer): Unit = // Note: we write 0 for the count because we have not measured the actual coverage at this point writer.write(s"""${stmt.id} - |${getRelativePath(stmt.location.sourcePath)} - |${stmt.location.packageName} - |${stmt.location.className} + |${getRelativePath(stmt.location.sourcePath).escaped} + |${stmt.location.packageName.escaped} + |${stmt.location.className.escaped} |${stmt.location.classType} - |${stmt.location.fullClassName} - |${stmt.location.methodName} + |${stmt.location.fullClassName.escaped} + |${stmt.location.methodName.escaped} |${stmt.start} |${stmt.end} |${stmt.line} - |${stmt.symbolName} + |${stmt.symbolName.escaped} |${stmt.treeName} |${stmt.branch} |0 |${stmt.ignored} - |${stmt.desc} + |${stmt.desc.escaped} |\f |""".stripMargin) @@ -84,3 +85,27 @@ object Serializer: coverage.statements.toSeq .sortBy(_.id) .foreach(stmt => writeStatement(stmt, writer)) + + /** Makes a String suitable for output in the coverage statement data as a single line. + * Escaped characters: '\\' (backslash), '\n', '\r', '\f' + */ + extension (str: String) def escaped: String = + val builder = StringBuilder(str.length) + var i = 0 + while + i < str.length + do + str.charAt(i) match + case '\\' => + builder ++= "\\\\" + case '\n' => + builder ++= "\\n" + case '\r' => + builder ++= "\\r" + case '\f' => + builder ++= "\\f" + case c => + builder += c + i += 1 + end while + builder.result() diff --git a/tests/coverage/pos/Enum.scoverage.check b/tests/coverage/pos/Enum.scoverage.check index 6fb835ca87f4..7e9b69be2d31 100644 --- a/tests/coverage/pos/Enum.scoverage.check +++ b/tests/coverage/pos/Enum.scoverage.check @@ -84,7 +84,7 @@ Apply false 0 false -println("Example 1: \n"+emptyList) +println("Example 1: \\n"+emptyList) 4 Enum.scala @@ -101,7 +101,7 @@ Apply false 0 false -"Example 1: \n"+emptyList +"Example 1: \\n"+emptyList 5 Enum.scala @@ -118,7 +118,7 @@ Apply false 0 false -println(s"${list}\n") +println(s"${list}\\n") 6 Enum.scala @@ -135,7 +135,7 @@ Apply false 0 false -s"${list}\n" +s"${list}\\n" 7 Enum.scala @@ -169,8 +169,7 @@ Apply false 0 false -for p <- Planet.values do - println(s"Your weight on $p is ${p.surfaceWeight(mass)}") +for p <- Planet.values do\n println(s"Your weight on $p is ${p.surfaceWeight(mass)}") 9 Enum.scala diff --git a/tests/coverage/pos/Escaping.scala b/tests/coverage/pos/Escaping.scala new file mode 100644 index 000000000000..bdde94290251 --- /dev/null +++ b/tests/coverage/pos/Escaping.scala @@ -0,0 +1,4 @@ +package covtest.`\n` + +class `\r\n\f`: + def `\r\n\f`(`\\`: String) = `\\`.length diff --git a/tests/coverage/pos/Escaping.scoverage.check b/tests/coverage/pos/Escaping.scoverage.check new file mode 100644 index 000000000000..ecb907a9d222 --- /dev/null +++ b/tests/coverage/pos/Escaping.scoverage.check @@ -0,0 +1,54 @@ +# Coverage data, format version: 3.0 +# Statement data: +# - id +# - source path +# - package name +# - class name +# - class type (Class, Object or Trait) +# - full class name +# - method name +# - start offset +# - end offset +# - line number +# - symbol name +# - tree name +# - is branch +# - invocations count +# - is ignored +# - description (can be multi-line) +# ' ' sign +# ------------------------------------------ +0 +Escaping.scala +covtest.\n +\r\n\f +Class +covtest.\n.\r\n\f +\r\n\f +69 +80 +3 +length +Apply +false +0 +false +`\\\\`.length + +1 +Escaping.scala +covtest.\n +\r\n\f +Class +covtest.\n.\r\n\f +\r\n\f +40 +48 +3 +\r\n\f +DefDef +false +0 +false +def `\\r\\ + diff --git a/tests/coverage/pos/For.scoverage.check b/tests/coverage/pos/For.scoverage.check index 80d3ef51116b..9fdc9a7e9d80 100644 --- a/tests/coverage/pos/For.scoverage.check +++ b/tests/coverage/pos/For.scoverage.check @@ -33,8 +33,7 @@ Apply false 0 false -for i <- 1 to 10 do - println(i) +for i <- 1 to 10 do\n println(i) 1 For.scala @@ -136,8 +135,7 @@ Apply false 0 false -for j <- 1 to 10 if f(j) do - println(j) +for j <- 1 to 10 if f(j) do\n println(j) 7 For.scala diff --git a/tests/coverage/run/erased/test.scoverage.check b/tests/coverage/run/erased/test.scoverage.check index 3dfbebe5636a..f31c1a2418a9 100644 --- a/tests/coverage/run/erased/test.scoverage.check +++ b/tests/coverage/run/erased/test.scoverage.check @@ -203,6 +203,5 @@ DefDef false 0 false -@main -def Test +@main\ndef Test diff --git a/tests/coverage/run/inheritance/test.scoverage.check b/tests/coverage/run/inheritance/test.scoverage.check index fe7bfd3ada33..4b75764fcef2 100644 --- a/tests/coverage/run/inheritance/test.scoverage.check +++ b/tests/coverage/run/inheritance/test.scoverage.check @@ -135,6 +135,5 @@ DefDef false 0 false -@main -def Test +@main\ndef Test diff --git a/tests/coverage/run/inline-def/test.scoverage.check b/tests/coverage/run/inline-def/test.scoverage.check index db3bc80cc6e3..784c0a00b62b 100644 --- a/tests/coverage/run/inline-def/test.scoverage.check +++ b/tests/coverage/run/inline-def/test.scoverage.check @@ -169,6 +169,5 @@ DefDef false 0 false -@main -def Test +@main\ndef Test diff --git a/tests/coverage/run/interpolation/test.scoverage.check b/tests/coverage/run/interpolation/test.scoverage.check index c6472a211da6..6b38152cdcc1 100644 --- a/tests/coverage/run/interpolation/test.scoverage.check +++ b/tests/coverage/run/interpolation/test.scoverage.check @@ -288,7 +288,7 @@ Apply false 0 false -println(raw"a\nb") +println(raw"a\\nb") 16 interpolation/test.scala @@ -305,7 +305,7 @@ Apply false 0 false -raw"a\nb" +raw"a\\nb" 17 interpolation/test.scala diff --git a/tests/coverage/run/java-methods/test.scoverage.check b/tests/coverage/run/java-methods/test.scoverage.check index c65d77a64743..7d3752c8db20 100644 --- a/tests/coverage/run/java-methods/test.scoverage.check +++ b/tests/coverage/run/java-methods/test.scoverage.check @@ -152,6 +152,5 @@ DefDef false 0 false -@main -def Test +@main\ndef Test diff --git a/tests/coverage/run/lifting-bool/test.scoverage.check b/tests/coverage/run/lifting-bool/test.scoverage.check index 0fe812024d4b..9d2a3d0f0162 100644 --- a/tests/coverage/run/lifting-bool/test.scoverage.check +++ b/tests/coverage/run/lifting-bool/test.scoverage.check @@ -305,6 +305,5 @@ DefDef false 0 false -@main -def Test +@main\ndef Test diff --git a/tests/coverage/run/lifting/test.scoverage.check b/tests/coverage/run/lifting/test.scoverage.check index 8dffa6778f03..536c5ab0cf1b 100644 --- a/tests/coverage/run/lifting/test.scoverage.check +++ b/tests/coverage/run/lifting/test.scoverage.check @@ -475,6 +475,5 @@ DefDef false 0 false -@main -def Test +@main\ndef Test diff --git a/tests/coverage/run/parameterless/test.scoverage.check b/tests/coverage/run/parameterless/test.scoverage.check index c35283efc640..91a9b1d6597f 100644 --- a/tests/coverage/run/parameterless/test.scoverage.check +++ b/tests/coverage/run/parameterless/test.scoverage.check @@ -339,6 +339,5 @@ DefDef false 0 false -@main -def Test +@main\ndef Test diff --git a/tests/coverage/run/trait/test.scoverage.check b/tests/coverage/run/trait/test.scoverage.check index 42f7bbc0f22e..8dbf64238cfa 100644 --- a/tests/coverage/run/trait/test.scoverage.check +++ b/tests/coverage/run/trait/test.scoverage.check @@ -186,6 +186,5 @@ DefDef false 0 false -@main -def Test +@main\ndef Test diff --git a/tests/coverage/run/varargs/test_1.scoverage.check b/tests/coverage/run/varargs/test_1.scoverage.check index 904735da3632..2c4edea68fcc 100644 --- a/tests/coverage/run/varargs/test_1.scoverage.check +++ b/tests/coverage/run/varargs/test_1.scoverage.check @@ -288,6 +288,5 @@ DefDef false 0 false -@main -def Test +@main\ndef Test