summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/symtab/SymbolWalker.scala
blob: d93b69c135eaa47f0a9d1c0b8790a965e4f13e57 (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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
package scala.tools.nsc.symtab

trait SymbolWalker {
  val global : Global
  import scala.tools.nsc.util._
  import global._
  import scala.collection.mutable.LinkedHashSet
  trait Visitor {
    def update(pos : Position, sym : Symbol) : Unit
    def contains(pos : Position) : Boolean
    def apply(pos : Position) : Symbol
    def putDef(sym : Symbol, pos : Position) : Unit = ()
  }
  import scala.collection.mutable.Map
  /*
  implicit def map2use(map : Map[Position,Symbol]) = new Visitor {
    def update(pos : Position, sym : Symbol) : Unit = map.update(pos, sym)
    def contains(pos : Position) : Boolean = map.contains(pos)
    def apply(pos : Position) : Symbol = map.apply(pos)
  }
  */
  def walk(tree: Tree, visitor : Visitor)(fid : (util.Position) => Option[String]) : Unit = {
    val visited = new LinkedHashSet[Tree]
    def f(t : Tree) : Unit = {
      if (visited.add(t)) return
      def fs(l : List[Tree]) : Unit = {
        val i = l.iterator
        while (i.hasNext) f(i.next)
      }
      def fss(l : List[List[Tree]]) : Unit = {
        val i = l.iterator
        while (i.hasNext) fs(i.next)
      }
      if (t.isInstanceOf[StubTree]) return
      def asTypeRef = t.tpe.asInstanceOf[TypeRef]
      val sym = (t,t.tpe) match {
        case (Super(_,_),SuperType(_,supertp)) if supertp.typeSymbol != NoSymbol && supertp.typeSymbol != null => supertp.typeSymbol
        case _ if t.symbol != NoSymbol && t.symbol != null => t.symbol
        case (t : TypeTree, tp) if tp != null && tp.typeSymbol != null && tp.typeSymbol != NoSymbol => tp.typeSymbol
        case (t : TypeTree, tp) if tp != null && tp.resultType != null && tp.resultType.typeSymbol != null => tp.resultType.typeSymbol
        case (t, tpe : Type) if tpe != null && (t.symbol eq NoSymbol) && t.isTerm && tpe.termSymbol != null =>
          tpe.termSymbol
        case (t, tpe : Type) if tpe != null && (t.symbol eq NoSymbol) && tpe.typeSymbol != null =>
              if (t.tpe.isInstanceOf[TypeRef]) asTypeRef.sym // XXX: looks like a bug
             else tpe.typeSymbol
        case _ => NoSymbol
      }
      if (sym != null && sym != NoSymbol /* && !sym.hasFlag(SYNTHETIC) */) {
        var id = fid(t.pos)
        val doAdd = if (id.isDefined) {
          if (id.get.charAt(0) == '`') id = Some(id.get.substring(1, id.get.length - 1))
          val name = sym.name.decode.trim
          if ((name startsWith id.get) || (id.get startsWith name)) true
          else {
            false
          }
        } else false
        if (doAdd) {

        if (!visitor.contains(t.pos)) {
          visitor(t.pos) = sym
        } else {
          val existing = visitor(t.pos)
          if (sym.sourceFile != existing.sourceFile || sym.pos != existing.pos) {
            (sym,existing) match {
            case (sym,existing) if sym.pos == existing.pos =>
            case (sym : TypeSymbol ,_ : ClassSymbol) => visitor(t.pos) = sym
            case (_ : ClassSymbol,_ : TypeSymbol) => // nothing
            case _ if sym.isModule && existing.isValue => // nothing
            case _ if sym.isClass && existing.isMethod => // nothing
            case _ =>
              assert(true)
            }
          }
        }}
      }
      t match {
      case t : DefTree if t.symbol != NoSymbol =>
        if (t.pos != NoPosition)
          visitor.putDef(t.symbol, t.pos)
          if (t.symbol.isClass) {
            val factory = NoSymbol // XXX: t.symbol.caseFactory
            if (factory != NoSymbol) {
              visitor.putDef(factory, t.pos)
            }
        }
      case t : TypeBoundsTree => f(t.lo); f(t.hi)
      case t : TypeTree if t.original != null =>
        def h(original : Tree, tpe : Type): Unit = try {
          if (original.tpe == null)
            original.tpe = tpe
          (original) match {
          case (AppliedTypeTree(_,trees)) if tpe.isInstanceOf[TypeRef] =>
            val types = tpe.asInstanceOf[TypeRef].args
            trees.zip(types).foreach{
            case (tree,tpe) => assert(tree != null && tpe != null); h(tree, tpe)
            }
          case _ =>
          }
        }
        if (t.original.tpe == null) {
          val dup = t.original.duplicate
          h(dup,t.tpe)
          f(dup)
        } else f(t.original)
        ()
      case _ =>
      }
      (t) match {
      case (t : MemberDef) if t.symbol != null && t.symbol != NoSymbol =>
        val annotated = if (sym.isModule) sym.moduleClass else sym
        val i = t.mods.annotations.iterator
        val j = annotated.annotations.iterator
        while (i.hasNext && j.hasNext) {
          val tree = i.next
          val ainfo = j.next
          val sym = ainfo.atp.typeSymbol
          tree.setType(ainfo.atp)
          tree.setSymbol(sym)
          f(tree)
        }

      case _ =>
      }
      t match {
      case tree: ImplDef =>
        fs(tree.impl.parents); f(tree.impl.self); fs(tree.impl.body)
        tree match {
        case tree : ClassDef => fs(tree.tparams)
        case _ =>
        }
      case tree: PackageDef => fs(tree.stats)
      case tree: ValOrDefDef =>
        f(tree.rhs);
        if (tree.tpt != null) {
          f(tree.tpt)
        }
        tree match {
        case tree : DefDef => fs(tree.tparams); fss(tree.vparamss)
        case _ =>
        }
      case tree: Function => fs(tree.vparams); f(tree.body)
      case tree : Bind => f(tree.body)
      case tree : Select =>
        val qualifier = if (tree.tpe != null && tree.qualifier.tpe == null) {
          val pre = tree.tpe.prefix
          val qualifier = tree.qualifier.duplicate
          qualifier.tpe = pre
          qualifier
        } else tree.qualifier

        f(qualifier)
      case tree : Annotated => f(tree.annot); f(tree.arg)
      case tree : GenericApply => f(tree.fun); fs(tree.args)
      case tree : UnApply => f(tree.fun); fs(tree.args)
      case tree : AppliedTypeTree =>
        if (tree.tpe != null) {
          val i = tree.tpe.typeArgs.iterator
          val j = tree.args.iterator
          while (i.hasNext && j.hasNext) {
            val tpe = i.next
            val arg = j.next
            if (arg.tpe == null) {
              arg.tpe = tpe
            }
          }
          if (tree.tpt.tpe == null) {
            tree.tpt.tpe = tree.tpe
          }

        }
        f(tree.tpt); fs(tree.args)

      case tree : ExistentialTypeTree=>
        if (tree.tpt.tpe == null) {
          tree.tpt.tpe = tree.tpe
        }

        f(tree.tpt)
        fs(tree.whereClauses)
      case tree : SingletonTypeTree =>
        if (tree.ref.tpe == null) {
          val dup = tree.ref.duplicate
          dup.tpe = tree.tpe
          f(dup)
        } else f(tree.ref)
      case tree : CompoundTypeTree =>
        if (tree.tpe != null && tree.tpe.typeSymbol != null && tree.tpe.typeSymbol.isRefinementClass) tree.tpe.typeSymbol.info match {
        case tpe : RefinedType =>
          tpe.parents.zip(tree.templ.parents).foreach{
          case (tpe,tree) =>
            if (tree.hasSymbol && (tree.symbol == NoSymbol || tree.symbol == null)) {
              tree.symbol = tpe.typeSymbol
            }
          }

        case _ =>
        }

        f(tree.templ)
      case tree : Template => fs(tree.parents); f(tree.self); fs(tree.body)
      case tree : SelectFromTypeTree => {
        if (tree.qualifier.tpe == null) tree.tpe match {
        case tpe : TypeRef =>
          // give it a type!
          tree.qualifier.tpe = tpe.prefix
        case _ =>
          // tree.tpe.pre
        }
        f(tree.qualifier)
      }
      case tree : Literal =>
      /*
        if (tree.tpe != null && tree.tpe.typeSymbol == definitions.ClassClass) {
          // nothing we can do without original tree.
        }
      */

      case tree : Typed => f(tree.expr); f(tree.tpt)
      case tree : Block => fs(tree.stats); f(tree.expr)
      case tree: CaseDef => f(tree.pat);f(tree.guard);f(tree.body)
      case tree : Sequence   => fs(tree.trees);
      case tree : Assign     => f(tree.lhs); f(tree.rhs);
      case tree : If         => f(tree.cond); f(tree.thenp); f(tree.elsep);
      case tree : New        => f(tree.tpt);
      case tree : Match      => f(tree.selector); fs(tree.cases);
      case tree : Return     => f(tree.expr);
      case tree : LabelDef   => f(tree.rhs);
      case tree : Throw      => f(tree.expr);
      case tree : Try        => f(tree.block); fs(tree.catches); f(tree.finalizer);
      case tree : Alternative => fs(tree.trees);
      case tree : TypeDef =>
        (tree.tpe,sym) match {
          case (null,sym : TypeSymbol) if (sym.rawInfo.isComplete) =>
            if (tree.tparams.isEmpty) {
              if (tree.rhs.tpe == null) tree.rhs.tpe = sym.info
              f(tree.rhs)
            } else {
              val tree0 = AppliedTypeTree(tree.rhs, tree.tparams)
              tree0.tpe = sym.info
              f(tree0)
            }
          case _ => f(tree.rhs); fs(tree.tparams)
        }
      case tree : DocDef     => f(tree.definition);
      case tree: Import => f(tree.expr)
      case _ =>
      }
    }
    f(tree)
  }

}