groovy-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Eric Milles (JIRA)" <j...@apache.org>
Subject [jira] [Updated] (GROOVY-8208) VariableExpressionTransformer does not set source position on property expressions
Date Fri, 26 May 2017 15:11:04 GMT

     [ https://issues.apache.org/jira/browse/GROOVY-8208?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Eric Milles updated GROOVY-8208:
--------------------------------
    Description: 
Two paths in VariableExpressionTransformer create PropertyExpression nodes to stand in for
unresolved variable references. Neither case sets the exp source position onto the new node.
Other paths through this method transfer position info.
The fix is simple:
{code}
private static Expression tryTransformDelegateToProperty(VariableExpression expr) {
        // we need to transform variable expressions that go to a delegate
        // to a property expression, as ACG would loose the information
        // in processClassVariable before it reaches any makeCall, that could
        // handle it
        Object val = expr.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
        if (val == null) return null;
        VariableExpression implicitThis = new VariableExpression("this");
        PropertyExpression pexp = new PropertyExpression(implicitThis, expr.getName());
        pexp.copyNodeMetaData(expr);
        pexp.setImplicitThis(true);
        // GRECLIPSE add
        pexp.getProperty().setSourcePosition(expr);
        // GRECLIPSE end
        ClassNode owner = expr.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
        if (owner != null) {
            implicitThis.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, owner);
            implicitThis.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, val);
        }
        return pexp;
    }

    private static Expression tryTransformPrivateFieldAccess(VariableExpression expr) {
        FieldNode field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
        if (field == null) {
            field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION);
        }
        if (field != null) {
            // access to a private field from a section of code that normally doesn't have
access to it, like a
            // closure or an inner class
            VariableExpression receiver = new VariableExpression("this");
            PropertyExpression pexp = new PropertyExpression(
                    receiver,
                    expr.getName()
            );
            pexp.setImplicitThis(true);
            // GRECLIPSE add
            pexp.getProperty().setSourcePosition(expr);
            // GRECLIPSE end
            // put the receiver inferred type so that the class writer knows that it will
have to call a bridge method
            receiver.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getDeclaringClass());
            // add inferred type information
            pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getOriginType());
            return pexp;
        }
        return null;
    }
{code}

The first method affects code like
{code}
@groovy.transform.CompileStatic
class E {
    D d = new D()
    void doSomething() {
        d.with { // 'foo' and 'bar' VariableExpressions are xformed to PropertyExpressions
            foo = 'foo'
            bar = new D()
            bar.foo = 'bar'
        }
    }
}
{code}

The second method affects code like
{code}
@groovy.transform.CompileStatic
class X {
  String id
  @Lazy Object thing = { ->
    Directory.lookup(id) // 'id' is transformed from a VariableExpression to a PropertyExpression
  }()
}
{code}

  was:
Two paths in VariableExpressionTransformer create PropertyExpression nodes to stand in for
unresolved variable references. Neither case sets the exp source position onto the new node.
Other paths through this method transfer position info.
The fix is simple:
{code}
private static Expression tryTransformDelegateToProperty(VariableExpression expr) {
        // we need to transform variable expressions that go to a delegate
        // to a property expression, as ACG would loose the information
        // in processClassVariable before it reaches any makeCall, that could
        // handle it
        Object val = expr.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
        if (val == null) return null;
        VariableExpression implicitThis = new VariableExpression("this");
        PropertyExpression pexp = new PropertyExpression(implicitThis, expr.getName());
        pexp.copyNodeMetaData(expr);
        pexp.setImplicitThis(true);
        // GRECLIPSE add
        pexp.getProperty().setSourcePosition(expr);
        // GRECLIPSE end
        ClassNode owner = expr.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
        if (owner != null) {
            implicitThis.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, owner);
            implicitThis.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, val);
        }
        return pexp;
    }

    private static Expression tryTransformPrivateFieldAccess(VariableExpression expr) {
        FieldNode field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
        if (field == null) {
            field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION);
        }
        if (field != null) {
            // access to a private field from a section of code that normally doesn't have
access to it, like a
            // closure or an inner class
            VariableExpression receiver = new VariableExpression("this");
            PropertyExpression pexp = new PropertyExpression(
                    receiver,
                    expr.getName()
            );
            pexp.setImplicitThis(true);
            // GRECLIPSE add
            pexp.getProperty().setSourcePosition(expr);
            // GRECLIPSE end
            // put the receiver inferred type so that the class writer knows that it will
have to call a bridge method
            receiver.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getDeclaringClass());
            // add inferred type information
            pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getOriginType());
            return pexp;
        }
        return null;
    }
{code}

