Skip to content

Commit 6d1f17e

Browse files
committed
Updated location code
1 parent 2a58a1e commit 6d1f17e

File tree

6 files changed

+87
-65
lines changed

6 files changed

+87
-65
lines changed
Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1 @@
11
package scoverage
2-
3-
object ClassType {
4-
case object Object extends ClassType
5-
case object Class extends ClassType
6-
case object Trait extends ClassType
7-
}
8-
9-
/** @author Stephen Samuel */
10-
sealed trait ClassType

scalac-scoverage-plugin/src/main/scala/scoverage/IOUtils.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ object IOUtils {
8787
{stmt.source}
8888
</source>
8989
<package>
90-
{stmt.location._package}
90+
{stmt.location.packageName}
9191
</package>
9292
<class>
93-
{stmt.location._class}
93+
{stmt.location.className}
9494
</class>
9595
<classType>
9696
{stmt.location.classType.toString}
@@ -99,7 +99,7 @@ object IOUtils {
9999
{stmt.location.method}
100100
</method>
101101
<path>
102-
{stmt.location.path}
102+
{stmt.location.sourcePath}
103103
</path>
104104
<id>
105105
{stmt.id.toString}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package scoverage
2+
3+
import scala.tools.nsc.Global
4+
5+
case class Location(packageName: String,
6+
className: String,
7+
classType: ClassType,
8+
method: String,
9+
sourcePath: String) extends java.io.Serializable {
10+
val fqn = (packageName + ".").replace("<empty>.", "") + className
11+
}
12+
13+
object Location {
14+
15+
def apply(global: Global): global.Tree => Option[Location] = { tree =>
16+
17+
def className(s: global.Symbol): String = {
18+
// anon functions are enclosed in proper classes.
19+
if (s.enclClass.isAnonymousFunction) className(s.owner)
20+
else s.enclClass.nameString
21+
}
22+
23+
def classType(s: global.Symbol): ClassType = {
24+
if (s.owner.enclClass.isTrait) ClassType.Trait
25+
else if (s.owner.enclClass.isModule) ClassType.Object
26+
else ClassType.Class
27+
}
28+
29+
def enclosingMethod(s: global.Symbol): String = {
30+
// check if we are in a proper method and return that, otherwise traverse up
31+
if (s.enclClass.isAnonymousFunction) enclosingMethod(s.owner)
32+
else Option(s.owner.enclMethod.nameString).getOrElse("<none>")
33+
}
34+
35+
Option(tree.symbol) map {
36+
symbol =>
37+
Location(
38+
symbol.enclosingPackage.fullName,
39+
className(symbol),
40+
classType(symbol),
41+
enclosingMethod(symbol),
42+
symbol.sourceFile.canonicalPath)
43+
}
44+
}
45+
}

scalac-scoverage-plugin/src/main/scala/scoverage/coverage.scala

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ case class Coverage()
3838
trait MethodBuilders {
3939
def statements: Iterable[MeasuredStatement]
4040
def methods: Seq[MeasuredMethod] = {
41-
statements.groupBy(stmt => stmt.location._package + "/" + stmt.location._class + "/" + stmt.location.method)
41+
statements.groupBy(stmt => stmt.location.packageName + "/" + stmt.location.className + "/" + stmt.location.method)
4242
.map(arg => MeasuredMethod(arg._1, arg._2))
4343
.toSeq
4444
}
@@ -49,13 +49,13 @@ trait PackageBuilders {
4949
def statements: Iterable[MeasuredStatement]
5050
def packageCount = packages.size
5151
def packages: Seq[MeasuredPackage] = {
52-
statements.groupBy(_.location._package).map(arg => MeasuredPackage(arg._1, arg._2)).toSeq.sortBy(_.name)
52+
statements.groupBy(_.location.packageName).map(arg => MeasuredPackage(arg._1, arg._2)).toSeq.sortBy(_.name)
5353
}
5454
}
5555

5656
trait ClassBuilders {
5757
def statements: Iterable[MeasuredStatement]
58-
def classes = statements.groupBy(_.location._class).map(arg => MeasuredClass(arg._1, arg._2))
58+
def classes = statements.groupBy(_.location.className).map(arg => MeasuredClass(arg._1, arg._2))
5959
def classCount: Int = classes.size
6060
}
6161

@@ -99,15 +99,16 @@ case class MeasuredStatement(source: String,
9999
def isInvoked = count > 0
100100
}
101101

102-
case class Location(_package: String,
103-
_class: String,
104-
classType: ClassType,
105-
method: String,
106-
path: String)
107-
extends java.io.Serializable {
108-
val fqn = (_package + ".").replace("<empty>.", "") + _class
102+
object ClassType {
103+
case object Object extends ClassType
104+
case object Class extends ClassType
105+
case object Trait extends ClassType
109106
}
110107

108+
sealed trait ClassType
109+
110+
111+
111112
case class ClassRef(name: String) {
112113
lazy val simpleName = name.split(".").last
113114
lazy val getPackage = name.split(".").dropRight(1).mkString(".")

scalac-scoverage-plugin/src/main/scala/scoverage/plugin.scala

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ class ScoverageInstrumentationComponent(val global: Global)
101101

102102
import global._
103103

104+
// contains the location of the last node
104105
var location: Location = null
105106

106107
/**
@@ -185,33 +186,11 @@ class ScoverageInstrumentationComponent(val global: Global)
185186
def isFileIncluded(source: SourceFile): Boolean = coverageFilter.isFileIncluded(source)
186187
def isStatementIncluded(pos: Position): Boolean = coverageFilter.isLineIncluded(pos)
187188

188-
def className(s: Symbol): String = {
189-
if (s.enclClass.isAnonymousFunction || s.enclClass.isAnonymousFunction)
190-
className(s.owner)
191-
else
192-
s.enclClass.nameString
193-
}
194-
195-
def enclosingMethod(s: Symbol): String = {
196-
if (s.enclClass.isAnonymousFunction || s.enclClass.isAnonymousFunction)
197-
enclosingMethod(s.owner)
198-
else
199-
Option(s.owner.enclMethod.nameString).getOrElse("<none>")
200-
}
201-
202-
def updateLocation(s: Symbol) {
203-
val classType = {
204-
if (s.owner.enclClass.isTrait) ClassType.Trait
205-
else if (s.owner.enclClass.isModule) ClassType.Object
206-
else ClassType.Class
189+
def updateLocation(t: Tree) {
190+
Location(global)(t) match {
191+
case Some(loc) => this.location = loc
192+
case _ => println(s"[warn] Cannot update location for $t")
207193
}
208-
location = Location(
209-
s.enclosingPackage.fullName,
210-
className(s),
211-
classType,
212-
enclosingMethod(s),
213-
s.sourceFile.canonicalPath
214-
)
215194
}
216195

217196
def transformPartial(c: ClassDef): ClassDef = {
@@ -331,7 +310,7 @@ class ScoverageInstrumentationComponent(val global: Global)
331310

332311
case c: ClassDef =>
333312
if (isFileIncluded(c.pos.source) && isClassIncluded(c.symbol)) {
334-
updateLocation(c.symbol)
313+
updateLocation(c)
335314
super.transform(tree)
336315
} else {
337316
c
@@ -352,10 +331,13 @@ class ScoverageInstrumentationComponent(val global: Global)
352331
case d: DefDef if d.symbol != null && d.tpt.symbol.fullNameString == "scala.reflect.api.Exprs.Expr" =>
353332
tree
354333

355-
// todo do we really want to ignore?
356-
case d: DefDef if d.symbol.isPrimaryConstructor => tree
357-
// todo definitely want to instrument user level constructors
358-
case d: DefDef if tree.symbol.isConstructor => tree
334+
case d: DefDef if d.symbol.isPrimaryConstructor =>
335+
updateLocation(d)
336+
super.transform(d)
337+
338+
case d: DefDef if tree.symbol.isConstructor =>
339+
updateLocation(d)
340+
super.transform(d)
359341

360342
/**
361343
* Case class accessors for vals
@@ -372,7 +354,7 @@ class ScoverageInstrumentationComponent(val global: Global)
372354
* Lazy stable DefDefs are generated as the impl for lazy vals.
373355
*/
374356
case d: DefDef if d.symbol.isStable && d.symbol.isGetter && d.symbol.isLazy =>
375-
updateLocation(d.symbol)
357+
updateLocation(d)
376358
treeCopy.DefDef(d, d.mods, d.name, d.tparams, d.vparamss, d.tpt, process(d.rhs))
377359

378360
/**
@@ -409,7 +391,7 @@ class ScoverageInstrumentationComponent(val global: Global)
409391
* this is expressed by having `tpt` set to `TypeTree()` (but not to an `EmptyTree`!).
410392
*/
411393
case d: DefDef =>
412-
updateLocation(d.symbol)
394+
updateLocation(d)
413395
treeCopy.DefDef(d, d.mods, d.name, d.tparams, d.vparamss, d.tpt, process(d.rhs))
414396

415397
case EmptyTree => tree
@@ -445,16 +427,18 @@ class ScoverageInstrumentationComponent(val global: Global)
445427
}
446428

447429
// a synthetic object is a generated object, such as case class companion
448-
case m: ModuleDef if m.symbol.isSynthetic => super.transform(tree)
430+
case m: ModuleDef if m.symbol.isSynthetic =>
431+
updateLocation(m)
432+
super.transform(tree)
449433

450434
// user defined objects
451435
case m: ModuleDef =>
452436
if (isFileIncluded(m.pos.source) && isClassIncluded(m.symbol)) {
453-
updateLocation(m.symbol)
437+
updateLocation(m)
454438
super.transform(tree)
455-
}
456-
else
439+
} else {
457440
m
441+
}
458442

459443
/**
460444
* match with syntax `New(tpt)`.
@@ -532,6 +516,7 @@ class ScoverageInstrumentationComponent(val global: Global)
532516
case t: TypeDef => super.transform(tree)
533517

534518
case t: Template =>
519+
updateLocation(t)
535520
treeCopy.Template(tree, t.parents, t.self, transformStatements(t.body))
536521

537522
case _: TypeTree => super.transform(tree)
@@ -554,7 +539,7 @@ class ScoverageInstrumentationComponent(val global: Global)
554539

555540
// we need to remove the final mod so that we keep the code in order to check its invoked
556541
case v: ValDef if v.mods.isFinal =>
557-
updateLocation(v.symbol)
542+
updateLocation(v)
558543
treeCopy.ValDef(v, v.mods.&~(ModifierFlags.FINAL), v.name, v.tpt, process(v.rhs))
559544

560545
/**
@@ -570,7 +555,7 @@ class ScoverageInstrumentationComponent(val global: Global)
570555
* This includes top level non-lazy vals. Lazy vals are generated as stable defs.
571556
*/
572557
case v: ValDef =>
573-
updateLocation(v.symbol)
558+
updateLocation(v)
574559
treeCopy.ValDef(tree, v.mods, v.name, v.tpt, process(v.rhs))
575560

576561
case _ =>

scalac-scoverage-plugin/src/main/scala/scoverage/report/ScoverageXmlWriter.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ class ScoverageXmlWriter(sourceDir: File, outputDir: File, debug: Boolean) {
2121
def statement(stmt: MeasuredStatement): Node = {
2222
debug match {
2323
case true =>
24-
<statement package={stmt.location._package}
25-
class={stmt.location._class}
24+
<statement package={stmt.location.packageName}
25+
class={stmt.location.className}
2626
method={stmt.location.method}
2727
start={stmt.start.toString}
2828
line={stmt.line.toString}
@@ -33,8 +33,8 @@ class ScoverageXmlWriter(sourceDir: File, outputDir: File, debug: Boolean) {
3333
{IOUtils.escape(stmt.desc)}
3434
</statement>
3535
case false =>
36-
<statement package={stmt.location._package}
37-
class={stmt.location._class}
36+
<statement package={stmt.location.packageName}
37+
class={stmt.location.className}
3838
method={stmt.location.method}
3939
start={stmt.start.toString}
4040
line={stmt.line.toString}

0 commit comments

Comments
 (0)