forked from scala/scala
-
Notifications
You must be signed in to change notification settings - Fork 1
/
SourceContextUtils.scala
139 lines (120 loc) · 5.32 KB
/
SourceContextUtils.scala
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
/* NSC -- new Scala compiler
* Copyright 2005-2011 LAMP/EPFL
* @author Martin Odersky
*/
package scala.tools.nsc
package typechecker
/* Utilities for generating SourceLocations and SourceContexts.
*
* @author Philipp Haller
*/
trait SourceContextUtils {
self: Analyzer =>
import global._
import definitions._
def contextSourceInfoChain(ctx: Context,
stopAt: Context,
prevValDef: Option[String]): List[(String, Int)] = {
if (ctx == stopAt)
List()
else ctx.tree match {
case vd @ ValDef(_, name, _, _) if prevValDef.isEmpty || (!prevValDef.get.equals(name.toString)) =>
(name.toString, vd.pos.line) :: contextSourceInfoChain(ctx.outer, stopAt, Some(name.toString))
//case app @ Apply(fun, args) if fun.symbol.isMethod =>
// (fun.symbol.nameString, fun.pos.line) :: contextSourceInfoChain(ctx.outer, stopAt)
case _ =>
contextSourceInfoChain(ctx.outer, stopAt, None)
}
}
def contextInfoChain(ctx: Context, tree: Tree) = ctx.tree match {
case vd @ ValDef(_, name, _, _) =>
//println("current context tree is ValDef "+name)
contextSourceInfoChain(ctx, ctx.enclClass, None)
case _ =>
//println("current context tree: "+ctx.tree)
val l = tree.pos match {
case NoPosition => 0
case _ => tree.pos.line
}
(null, l) :: contextSourceInfoChain(ctx.outer, ctx.outer.enclClass, None)
}
def sourceInfoTree(chain: List[(String, Int)]): Tree = chain match {
case (name, line) :: rest =>
val pairTree = gen.mkTuple(List(Literal(Constant(name)), Literal(Constant(line))))
Apply(Select(gen.mkAttributedRef(ListModule), nme.apply), List(pairTree))
case List() =>
gen.mkNil
}
/** Creates a tree that calls the factory method called constructor in object reflect.SourceContext */
def sourceInfoFactoryCall(typer: Typer, infoTree: Tree, constructor: String, args: Tree*): Tree =
if (args contains EmptyTree) EmptyTree
else typer.typedPos(infoTree.pos.focus) {
Apply(
Select(gen.mkAttributedRef(SourceContextModule), constructor),
args.toList
)
}
def methodNameOf(tree: Tree) = {
tree match {
case Apply(TypeApply(s, _), _) => s.symbol.name
case Apply(s@Select(_, _), _) => s.symbol.name
case Apply(s@Ident(_), _) => s.symbol.name
case Apply(Apply(s, _), _) => s.symbol.name
case s@Select(_, _) => s.symbol.name
case other => ""
}
}
def receiverOptOf(tree: Tree) = {
try {
tree match {
case Apply(TypeApply(Select(recv, _), _), _) => Some(recv.symbol.name)
case Apply(Select(recv, _), _) => Some(recv.symbol.name)
case Select(recv, _) => Some(recv.symbol.name)
case _ => None
}
} catch {
case npe: NullPointerException =>
None
}
}
def sourceInfo(typer: Typer, infoContext: Context, infoTree: Tree): SearchResult = {
def srcInfo()(implicit from: List[Symbol] = List(), to: List[Type] = List()): SearchResult = {
implicit def wrapResult(tree: Tree): SearchResult =
if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to))
val methodName = methodNameOf(infoTree)
val receiver = receiverOptOf(infoTree)
//println("context source info chain:")
//println(contextInfoChain)
//println("source info tree:")
//println(sourceInfoTree(contextInfoChain))
val position = infoTree.pos.focus
val fileName = if (position.isDefined) position.source.file.absolute.path
else "<unknown file>"
if (receiver.isEmpty)
sourceInfoFactoryCall(typer, infoTree, "apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), sourceInfoTree(contextInfoChain(infoContext, infoTree)))
else
sourceInfoFactoryCall(typer, infoTree, "apply", Literal(Constant(fileName)), Literal(Constant(methodName.toString)), Literal(Constant(receiver.get.toString)), sourceInfoTree(contextInfoChain(infoContext, infoTree)))
}
srcInfo()
}
def sourceLocation(typer: Typer, infoTree: Tree): SearchResult = {
/** Creates a tree that calls the factory method called constructor in object reflect.SourceLocation */
def sourceLocationFactoryCall(constructor: String, args: Tree*): Tree =
if (args contains EmptyTree) EmptyTree
else typer.typedPos(infoTree.pos.focus) {
Apply(
Select(gen.mkAttributedRef(SourceLocationModule), constructor),
args.toList
)
}
def srcLocation()(implicit from: List[Symbol] = List(), to: List[Type] = List()): SearchResult = {
implicit def wrapResult(tree: Tree): SearchResult =
if (tree == EmptyTree) SearchFailure else new SearchResult(tree, new TreeTypeSubstituter(from, to))
val position = infoTree.pos.focus
val fileName = if (position.isDefined) position.source.file.absolute.path
else "<unknown file>"
sourceLocationFactoryCall("apply", Literal(Constant(position.line)), Literal(Constant(position.point)), Literal(Constant(fileName)))
}
srcLocation()
}
}