@@ -8,14 +8,50 @@ import core.Flags._
8
8
import core .Decorators ._
9
9
import MegaPhase .MiniPhase
10
10
import ast .Trees ._
11
+ import util .Property
11
12
12
13
/** Add accessors for all protected accesses. An accessor is needed if
13
14
* according to the rules of the JVM a protected class member is not accesissible
14
15
* from the point of access, but is accessible if the access is from an enclosing
15
16
* class. In this point a public access method is placed in that enclosing class.
16
17
*/
18
+ object ProtectedAccessors {
19
+ val name = " protectedAccessors"
20
+
21
+ private val LHS = new Property .StickyKey [Unit ]
22
+
23
+ /** Is the current context's owner inside the access boundary established by `sym`? */
24
+ def insideBoundaryOf (sym : Symbol )(implicit ctx : Context ): Boolean = {
25
+ if (sym.is(JavaDefined )) {
26
+ sym.is(JavaStatic ) || // Java's static protected definitions are treated as public
27
+ ctx.owner.enclosingPackageClass == sym.enclosingPackageClass
28
+ }
29
+ else {
30
+ // For Scala-defined symbols we currently allow private and protected accesses
31
+ // from inner packages, and compensate by widening accessibility of such symbols to public.
32
+ // It would be good if we could revisit this at some point.
33
+ val boundary = sym.accessBoundary(sym.enclosingPackageClass)
34
+ ctx.owner.isContainedIn(boundary) || ctx.owner.isContainedIn(boundary.linkedClass)
35
+ }
36
+ }
37
+
38
+ /** Do we need a protected accessor if the current context's owner
39
+ * is not in a subclass or subtrait of `sym`?
40
+ */
41
+ def needsAccessorIfNotInSubclass (sym : Symbol )(implicit ctx : Context ): Boolean =
42
+ sym.isTerm && sym.is(Protected ) &&
43
+ ! sym.owner.is(Trait ) && // trait methods need to be handled specially, are currently always public
44
+ ! insideBoundaryOf(sym)
45
+
46
+ /** Do we need a protected accessor for accessing sym from the current context's owner? */
47
+ def needsAccessor (sym : Symbol )(implicit ctx : Context ): Boolean =
48
+ needsAccessorIfNotInSubclass(sym) &&
49
+ ! ctx.owner.enclosingClass.derivesFrom(sym.owner)
50
+ }
51
+
17
52
class ProtectedAccessors extends MiniPhase {
18
53
import ast .tpd ._
54
+ import ProtectedAccessors ._
19
55
20
56
override def phaseName = ProtectedAccessors .name
21
57
@@ -24,39 +60,19 @@ class ProtectedAccessors extends MiniPhase {
24
60
def setterName = ProtectedSetterName
25
61
26
62
val insert = new Insert {
27
- def needsAccessor (sym : Symbol )(implicit ctx : Context ): Boolean = {
28
- def insideBoundary = {
29
- if (sym.is(JavaDefined )) {
30
- sym.is(JavaStatic ) || // Java's static protected definitions are treated as public
31
- ctx.owner.enclosingPackageClass == sym.enclosingPackageClass
32
- }
33
- else {
34
- // For Scala-defined symbols we currently allow private and protected accesses
35
- // from inner packages, and compensate by widening accessibility of such symbols to public.
36
- // It would be good if we could revisit this at some point.
37
- val boundary = sym.accessBoundary(sym.enclosingPackageClass)
38
- ctx.owner.isContainedIn(boundary) || ctx.owner.isContainedIn(boundary.linkedClass)
39
- }
40
- }
41
- sym.isTerm && sym.is(Protected ) &&
42
- ! sym.owner.is(Trait ) && // trait methods need to be handled specially, are currently always public
43
- ! insideBoundary &&
44
- ! ctx.owner.enclosingClass.derivesFrom(sym.owner)
45
- }
63
+ def needsAccessor (sym : Symbol )(implicit ctx : Context ) = ProtectedAccessors .needsAccessor(sym)
46
64
}
47
65
}
48
66
49
- override def prepareForAssign (tree : Assign )(implicit ctx : Context ) = tree.lhs match {
50
- case tree : RefTree if Accessors .insert.needsAccessor(tree.symbol) =>
51
- ctx.fresh.setTree(tree)
52
- case _ =>
53
- ctx
67
+ override def prepareForAssign (tree : Assign )(implicit ctx : Context ) = {
68
+ tree.lhs match {
69
+ case lhs : RefTree if needsAccessor(lhs.symbol) => lhs.putAttachment(LHS , ())
70
+ case _ =>
71
+ }
72
+ ctx
54
73
}
55
74
56
- def isLHS (tree : RefTree )(implicit ctx : Context ) = ctx.tree match {
57
- case Assign (lhs, _) => tree.symbol == lhs.symbol
58
- case _ => false
59
- }
75
+ private def isLHS (tree : RefTree ) = tree.removeAttachment(LHS ).isDefined
60
76
61
77
override def transformIdent (tree : Ident )(implicit ctx : Context ): Tree =
62
78
if (isLHS(tree)) tree else Accessors .insert.accessorIfNeeded(tree)
@@ -70,5 +86,3 @@ class ProtectedAccessors extends MiniPhase {
70
86
override def transformTemplate (tree : Template )(implicit ctx : Context ): Tree =
71
87
cpy.Template (tree)(body = Accessors .addAccessorDefs(tree.symbol.owner, tree.body))
72
88
}
73
- object ProtectedAccessors { val name = " protectedAccessors" }
74
-
0 commit comments