Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-6508

Outer class property dispatcher called by an inner class's propertyMissing looks for attributes/fields rather than properties on the outer class

    XMLWordPrintableJSON

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 2.2.2
    • Component/s: ast builder
    • Labels:
      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!

        Attachments

          Activity

            People

            • Assignee:
              blackdrag Jochen Theodorou
              Reporter:
              lujke Luke Kirby
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: