Skip to content

Commit 5fda6cb

Browse files
puredangerstuarthalloway
authored andcommitted
CLJ-1363 - reflect .- should return field if both field and method exist
1 parent 3b1a1dd commit 5fda6cb

File tree

3 files changed

+39
-10
lines changed

3 files changed

+39
-10
lines changed

src/jvm/clojure/lang/Compiler.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,7 @@ else if(instance != null && instance.hasJavaClass() && instance.getJavaClass() !
943943
if(c != null) {
944944
return new StaticFieldExpr(line, column, c, munge(sym.name), tag);
945945
} else
946-
return new InstanceFieldExpr(line, column, instance, munge(sym.name), tag);
946+
return new InstanceFieldExpr(line, column, instance, munge(sym.name), tag, (((Symbol)RT.third(form)).name.charAt(0) == '-'));
947947
}
948948
else
949949
{
@@ -1081,18 +1081,20 @@ static class InstanceFieldExpr extends FieldExpr implements AssignableExpr{
10811081
public final int line;
10821082
public final int column;
10831083
public final Symbol tag;
1084-
final static Method invokeNoArgInstanceMember = Method.getMethod("Object invokeNoArgInstanceMember(Object,String)");
1084+
public final boolean requireField;
1085+
final static Method invokeNoArgInstanceMember = Method.getMethod("Object invokeNoArgInstanceMember(Object,String,boolean)");
10851086
final static Method setInstanceFieldMethod = Method.getMethod("Object setInstanceField(Object,String,Object)");
10861087

10871088

1088-
public InstanceFieldExpr(int line, int column, Expr target, String fieldName, Symbol tag) {
1089+
public InstanceFieldExpr(int line, int column, Expr target, String fieldName, Symbol tag, boolean requireField) {
10891090
this.target = target;
10901091
this.targetClass = target.hasJavaClass() ? target.getJavaClass() : null;
10911092
this.field = targetClass != null ? Reflector.getField(targetClass, fieldName, false) : null;
10921093
this.fieldName = fieldName;
10931094
this.line = line;
10941095
this.column = column;
10951096
this.tag = tag;
1097+
this.requireField = requireField;
10961098
if(field == null && RT.booleanCast(RT.WARN_ON_REFLECTION.deref()))
10971099
{
10981100
if(targetClass == null)
@@ -1111,7 +1113,7 @@ public InstanceFieldExpr(int line, int column, Expr target, String fieldName, Sy
11111113
}
11121114

11131115
public Object eval() {
1114-
return Reflector.invokeNoArgInstanceMember(target.eval(), fieldName);
1116+
return Reflector.invokeNoArgInstanceMember(target.eval(), fieldName, requireField);
11151117
}
11161118

11171119
public boolean canEmitPrimitive(){
@@ -1149,6 +1151,7 @@ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
11491151
{
11501152
target.emit(C.EXPRESSION, objx, gen);
11511153
gen.push(fieldName);
1154+
gen.push(requireField);
11521155
gen.invokeStatic(REFLECTOR_TYPE, invokeNoArgInstanceMember);
11531156
if(context == C.STATEMENT)
11541157
gen.pop();

src/jvm/clojure/lang/Reflector.java

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -291,13 +291,29 @@ public static Object setInstanceField(Object target, String fieldName, Object va
291291
+ " for " + target.getClass());
292292
}
293293

294+
// not used as of Clojure 1.6, but left for runtime compatibility with
295+
// compiled bytecode from older versions
294296
public static Object invokeNoArgInstanceMember(Object target, String name) {
295-
//favor method over field
296-
List meths = getMethods(target.getClass(), 0, name, false);
297-
if(meths.size() > 0)
298-
return invokeMatchingMethod(name, meths, target, RT.EMPTY_ARRAY);
299-
else
300-
return getInstanceField(target, name);
297+
return invokeNoArgInstanceMember(target, name, false);
298+
}
299+
300+
public static Object invokeNoArgInstanceMember(Object target, String name, boolean requireField) {
301+
Class c = target.getClass();
302+
303+
if(requireField) {
304+
Field f = getField(c, name, false);
305+
if(f != null)
306+
return getInstanceField(target, name);
307+
else
308+
throw new IllegalArgumentException("No matching field found: " + name
309+
+ " for " + target.getClass());
310+
} else {
311+
List meths = getMethods(c, 0, name, false);
312+
if(meths.size() > 0)
313+
return invokeMatchingMethod(name, meths, target, RT.EMPTY_ARRAY);
314+
else
315+
return getInstanceField(target, name);
316+
}
301317
}
302318

303319
public static Object invokeInstanceMember(Object target, String name) {

test/clojure/test_clojure/java_interop.clj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@
5555
Integer/MAX_VALUE
5656
(. Integer MAX_VALUE) ))
5757

58+
(definterface I (a []))
59+
(deftype T [a] I (a [_] "method"))
60+
61+
(deftest test-reflective-field-name-ambiguous
62+
(let [t (->T "field")]
63+
(is (= "method" (. ^T t a)))
64+
(is (= "field" (. ^T t -a)))
65+
(is (= "method" (. t a)))
66+
(is (= "field" (. t -a)))
67+
(is (thrown? IllegalArgumentException (. t -BOGUS)))))
5868

5969
(deftest test-double-dot
6070
(is (= (.. System (getProperties) (get "os.name"))

0 commit comments

Comments
 (0)