You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2019/11/18 16:17:31 UTC

[groovy] branch GROOVY-7304 created (now a5cefa6)

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a change to branch GROOVY-7304
in repository https://gitbox.apache.org/repos/asf/groovy.git.


      at a5cefa6  STC: isLHSOfEnclosingAssignment returns true for ++/-- on variable expr

This branch includes the following new commits:

     new a5cefa6  STC: isLHSOfEnclosingAssignment returns true for ++/-- on variable expr

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[groovy] 01/01: STC: isLHSOfEnclosingAssignment returns true for ++/-- on variable expr

Posted by em...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY-7304
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit a5cefa69b7257fb16593fe23c24123e07c1d1bbb
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Nov 18 10:17:13 2019 -0600

    STC: isLHSOfEnclosingAssignment returns true for ++/-- on variable expr
    
    PV_FIELDS_MUTATION is recorded instead of PV_FIELDS_ACCESS
    
    
    This is a first step towards fixing:
    
        @NotYetImplemented // GROOVY-7304
        void testShouldGoThroughPrivateBridgeAccessorWithWriteAccess() {
            ['++i', 'i++', 'i+=1', 'i=i+1'].each {
                assertScript """
                    class Foo {
                        private int i = 1
                        def m() { new String().with { $it } }
                    }
                    assert new Foo().m() == 2
                    class Bar extends Foo {}
                    assert new Bar().m() == 2
                """
            }
        }
---
 .../java/org/codehaus/groovy/syntax/TokenUtil.java | 77 +++++++++-------------
 .../transform/stc/StaticTypeCheckingVisitor.java   | 63 ++++++++++--------
 2 files changed, 67 insertions(+), 73 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/syntax/TokenUtil.java b/src/main/java/org/codehaus/groovy/syntax/TokenUtil.java
index b03b6c7..884ab2d 100644
--- a/src/main/java/org/codehaus/groovy/syntax/TokenUtil.java
+++ b/src/main/java/org/codehaus/groovy/syntax/TokenUtil.java
@@ -18,45 +18,30 @@
  */
 package org.codehaus.groovy.syntax;
 
