Permalink
Browse files

Created a custom Tree Traverser to traverse TypeTree nodes

The available compiler's ``Traverser`` does not recurse inside ``TypeTree``
nodes This is inconvenient as compiler's tree's type such as ``ExistentialTypeTree``
are "hidden" inside ``TypeTree`` node. Therefore I have created a custom tree traverser
``TypeTreeTraverser`` that tries to traverse ``TypeTree`` nodes when possible.

This makes the ``SafeSymbol.safeSymbol`` routine simpler as it does no longer need to unroll
``TypeTree`` nodes.
  • Loading branch information...
1 parent fbb7d12 commit 376d293897534a4fbaafc1b6e98f7b1273b5dc1b @dotta dotta committed Apr 11, 2012
@@ -46,10 +46,10 @@ object SymbolClassification {
}
class SymbolClassification(protected val sourceFile: SourceFile, val global: ScalaPresentationCompiler, useSyntacticHints: Boolean)
- extends SafeSymbol with SymbolClassificationDebugger with SymbolTests with HasLogger {
+ extends SafeSymbol with TypeTreeTraverser with SymbolClassificationDebugger with SymbolTests with HasLogger {
import SymbolClassification._
- import global._
+ import global.{ Symbol, Position, NoSymbol }
def compilationUnitOfFile(f: AbstractFile) = global.unitOfFile.get(f)
@@ -0,0 +1,68 @@
+package scala.tools.eclipse.semantichighlighting.classifier
+
+import scala.tools.eclipse.javaelements.ScalaCompilationUnit
+import scala.collection.mutable.ListBuffer
+
+trait TypeTreeTraverser {
+ val global: tools.nsc.Global
+
+ import global._
+
+ implicit def tree2treeWrapper(tree: Tree): TreeWrapper = new TreeWrapper(tree)
+
+ /**
+ * Monadic wrapper for a Tree. The wrapper is actually very similar
+ * to {{{TreeOps}}}, with the difference that is uses the below defined
+ * {{{TypeTreeTraverser}}} in place of the standard {{{Traverser}}} to
+ * traverse the Tree.
+ */
+ class TreeWrapper(tree: Tree) {
+ private val adaptee = new TreeOps(tree)
+
+ def isType: Boolean = adaptee.isType
+
+ def foreach(f: Tree => Unit) {
+ new ForeachTypeTreeTraverser(f).traverse(tree)
+ }
+ // TODO: Need to replace {{{filter}} with {{{withFilter}}}
+ def filter(p: Tree => Boolean): List[Tree] = {
+ val ft = new FilterTypeTreeTraverser(p)
+ ft.traverse(tree)
+ ft.hits.toList
+ }
+ }
+
+ //Note [mirco]: The implementation was copied from {{{Trees.ForeachTreeTraverser}}}. Can this be avoided?
+ private class ForeachTypeTreeTraverser(f: Tree => Unit) extends TypeTreeTraverser {
+ override def traverse(t: Tree) {
+ f(t)
+ super.traverse(t)
+ }
+ }
+
+ //Note [mirco]: The implementation was copied from {{{Trees.ForeachTreeTraverser}}}. Can this be avoided?
+ private class FilterTypeTreeTraverser(p: Tree => Boolean) extends TypeTreeTraverser {
+ val hits = new ListBuffer[Tree]
+ override def traverse(t: Tree) {
+ if (p(t)) hits += t
+ super.traverse(t)
+ }
+ }
+
+ /**
+ * Traverse {{{TypeTree}} AST nodes if an {{{original}}} (underlying) Tree exists.
+ * This let us decompose traverse type trees such as {{{ExistentialTypeTree}}} which
+ * would otherwise be ignored by the standard {{{scala.tools.nsc.Trees.Traverser}}}
+ * implementation
+ */
+ private trait TypeTreeTraverser extends Traverser {
+ override def traverse(tree: Tree): Unit = tree match {
+ case tpeTree: TypeTree =>
+ val original = tpeTree.original
+ if (original == null || original == tpeTree) super.traverse(tpeTree)
+ else traverse(original)
+
+ case _ => super.traverse(tree)
+ }
+ }
+}

0 comments on commit 376d293

Please sign in to comment.