diff --git a/main/settings/src/main/scala/sbt/std/KeyMacro.scala b/main/settings/src/main/scala/sbt/std/KeyMacro.scala index d476c1b5f..c31169b07 100644 --- a/main/settings/src/main/scala/sbt/std/KeyMacro.scala +++ b/main/settings/src/main/scala/sbt/std/KeyMacro.scala @@ -31,15 +31,20 @@ private[sbt] object KeyMacro def definingValName(c: Context, invalidEnclosingTree: String => String): String = { import c.universe.{Apply=>ApplyTree,_} - val methodName = c.macroApplication.symbol.name.decoded + val methodName = c.macroApplication.symbol.name + def processName(n: Name): String = n.decoded.trim // trim is not strictly correct, but macros don't expose the API necessary def enclosingVal(trees: List[c.Tree]): String = + { trees match { - case vd @ ValDef(_, name, _, _) :: ts => name.decoded + case vd @ ValDef(_, name, _, _) :: ts => processName(name) case (_: ApplyTree | _: Select | _: TypeApply) :: xs => enclosingVal(xs) + // lazy val x: X = has this form for some reason (only when the explicit type is present, though) + case Block(_, _) :: DefDef(mods, name, _, _, _, _) :: xs if mods.hasFlag(Flag.LAZY) => processName(name) case _ => - c.error(c.enclosingPosition, invalidEnclosingTree(methodName)) + c.error(c.enclosingPosition, invalidEnclosingTree(methodName.decoded)) "" } + } enclosingVal(enclosingTrees(c).toList) } def enclosingTrees(c: Context): Seq[c.Tree] = diff --git a/main/src/test/scala/ProjectMacro.scala b/main/src/test/scala/ProjectMacro.scala new file mode 100644 index 000000000..6cb9d54c9 --- /dev/null +++ b/main/src/test/scala/ProjectMacro.scala @@ -0,0 +1,67 @@ +package sbt + + import org.scalacheck._ + import Prop._ + import Project.project + import java.io.File + +class ProjectDefs +{ + lazy val p = project + + val x = project + + // should not compile + // def y = project + + val z = project in new File("dir") + + val a: Project = project + + lazy val aa: Project = project +} + + +object ProjectMacro extends Properties("ProjectMacro") +{ + lazy val pd = new ProjectDefs + import pd._ + + def secure(f: => Prop): Prop = try { + Prop.secure(f) + } catch { case e: Throwable => + e.printStackTrace + throw e + } + + property("Explicit type on lazy val supported") = secure { + check(aa, "aa", "aa") + } + + property("Explicit type on val supported") = secure { + check(a, "a", "a") + } + + property("lazy vals supported") = secure { + check(p, "p", "p") + } + + property("plain vals supported") = secure { + check(x, "x", "x") + } + + property("Directory overridable") = secure { + check(z, "z", "dir") + } + + def check(p: Project, id: String, dir: String): Prop = + { + s"Expected id: $id" |: + s"Expected dir: $dir" |: + s"Actual id: ${p.id}" |: + s"Actual dir: ${p.base}" |: + (p.id == id) && + (p.base.getName == dir) + } +} + \ No newline at end of file