Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
None
-
None
Description
Appears to affect all versions such the introduction of inner classes in 1.7.
I have a unit test and bugfix and a pull request will be forthcoming.
Consider the following:
class BaseFieldBearer { String baseField = 'baseValue' } class BaseFieldBearerSub extends BaseFieldBearer { String getBaseFieldViaInner() { // An easy way to create an inner class and have it resolve something new java.util.concurrent.Callable<String>() { String call() { baseField } }.call(); } } BaseFieldBearerSub s = new BaseFieldBearerSub() assert s.baseFieldViaInner == s.baseField
BaseFieldBearerSub.baseFieldViaInner will fail with the following:
Exception in thread "main" groovy.lang.MissingFieldException: No such field: baseField for class: BaseFieldBearerSub at groovy.lang.MetaClassImpl.getAttribute(MetaClassImpl.java:2628) at groovy.lang.MetaClassImpl.getAttribute(MetaClassImpl.java:3466) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getGroovyObjectField(ScriptBytecodeAdapter.java:352) at BaseFieldBearerSub.this$dist$get$2(GroovyXXXBug.groovy) at BaseFieldBearerSub$1.propertyMissing(GroovyXXXBug.groovy) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90) at groovy.lang.MetaClassImpl.invokeMissingProperty(MetaClassImpl.java:778) at groovy.lang.MetaClassImpl$12.getProperty(MetaClassImpl.java:1896) at org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.getProperty(GetEffectivePogoPropertySite.java:84) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231) at BaseFieldBearerSub$1.call(GroovyXXXBug.groovy:32) at BaseFieldBearerSub$1.call(GroovyXXXBug.groovy) at java_util_concurrent_Callable$call.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112) at BaseFieldBearerSub.getBaseFieldViaInner(GroovyXXXBug.groovy:30) at BaseFieldBearerSub$getBaseFieldViaInner.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112) at GroovyXXXBug.testInnerClassAccessingBaseFieldProperty(GroovyXXXBug.groovy:11) at GroovyXXXBug$testInnerClassAccessingBaseFieldProperty.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112) at GroovyXXXBug.main(GroovyXXXBug.groovy:17)
BaseFieldBearerSub.this$dist$get$2 is a dispatcher method that's meant to resolve a named property in the outer class, but instead of using ScriptBytecodeAdapter.getGroovyObjectProperty it calls ScriptBytecodeAdapter.getGroovyObjectField. If baseField were a property in the subclass then this would normally go unnoticed, as the attribute would be found (though any property getter method would be ignored). I expect that's why I couldn't find other references to this bug.
The code at fault appears to be in InnerClassVisitorHelper as the dispatcher method uses an AttributeExpression instead of a PropertyExpression. I can't imagine there's any reason for the dispatcher to only consider attributes rather than properties, but I'm open to being corrected!