summaryrefslogtreecommitdiff
path: root/src/scaladoc/scala/tools/nsc/doc/model/TreeFactory.scala
blob: 86a7a67160beda4da568dd58bcc325c8a3f81248 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package scala.tools.nsc
package doc
package model

import scala.collection._
import scala.reflect.internal.util.{RangePosition, OffsetPosition, SourceFile}

/** The goal of this trait is , using makeTree,
  * to browse a tree to
  * 1- have the String of the complete tree (tree.expression)
  * 2- fill references to create hyperLinks later in html.pageTemplate
  *
  * It is applied in ModelFactory => makeTree
  *
  */

trait TreeFactory { thisTreeFactory: ModelFactory with TreeFactory =>

  val global: Global
  import global._

  def makeTree(rhs: Tree): TreeEntity = {

    val expr = new StringBuilder
    var refs = new immutable.TreeMap[Int, (Entity, Int)] // start, (Entity to be linked to , end)

    rhs.pos match {
      case pos: RangePosition => {
        val source: SourceFile = pos.source
        val firstIndex = pos.start
        val lastIndex = pos.end

        assert(firstIndex < lastIndex, "Invalid position indices for tree " + rhs + " (" + firstIndex + ", " + lastIndex + ")")
        expr.appendAll(source.content, firstIndex, lastIndex - firstIndex)

        val traverser = new Traverser {

          /** Finds the Entity on which we will later create a link on,
           * stores it in tree.refs with its position
           */
          def makeLink(rhs: Tree){
            val start = pos.start - firstIndex
            val end = pos.end - firstIndex
            if(start != end) {
              var asym = rhs.symbol
              if (asym.isClass) makeTemplate(asym) match{
                case docTmpl: DocTemplateImpl =>
                  refs += ((start, (docTmpl,end)))
                case _ =>
              }
              else if (asym.isTerm && asym.owner.isClass){
                if (asym.isSetter) asym = asym.getter(asym.owner)
                makeTemplate(asym.owner) match {
                  case docTmpl: DocTemplateImpl =>
                    val mbrs: Option[MemberImpl] = findMember(asym, docTmpl)
                    mbrs foreach { mbr => refs += ((start, (mbr,end))) }
                  case _ =>
                }
              }
            }
          }
          /**
           * Goes through the tree and makes links when a Select occurs,
           * The case of New(_) is ignored because the object we want to create a link on
           * will be reached with recursivity and we don't want a link on the "new" string
           * If a link is not created, its case is probably not defined in here
           */
          override def traverse(tree: Tree) = tree match {
            case Select(qualifier, name) =>
              qualifier match {
                case New(_) =>
                  case _ => makeLink(tree)
              }
            traverse(qualifier)
            case Ident(_) => makeLink(tree)
            case _ =>
              super.traverse(tree)
          }
        }

        traverser.traverse(rhs)

        new TreeEntity {
          val expression = expr.toString
          val refEntity = refs
        }
      }
      case _ =>
        new TreeEntity {
          val expression = rhs.toString
          val refEntity = new immutable.TreeMap[Int, (Entity, Int)]
        }
    }
  }
}