You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2019/11/22 02:41:14 UTC

[groovy] branch master updated: STC: isLHSOfEnclosingAssignment returns true for ++/-- on variable expr

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

sunlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 8c0c5b0  STC: isLHSOfEnclosingAssignment returns true for ++/-- on variable expr
8c0c5b0 is described below

commit 8c0c5b018805fcab7217f5cdc784fc88354cfb15
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 79132b3..bc36c28 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -187,6 +187,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;
@@ -2044,7 +2045,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);
@@ -2052,46 +2052,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();
         }
     }