Skip to content

Commit b36337a

Browse files
author
beha
committed
- Fixed evaluation of arguments passed to the primary constructor with Scala 2.11
- Workaround for evaluation of arguments passed to the primary constructor with Scala 2.10 - Added test for implicit parameter lists - Added test for empty parameter lists
1 parent 695deca commit b36337a

File tree

9 files changed

+109
-21
lines changed

9 files changed

+109
-21
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,23 @@ def foo(bar: String, baz: Int)(p: Boolean): Unit = {
492492
foo("baz", 42)(true) // foo(bar=baz, baz=42)(p=true)
493493
```
494494

495+
Please note, that it's currently not possible to access the arguments passed
496+
to a constructor if you are using Scala 2.10, e.g. the following code will
497+
work as expected with 2.11, but _not_ with 2.10:
498+
```scala
499+
def debug(implicit name: sourcecode.Name, args: sourcecode.Args): Unit = {
500+
println(name.value + args.value.map(_.map(a => a.source + "=" + a.value).mkString("(", ", ", ")")).mkString(""))
501+
}
502+
503+
class Foo(arg1: String, arg2: Int) {
504+
debug
505+
}
506+
507+
new Foo("bar", 42)
508+
```
509+
510+
For 2.10 `sourcecode.Args.value will be an empty list.`
511+
495512
Embedding Domain-Specific Languages
496513
-----------------------------------
497514

build.sbt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ lazy val sourcecode = crossProject.settings(
2222
if (scalaVersion.value startsWith "2.10.") Seq(baseDirectory.value / ".."/"shared"/"src"/ "main" / "scala-2.10")
2323
else Seq(baseDirectory.value / ".."/"shared" / "src" / "main" / "scala-2.11")
2424
},
25+
unmanagedSourceDirectories in Test ++= {
26+
if (scalaVersion.value startsWith "2.10.") Seq(baseDirectory.value / ".."/"shared"/"src"/ "test" / "scala-2.10")
27+
else Seq(baseDirectory.value / ".."/"shared" / "src" / "test" / "scala-2.11")
28+
},
2529
publishTo := Some("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2"),
2630

2731
pomExtra :=

sourcecode/shared/src/main/scala-2.10/sourcecode/Compat.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,12 @@ object Compat{
99
.owner
1010
.asInstanceOf[c.Symbol]
1111
}
12+
13+
def enclosingParamList(c: Context): List[List[c.Symbol]] = {
14+
def nearestClassOrMethod(owner: c.Symbol): c.Symbol =
15+
if (owner.isMethod || owner.isClass) owner else nearestClassOrMethod(owner.owner)
16+
17+
val com = nearestClassOrMethod(enclosingOwner(c))
18+
if (com.isClass) List() else com.asMethod.paramss
19+
}
1220
}

sourcecode/shared/src/main/scala-2.11/sourcecode/Compat.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,13 @@ package sourcecode
33
object Compat{
44
type Context = scala.reflect.macros.blackbox.Context
55
def enclosingOwner(c: Context) = c.internal.enclosingOwner
6+
7+
def enclosingParamList(c: Context): List[List[c.Symbol]] = {
8+
def nearestEnclosingMethod(owner: c.Symbol): c.Symbol =
9+
if (owner.isMethod) owner
10+
else if (owner.isClass) owner.asClass.primaryConstructor
11+
else nearestEnclosingMethod(owner.owner)
12+
13+
nearestEnclosingMethod(enclosingOwner(c)).asMethod.paramLists
14+
}
615
}

sourcecode/shared/src/main/scala/sourcecode/SourceContext.scala

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,7 @@ object Args extends SourceCompanion[Seq[Seq[Text[_]]], Args](new Args(_)) {
117117
implicit def generate: Args = macro impl
118118
def impl(c: Compat.Context): c.Expr[Args] = {
119119
import c.universe._
120-
121-
def enclosingMethod(owner: Symbol): MethodSymbol =
122-
if (owner.isMethod) owner.asMethod else enclosingMethod(owner.owner)
123-
124-
val method = enclosingMethod(Compat.enclosingOwner(c))
125-
val param = method.asMethod.paramss
120+
val param = Compat.enclosingParamList(c)
126121
val texts = param.map(_.map(p => c.Expr[Text[_]](q"""sourcecode.Text($p, ${p.name.toString})""")))
127122
val textSeqs = texts.map(s => c.Expr(q"""Seq(..$s)"""))
128123
c.Expr[Args](q"""Seq(..$textSeqs)""")
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package sourcecode
2+
3+
object ArgsPrimaryConstructorTests {
4+
def apply() = {
5+
6+
var args: Seq[Seq[(String, Any)]] = Seq()
7+
8+
def debug(implicit arguments: sourcecode.Args): Unit = args = arguments.value.map(_.map(t => t.source -> t.value))
9+
10+
class Foo(p1: String, p2: Long, p3: Boolean)(foo: String, bar: String) {
11+
debug
12+
}
13+
14+
new Foo("text", 42, false)("foo", "bar")
15+
assert(args == Seq())
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package sourcecode
2+
3+
object ArgsPrimaryConstructorTests {
4+
def apply() = {
5+
6+
var args: Seq[Seq[(String, Any)]] = Seq()
7+
8+
def debug(implicit arguments: sourcecode.Args): Unit = args = arguments.value.map(_.map(t => t.source -> t.value))
9+
10+
class Foo(p1: String, p2: Long, p3: Boolean)(foo: String, bar: String) {
11+
debug
12+
}
13+
14+
new Foo("text", 42, false)("foo", "bar")
15+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42, "p3" -> false), Seq("foo" -> "foo", "bar" -> "bar")))
16+
}
17+
}

sourcecode/shared/src/test/scala/sourcecode/ArgsTests.scala

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,9 @@ package sourcecode
33
object ArgsTests {
44
def apply() = {
55

6-
def debug(implicit args: sourcecode.Args): Unit = {
7-
assert(args.value.size == 2)
8-
assert(args.value(0).size == 3)
9-
assert(args.value(0)(0).source == "p1")
10-
assert(args.value(0)(0).value == "text")
11-
assert(args.value(0)(1).source == "p2")
12-
assert(args.value(0)(1).value == 42)
13-
assert(args.value(0)(2).source == "p3")
14-
assert(args.value(0)(2).value == false)
15-
assert(args.value(1).size == 2)
16-
assert(args.value(1)(0).source == "foo")
17-
assert(args.value(1)(0).value == "foo")
18-
assert(args.value(1)(1).source == "bar")
19-
assert(args.value(1)(1).value == "bar")
20-
}
6+
var args: Seq[Seq[(String, Any)]] = Seq()
7+
8+
def debug(implicit arguments: sourcecode.Args): Unit = args = arguments.value.map(_.map(t => t.source -> t.value))
219

2210
def foo(p1: String, p2: Long, p3: Boolean)(foo: String, bar: String): Unit = {
2311
debug
@@ -30,7 +18,39 @@ object ArgsTests {
3018
}
3119
}
3220

21+
def baz: Unit = {
22+
debug
23+
}
24+
25+
def withImplicit(p1: String, p2: Long, p3: Boolean)(implicit foo: String): Unit = {
26+
debug
27+
}
28+
29+
class Foo(p1: String, p2: Long, p3: Boolean)(foo: String, bar: String) {
30+
31+
def this(p1: String, p2: Long) = {
32+
this(p1, p2, false)("foo", "bar")
33+
debug
34+
}
35+
}
36+
37+
new Foo("text", 42)
38+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42)))
39+
3340
foo("text", 42, false)("foo", "bar")
41+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42, "p3" -> false), Seq("foo" -> "foo", "bar" -> "bar")))
42+
3443
bar("text", 42, false)("foo", "bar")
44+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42, "p3" -> false), Seq("foo" -> "foo", "bar" -> "bar")))
45+
46+
baz
47+
assert(args == Seq())
48+
49+
withImplicit("text", 42, false)("foo")
50+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42, "p3" -> false), Seq("foo" -> "foo")))
51+
52+
implicit val implicitFoo = "bar"
53+
withImplicit("text", 42, false)
54+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42, "p3" -> false), Seq("foo" -> "bar")))
3555
}
3656
}

sourcecode/shared/src/test/scala/sourcecode/Tests.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ object Tests{
2121
ManualImplicit()
2222
TextTests()
2323
ArgsTests()
24+
ArgsPrimaryConstructorTests()
2425

2526
println("================LogExample================")
2627
logExample()

0 commit comments

Comments
 (0)