-import static org.codehaus.groovy.syntax.Types.BITWISE_AND;
-import static org.codehaus.groovy.syntax.Types.BITWISE_AND_EQUAL;
-import static org.codehaus.groovy.syntax.Types.BITWISE_OR;
-import static org.codehaus.groovy.syntax.Types.BITWISE_OR_EQUAL;
-import static org.codehaus.groovy.syntax.Types.BITWISE_XOR;
-import static org.codehaus.groovy.syntax.Types.BITWISE_XOR_EQUAL;
-import static org.codehaus.groovy.syntax.Types.DIVIDE;
-import static org.codehaus.groovy.syntax.Types.DIVIDE_EQUAL;
-import static org.codehaus.groovy.syntax.Types.INTDIV;
-import static org.codehaus.groovy.syntax.Types.INTDIV_EQUAL;
-import static org.codehaus.groovy.syntax.Types.LEFT_SHIFT;
-import static org.codehaus.groovy.syntax.Types.LEFT_SHIFT_EQUAL;
-import static org.codehaus.groovy.syntax.Types.LOGICAL_AND;
-import static org.codehaus.groovy.syntax.Types.LOGICAL_AND_EQUAL;
-import static org.codehaus.groovy.syntax.Types.LOGICAL_OR;
-import static org.codehaus.groovy.syntax.Types.LOGICAL_OR_EQUAL;
-import static org.codehaus.groovy.syntax.Types.MINUS;
-import static org.codehaus.groovy.syntax.Types.MINUS_EQUAL;
-import static org.codehaus.groovy.syntax.Types.MOD;
-import static org.codehaus.groovy.syntax.Types.MOD_EQUAL;
-import static org.codehaus.groovy.syntax.Types.MULTIPLY;
-import static org.codehaus.groovy.syntax.Types.MULTIPLY_EQUAL;
-import static org.codehaus.groovy.syntax.Types.PLUS;
-import static org.codehaus.groovy.syntax.Types.PLUS_EQUAL;
-import static org.codehaus.groovy.syntax.Types.POWER;
-import static org.codehaus.groovy.syntax.Types.POWER_EQUAL;
-import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT;
-import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_EQUAL;
-import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_UNSIGNED;
-import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_UNSIGNED_EQUAL;
+import java.util.Optional;
 
 /**
  * Utility methods for working with Tokens.
- *
  */
 public class TokenUtil {
+
     private TokenUtil() {
     }
 
+    public static Optional<Token> asAssignment(int op) {
+        switch (op) {
+            case Types.PLUS_PLUS:
+            case Types.PREFIX_PLUS_PLUS:
+            case Types.POSTFIX_PLUS_PLUS:
+                return Optional.of(Token.newSymbol(Types.PLUS_EQUAL, -1, -1));
+            case Types.MINUS_MINUS:
+            case Types.PREFIX_MINUS_MINUS:
+            case Types.POSTFIX_MINUS_MINUS:
+                return Optional.of(Token.newSymbol(Types.MINUS_EQUAL, -1, -1));
+        }
+        return Optional.empty();
+    }
+
     /**
      * Removes the assignment portion of a given token.  If the given token
      * is not an operator with assignment, the given token is returned.
@@ -67,21 +52,21 @@ public class TokenUtil {
      */
     public static int removeAssignment(int op) {
         switch (op) {
-            case PLUS_EQUAL: return PLUS;
-            case MINUS_EQUAL: return MINUS;
-            case MULTIPLY_EQUAL: return MULTIPLY;
-            case LEFT_SHIFT_EQUAL: return LEFT_SHIFT;
-            case RIGHT_SHIFT_EQUAL: return RIGHT_SHIFT;
-            case RIGHT_SHIFT_UNSIGNED_EQUAL: return RIGHT_SHIFT_UNSIGNED;
-            case LOGICAL_OR_EQUAL: return LOGICAL_OR;
-            case LOGICAL_AND_EQUAL: return LOGICAL_AND;
-            case MOD_EQUAL: return MOD;
-            case DIVIDE_EQUAL: return DIVIDE;
-            case INTDIV_EQUAL: return INTDIV;
-            case POWER_EQUAL: return POWER;
-            case BITWISE_OR_EQUAL: return BITWISE_OR;
-            case BITWISE_AND_EQUAL: return BITWISE_AND;
-            case BITWISE_XOR_EQUAL: return BITWISE_XOR;
+            case Types.PLUS_EQUAL: return Types.PLUS;
+            case Types.MINUS_EQUAL: return Types.MINUS;
+            case Types.MULTIPLY_EQUAL: return Types.MULTIPLY;
+            case Types.LEFT_SHIFT_EQUAL: return Types.LEFT_SHIFT;
+            case Types.RIGHT_SHIFT_EQUAL: return Types.RIGHT_SHIFT;
+            case Types.RIGHT_SHIFT_UNSIGNED_EQUAL: return Types.RIGHT_SHIFT_UNSIGNED;
+            case Types.LOGICAL_OR_EQUAL: return Types.LOGICAL_OR;
+            case Types.LOGICAL_AND_EQUAL: return Types.LOGICAL_AND;
+            case Types.MOD_EQUAL: return Types.MOD;
+            case Types.DIVIDE_EQUAL: return Types.DIVIDE;
+            case Types.INTDIV_EQUAL: return Types.INTDIV;
+            case Types.POWER_EQUAL: return Types.POWER;
+            case Types.BITWISE_OR_EQUAL: return Types.BITWISE_OR;
+            case Types.BITWISE_AND_EQUAL: return Types.BITWISE_AND;
+            case Types.BITWISE_XOR_EQUAL: return Types.BITWISE_XOR;
             default: return op;
         }
     }
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index acdd3d9..3c6f10c 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -186,6 +186,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.binX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.isOrImplements;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.thisPropX;
@@ -2043,7 +2044,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
     @Override
     public void visitPostfixExpression(final PostfixExpression expression) {
-        super.visitPostfixExpression(expression);
         Expression operand = expression.getExpression();
         int operator = expression.getOperation().getType();
         visitPrefixOrPostifExpression(expression, operand, operator);
@@ -2051,46 +2051,55 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
     @Override
     public void visitPrefixExpression(final PrefixExpression expression) {
-        super.visitPrefixExpression(expression);
         Expression operand = expression.getExpression();
         int operator = expression.getOperation().getType();
         visitPrefixOrPostifExpression(expression, operand, operator);
     }
 
     private void visitPrefixOrPostifExpression(final Expression origin, final Expression operand, final int operator) {
-        boolean isPostfix = origin instanceof PostfixExpression;
-        ClassNode exprType = getType(operand);
-        String name = operator == PLUS_PLUS ? "next" : operator == MINUS_MINUS ? "previous" : null;
-
-        if (name != null && isNumberType(exprType)) {
-            if (!isPrimitiveType(exprType)) {
-                MethodNode node = findMethodOrFail(varX("_dummy_", exprType), exprType, name);
+        Optional<Token> token = TokenUtil.asAssignment(operator);
+        if (token.isPresent()) { // push "operand += 1" or "operand -= 1" onto stack for LHS checks
+            typeCheckingContext.pushEnclosingBinaryExpression(binX(operand, token.get(), constX(1)));
+        }
+        try {
+            operand.visit(this);
+            ClassNode operandType = getType(operand);
+            boolean isPostfix = (origin instanceof PostfixExpression);
+            String name = (operator == PLUS_PLUS ? "next" : operator == MINUS_MINUS ? "previous" : null);
+
+            if (name != null && isNumberType(operandType)) {
+                if (!isPrimitiveType(operandType)) {
+                    MethodNode node = findMethodOrFail(varX("_dummy_", operandType), operandType, name);
+                    if (node != null) {
+                        storeTargetMethod(origin, node);
+                        storeType(origin, isPostfix ? operandType : getMathWideningClassNode(operandType));
+                        return;
+                    }
+                }
+                storeType(origin, operandType);
+                return;
+            }
+            if (name != null && operandType.isDerivedFrom(Number_TYPE)) {
+                // special case for numbers, improve type checking as we can expect ++ and -- to return the same type
+                MethodNode node = findMethodOrFail(operand, operandType, name);
                 if (node != null) {
                     storeTargetMethod(origin, node);
-                    storeType(origin, isPostfix ? exprType : getMathWideningClassNode(exprType));
+                    storeType(origin, getMathWideningClassNode(operandType));
                     return;
                 }
             }
-            storeType(origin, exprType);
-            return;
-        }
-        if (name != null && exprType.isDerivedFrom(Number_TYPE)) {
-            // special case for numbers, improve type checking as we can expect ++ and -- to return the same type
-            MethodNode node = findMethodOrFail(operand, exprType, name);
+            if (name == null) {
+                addUnsupportedPreOrPostfixExpressionError(origin);
+                return;
+            }
+
+            MethodNode node = findMethodOrFail(operand, operandType, name);
             if (node != null) {
                 storeTargetMethod(origin, node);
-                storeType(origin, getMathWideningClassNode(exprType));
-                return;
+                storeType(origin, isPostfix ? operandType : inferReturnTypeGenerics(operandType, node, ArgumentListExpression.EMPTY_ARGUMENTS));
             }
-        }
-        if (name == null) {
-            addUnsupportedPreOrPostfixExpressionError(origin);
-            return;
-        }
-        MethodNode node = findMethodOrFail(operand, exprType, name);
-        if (node != null) {
-            storeTargetMethod(origin, node);
-            storeType(origin, isPostfix ? exprType : inferReturnTypeGenerics(exprType, node, ArgumentListExpression.EMPTY_ARGUMENTS));
+        } finally {
+            if (token.isPresent()) typeCheckingContext.popEnclosingBinaryExpression();
         }
     }