The first method affects code like
{code}
@groovy.transform.CompileStatic
class E {
    D d = new D()
    void doSomething() {
        d.with { // 'foo' and 'bar' VariableExpressions are xformed to PropertyExpressions
            foo = 'foo'
            bar = new D()
            bar.foo = 'bar'
        }
    }
}
{code}

The second method affects code like
{code}
            @groovy.transform.CompileStatic
            class X {
              String id
              @Lazy Object thing = { ->
                Directory.lookup(id) // 'id' is transformed from a VariableExpression to a
PropertyExpression
              }()
            }
{code}


> VariableExpressionTransformer does not set source position on property expressions
> ----------------------------------------------------------------------------------
>
>                 Key: GROOVY-8208
>                 URL: https://issues.apache.org/jira/browse/GROOVY-8208
>             Project: Groovy
>          Issue Type: Bug
>          Components: xforms
>            Reporter: Eric Milles
>            Priority: Minor
>
> Two paths in VariableExpressionTransformer create PropertyExpression nodes to stand in
for unresolved variable references. Neither case sets the exp source position onto the new
node. Other paths through this method transfer position info.
> The fix is simple:
> {code}
> private static Expression tryTransformDelegateToProperty(VariableExpression expr) {
>         // we need to transform variable expressions that go to a delegate
>         // to a property expression, as ACG would loose the information
>         // in processClassVariable before it reaches any makeCall, that could
>         // handle it
>         Object val = expr.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
>         if (val == null) return null;
>         VariableExpression implicitThis = new VariableExpression("this");
>         PropertyExpression pexp = new PropertyExpression(implicitThis, expr.getName());
>         pexp.copyNodeMetaData(expr);
>         pexp.setImplicitThis(true);
>         // GRECLIPSE add
>         pexp.getProperty().setSourcePosition(expr);
>         // GRECLIPSE end
>         ClassNode owner = expr.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
>         if (owner != null) {
>             implicitThis.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, owner);
>             implicitThis.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, val);
>         }
>         return pexp;
>     }
>     private static Expression tryTransformPrivateFieldAccess(VariableExpression expr)
{
>         FieldNode field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
>         if (field == null) {
>             field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION);
>         }
>         if (field != null) {
>             // access to a private field from a section of code that normally doesn't
have access to it, like a
>             // closure or an inner class
>             VariableExpression receiver = new VariableExpression("this");
>             PropertyExpression pexp = new PropertyExpression(
>                     receiver,
>                     expr.getName()
>             );
>             pexp.setImplicitThis(true);
>             // GRECLIPSE add
>             pexp.getProperty().setSourcePosition(expr);
>             // GRECLIPSE end
>             // put the receiver inferred type so that the class writer knows that it
will have to call a bridge method
>             receiver.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getDeclaringClass());
>             // add inferred type information
>             pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getOriginType());
>             return pexp;
>         }
>         return null;
>     }
> {code}
> The first method affects code like
> {code}
> @groovy.transform.CompileStatic
> class E {
>     D d = new D()
>     void doSomething() {
>         d.with { // 'foo' and 'bar' VariableExpressions are xformed to PropertyExpressions
>             foo = 'foo'
>             bar = new D()
>             bar.foo = 'bar'
>         }
>     }
> }
> {code}
> The second method affects code like
> {code}
> @groovy.transform.CompileStatic
> class X {
>   String id
>   @Lazy Object thing = { ->
>     Directory.lookup(id) // 'id' is transformed from a VariableExpression to a PropertyExpression
>   }()
> }
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

Mime
View raw message