Skip to content

Commit a30efa6

Browse files
committed
Merge pull request #76 from retronym/topic/defPath-accum
Test and refactor TreeInfo#defPath
2 parents 027abb4 + c208fe9 commit a30efa6

File tree

3 files changed

+44
-22
lines changed

3 files changed

+44
-22
lines changed

src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -421,30 +421,19 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
421421
* Pre: `sym` must have a position.
422422
*/
423423
def defPath(sym: Symbol, root: Tree)(implicit ctx: Context): List[Tree] = ctx.debugTraceIndented(s"defpath($sym with position ${sym.pos}, ${root.show})") {
424-
def show(from: Any): String = from match {
425-
case tree: Trees.Tree[_] => s"${tree.show} with attachments ${tree.allAttachments}"
426-
case x: printing.Showable => x.show
427-
case x => x.toString
428-
}
429-
430-
def search(from: Any): List[Tree] = ctx.debugTraceIndented(s"search(${show(from)})") {
431-
from match {
432-
case tree: Tree => // Dotty problem: cannot write Tree @ unchecked, this currently gives a syntax error
433-
if (definedSym(tree) == sym) tree :: Nil
434-
else if (tree.envelope.contains(sym.pos)) {
435-
val p = search(tree.productIterator)
436-
if (p.isEmpty) p else tree :: p
437-
} else Nil
438-
case xs: Iterable[_] =>
439-
search(xs.iterator)
440-
case xs: Iterator[_] =>
441-
xs.map(search).find(_.nonEmpty).getOrElse(Nil)
442-
case _ =>
443-
Nil
424+
require(sym.pos.exists)
425+
object accum extends TreeAccumulator[List[Tree]] {
426+
def apply(x: List[Tree], tree: Tree): List[Tree] = {
427+
if (tree.envelope.contains(sym.pos))
428+
if (definedSym(tree) == sym) tree :: x
429+
else {
430+
val x1 = foldOver(x, tree)
431+
if (x1 ne x) tree :: x1 else x1
432+
}
433+
else x
444434
}
445435
}
446-
require(sym.pos.exists)
447-
search(root)
436+
accum(Nil, root)
448437
}
449438

450439
/** The statement sequence that contains a definition of `sym`, or Nil

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
330330
def deepFold[T](z: T)(op: (T, tpd.Tree) => T) =
331331
new DeepFolder(op).apply(z, tree)
332332

333+
def find[T](pred: (tpd.Tree) => Boolean): Option[tpd.Tree] =
334+
shallowFold[Option[tpd.Tree]](None)((accum, tree) => if (pred(tree)) Some(tree) else accum)
335+
333336
def subst(from: List[Symbol], to: List[Symbol])(implicit ctx: Context): ThisTree =
334337
new TreeMapper(typeMap = new ctx.SubstSymMap(from, to)).apply(tree)
335338

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package dotty.tools.dotc
2+
package ast
3+
4+
import org.junit.Test
5+
import test.DottyTest
6+
import core.Names._
7+
import core.Types._
8+
import core.Symbols._
9+
import org.junit.Assert._
10+
11+
class TreeInfoTest extends DottyTest {
12+
13+
import tpd._
14+
15+
@Test
16+
def testDefPath = checkCompile("frontend", "class A { def bar = { val x = { val z = 0; 0} }} ") {
17+
(tree, context) =>
18+
implicit val ctx = context
19+
val xTree = tree.find(tree => tree.symbol.name == termName("x")).get
20+
val path = defPath(xTree.symbol, tree)
21+
assertEquals(List(
22+
("PackageDef", EMPTY_PACKAGE),
23+
("TypeDef", typeName("A")),
24+
("Template", termName("<local A>")),
25+
("DefDef", termName("bar")),
26+
("Block", NoSymbol.name),
27+
("ValDef", termName("x"))
28+
), path.map(x => (x.productPrefix, x.symbol.name)))
29+
}
30+
}

0 commit comments

Comments
 (0)