1
- package dotty .tools .dotc
1
+ package dotty .tools
2
+ package dotc
2
3
package ast
3
4
4
5
import util .Positions ._
5
- import util .SourcePosition
6
+ import util .{ SourceFile , SourcePosition }
6
7
import core .Contexts .{Context , SourceInfo }
7
8
import core .Decorators ._
8
9
import core .Flags .{JavaDefined , Extension }
9
10
import core .StdNames .nme
11
+ import io .AbstractFile
12
+ import annotation .transientParam
13
+ import annotation .internal .sharable
10
14
11
15
/** A base class for things that have positions (currently: modifiers and trees)
12
16
*/
13
- abstract class Positioned extends Product {
17
+ abstract class Positioned ( implicit @ transientParam src : SourceInfo ) extends Product with Cloneable {
14
18
19
+ /** A unique identifier. Among other things, used for determining the source file
20
+ * component of the position.
21
+ */
22
+ private var myUniqueId : Int = _
15
23
private [this ] var curPos : Position = _
16
24
17
- setPos(initialPos)
18
-
19
- /** The item's position.
20
- */
25
+ /** The item's position */
21
26
def pos : Position = curPos
22
27
23
- /** Destructively update `curPos` to given position. Also, set any missing
28
+ /** item's id */
29
+ def uniqueId : Int = myUniqueId
30
+
31
+ protected def srcfile : AbstractFile = TreeIds .fileOfId(uniqueId)
32
+ def source (implicit ctx : Context ): SourceFile = ctx.getSource(srcfile)
33
+ def sourcePos (implicit ctx : Context ): SourcePosition = source.atPos(pos)
34
+
35
+ setId(TreeIds .nextIdFor(initialFile(src)))
36
+ setPos(initialPos, srcfile)
37
+
38
+ protected def setId (id : Int ): Unit = myUniqueId = id
39
+
40
+ /** Destructively update `curPos` to given position. Also, set any missing
24
41
* positions in children.
25
42
*/
26
- protected def setPos (pos : Position ): Unit = {
27
- setPosUnchecked(pos)
28
- if (pos.exists) setChildPositions(pos.toSynthetic)
43
+ protected def setPos (pos : Position , file : AbstractFile ): Unit = {
44
+ setPosUnchecked(pos, file )
45
+ if (pos.exists) setChildPositions(pos.toSynthetic, file )
29
46
}
30
47
31
- def cloned (implicit src : SourceInfo ): Positioned
32
-
33
48
/** A positioned item like this one with the position set to `pos`.
34
49
* if the positioned item is source-derived, a clone is returned.
35
50
* If the positioned item is synthetic, the position is updated
36
51
* destructively and the item itself is returned.
37
52
*/
38
53
def withPos (pos : Position )(implicit src : SourceInfo ): this .type = {
39
- val newpd = if (pos == curPos || curPos.isSynthetic) this else cloned
40
- newpd.setPos(pos)
41
- newpd.asInstanceOf [this .type ]
54
+ val ownPos = this .pos
55
+ val newpd : this .type = if (pos == ownPos || ownPos.isSynthetic) this else cloneIn(srcfile)
56
+ newpd.setPos(pos, srcfile)
57
+ newpd
58
+ }
59
+
60
+ def withPos (posd : Positioned )(implicit ctx : Context ): this .type = {
61
+ val ownPos = this .pos
62
+ val newpd : this .type =
63
+ if (posd.source == source && posd.pos == ownPos || ownPos.isSynthetic) this
64
+ else cloneIn(posd.srcfile)
65
+ newpd.setPos(posd.pos, posd.srcfile)
66
+ newpd
67
+ }
68
+
69
+ def withSourcePos (sourcePos : SourcePosition )(implicit ctx : Context ): this .type = {
70
+ val ownPos = this .pos
71
+ val newpd : this .type =
72
+ if (sourcePos.source == source && sourcePos.pos == ownPos || ownPos.isSynthetic) this
73
+ else cloneIn(sourcePos.source.file)
74
+ newpd.setPos(sourcePos.pos, sourcePos.source.file)
75
+ newpd
42
76
}
43
77
44
78
/** This item with a position that's the union of the given `pos` and the
@@ -50,7 +84,10 @@ abstract class Positioned extends Product {
50
84
* any checks of consistency with - or updates of - other positions.
51
85
* Called from Unpickler when entering positions.
52
86
*/
53
- private [dotc] def setPosUnchecked (pos : Position ): Unit = curPos = pos
87
+ private [dotc] def setPosUnchecked (pos : Position , file : AbstractFile = this .srcfile): Unit = {
88
+ if (file != this .srcfile) setId(TreeIds .nextIdFor(file))
89
+ curPos = pos
90
+ }
54
91
55
92
/** If any children of this node do not have positions,
56
93
* fit their positions between the positions of the known subtrees
@@ -63,7 +100,7 @@ abstract class Positioned extends Product {
63
100
* But since mutual tail recursion is not supported in Scala, we express it instead
64
101
* as a while loop with a termination by return in the middle.
65
102
*/
66
- private def setChildPositions (pos : Position ): Unit = {
103
+ private def setChildPositions (pos : Position , file : AbstractFile ): Unit = {
67
104
var n = productArity // subnodes are analyzed right to left
68
105
var elems : List [Any ] = Nil // children in lists still to be considered, from right to left
69
106
var end = pos.end // the last defined offset, fill in positions up to this offset
@@ -75,10 +112,10 @@ abstract class Positioned extends Product {
75
112
// synthetic. We can preserve this invariant by always setting a
76
113
// zero-extent position for these trees here.
77
114
if (! p.pos.exists || p.pos.isZeroExtent) {
78
- p.setPos(Position (start, start))
115
+ p.setPos(Position (start, start), file )
79
116
fillIn(ps1, start, end)
80
117
} else {
81
- p.setPos(Position (start, end))
118
+ p.setPos(Position (start, end), file )
82
119
fillIn(ps1, end, end)
83
120
}
84
121
case nil =>
@@ -114,6 +151,31 @@ abstract class Positioned extends Product {
114
151
}
115
152
}
116
153
154
+ protected def cloneIn (file : AbstractFile ): this .type = {
155
+ val newpd : this .type = clone.asInstanceOf [this .type ]
156
+ newpd.setId(TreeIds .nextIdFor(file))
157
+ newpd
158
+ }
159
+
160
+ def initialFile (src : SourceInfo ): AbstractFile = {
161
+ def firstFile (x : Any ): AbstractFile = x match {
162
+ case x : Positioned if x.pos.exists =>
163
+ x.srcfile
164
+ case x1 :: xs1 =>
165
+ val f = firstFile(x1)
166
+ if (f != null ) f else firstFile(xs1)
167
+ case _ =>
168
+ null
169
+ }
170
+ def firstElemFile (n : Int ): AbstractFile =
171
+ if (n == productArity) src.source.file
172
+ else {
173
+ val f = firstFile(productElement(n))
174
+ if (f != null ) f else firstElemFile(n + 1 )
175
+ }
176
+ firstElemFile(0 )
177
+ }
178
+
117
179
/** The initial, synthetic position. This is usually the union of all positioned children's positions.
118
180
*/
119
181
def initialPos : Position = {
@@ -122,7 +184,7 @@ abstract class Positioned extends Product {
122
184
while (n > 0 ) {
123
185
n -= 1
124
186
productElement(n) match {
125
- case p : Positioned => pos = pos union p.pos
187
+ case p : Positioned if sameSource(p) => pos = pos union p.pos
126
188
case m : untpd.Modifiers => pos = unionPos(unionPos(pos, m.mods), m.annotations)
127
189
case xs : List [_] => pos = unionPos(pos, xs)
128
190
case _ =>
@@ -132,12 +194,14 @@ abstract class Positioned extends Product {
132
194
}
133
195
134
196
private def unionPos (pos : Position , xs : List [_]): Position = xs match {
135
- case (p : Positioned ) :: xs1 => unionPos(pos union p.pos, xs1)
197
+ case (p : Positioned ) :: xs1 if sameSource(p) => unionPos(pos union p.pos, xs1)
136
198
case (xs0 : List [_]) :: xs1 => unionPos(unionPos(pos, xs0), xs1)
137
199
case _ :: xs1 => unionPos(pos, xs1)
138
200
case _ => pos
139
201
}
140
202
203
+ private def sameSource (that : Positioned ) = srcfile == that.srcfile
204
+
141
205
def contains (that : Positioned ): Boolean = {
142
206
def isParent (x : Any ): Boolean = x match {
143
207
case x : Positioned =>
0 commit comments