@@ -8,14 +8,50 @@ import core.Flags._
88import core .Decorators ._
99import MegaPhase .MiniPhase
1010import ast .Trees ._
11+ import util .Property
1112
1213/** Add accessors for all protected accesses. An accessor is needed if
1314 * according to the rules of the JVM a protected class member is not accesissible
1415 * from the point of access, but is accessible if the access is from an enclosing
1516 * class. In this point a public access method is placed in that enclosing class.
1617 */
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+
1752class ProtectedAccessors extends MiniPhase {
1853 import ast .tpd ._
54+ import ProtectedAccessors ._
1955
2056 override def phaseName = ProtectedAccessors .name
2157
@@ -24,39 +60,19 @@ class ProtectedAccessors extends MiniPhase {
2460 def setterName = ProtectedSetterName
2561
2662 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)
4664 }
4765 }
4866
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
5473 }
5574
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
6076
6177 override def transformIdent (tree : Ident )(implicit ctx : Context ): Tree =
6278 if (isLHS(tree)) tree else Accessors .insert.accessorIfNeeded(tree)
@@ -70,5 +86,3 @@ class ProtectedAccessors extends MiniPhase {
7086 override def transformTemplate (tree : Template )(implicit ctx : Context ): Tree =
7187 cpy.Template (tree)(body = Accessors .addAccessorDefs(tree.symbol.owner, tree.body))
7288}
73- object ProtectedAccessors { val name = " protectedAccessors" }
74-
0 commit comments