summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-08-06 19:37:07 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-08-06 23:09:33 +0200
commit7bcb9da47362ba862a695f7c82c0095a8205e3e2 (patch)
treef3434a982cb3104a1abc7f1fd3f4751f5e896da7 /src
parent3cbe07f3e3ddb7201d1d174399d14d4a69df52fd (diff)
downloadscala-7bcb9da47362ba862a695f7c82c0095a8205e3e2.tar.gz
scala-7bcb9da47362ba862a695f7c82c0095a8205e3e2.tar.bz2
scala-7bcb9da47362ba862a695f7c82c0095a8205e3e2.zip
mirrors now support overriden fields and methods
Previously `checkMemberOf` was blocking base fields and methods that are overriden in receiver.getClass. Now this is fixed. The fix also uncovered an issue with field mirrors. Currently their `get` and `set` methods don't respect overriding and always return field values from a base class. After discussing this on a reflection meeting, we decided that this behavior is desirable and that for overriding people should use reflectMethod and then apply on getters/setters. See the discussion at: https://github.com/scala/scala/pull/1054.
Diffstat (limited to 'src')
-rw-r--r--src/reflect/scala/reflect/api/Mirrors.scala16
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala6
2 files changed, 21 insertions, 1 deletions
diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala
index 41acd73492..8f69ab526b 100644
--- a/src/reflect/scala/reflect/api/Mirrors.scala
+++ b/src/reflect/scala/reflect/api/Mirrors.scala
@@ -33,6 +33,14 @@ trait Mirrors { self: Universe =>
/** Reflects against a field symbol and returns a mirror
* that can be used to get and, if appropriate, set the value of the field.
*
+ * FieldMirrors are the only way to get at private[this] vals and vars and
+ * might be useful to inspect the data of underlying Java fields.
+ * For all other uses, it's better to go through the fields accessor.
+ *
+ * In particular, there should be no need to ever access a field mirror
+ * when reflecting on just the public members of a class or trait.
+ * Note also that only accessor MethodMirrors, but not FieldMirrors will accurately reflect overriding behavior.
+ *
* To get a field symbol by the name of the field you would like to reflect,
* use `<this mirror>.symbol.typeSignature.member(newTermName(<name of the field>)).asTerm.accessed`.
* For further information about member lookup refer to `Symbol.typeSignature`.
@@ -107,6 +115,10 @@ trait Mirrors { self: Universe =>
* Scala reflection uses reflection capabilities of the underlying platform,
* so `FieldMirror.get` might throw platform-specific exceptions associated
* with getting a field or invoking a getter method of the field.
+ *
+ * If `symbol` represents a field of a base class with respect to the class of the receiver,
+ * and this base field is overriden in the class of the receiver, then this method will retrieve
+ * the value of the base field. To achieve overriding behavior, use reflectMethod on an accessor.
*/
def get: Any
@@ -117,6 +129,10 @@ trait Mirrors { self: Universe =>
* Scala reflection uses reflection capabilities of the underlying platform,
* so `FieldMirror.get` might throw platform-specific exceptions associated
* with setting a field or invoking a setter method of the field.
+ *
+ * If `symbol` represents a field of a base class with respect to the class of the receiver,
+ * and this base field is overriden in the class of the receiver, then this method will set
+ * the value of the base field. To achieve overriding behavior, use reflectMethod on an accessor.
*/
def set(value: Any): Unit
}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index f9407d5b1b..d671225c37 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -161,7 +161,11 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
} else if (wannabe.owner == AnyValClass) {
if (!owner.isPrimitiveValueClass && !owner.isDerivedValueClass) ErrorNotMember(wannabe, owner)
} else {
- if (!owner.info.member(wannabe.name).alternatives.contains(wannabe)) ErrorNotMember(wannabe, owner)
+ def isMemberOf(wannabe: Symbol, owner: ClassSymbol): Boolean = {
+ val isNonShadowedMember = owner.info.member(wannabe.name).alternatives.contains(wannabe)
+ isNonShadowedMember || owner.info.baseClasses.tail.exists(base => isMemberOf(wannabe, base.asClass))
+ }
+ if (!isMemberOf(wannabe, owner)) ErrorNotMember(wannabe, owner)
}
}