From fd98b47bd2b2304039bfff32f3386970b733dbbe Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Thu, 13 Feb 2020 13:58:54 -0600 Subject: [PATCH] GROOVY-8707: SC: use makeSetProperty for compound assignment of property StaticTypesBinaryExpressionMultiTypeDispatcher#evaluateEqual does this --- ...esBinaryExpressionMultiTypeDispatcher.java | 35 +++++++++++++++++++ .../transform/stc/STCAssignmentTest.groovy | 15 ++++++++ .../sc/AssignmentsStaticCompileTest.groovy | 11 ++++-- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java index d97ba2384e4..3d1661aff1b 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java @@ -45,6 +45,8 @@ import org.codehaus.groovy.classgen.asm.OperandStack; import org.codehaus.groovy.classgen.asm.VariableSlotLoader; import org.codehaus.groovy.classgen.asm.WriterController; +import org.codehaus.groovy.syntax.Token; +import org.codehaus.groovy.syntax.TokenUtil; import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys; import org.codehaus.groovy.transform.sc.StaticCompilationVisitor; import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport; @@ -135,6 +137,39 @@ private static void visitInsnByType(final ClassNode top, final MethodVisitor mv, } } + @Override + protected void evaluateBinaryExpressionWithAssignment(final String method, final BinaryExpression expression) { + Expression leftExpression = expression.getLeftExpression(); + if (leftExpression instanceof PropertyExpression) { + PropertyExpression pexp = (PropertyExpression) leftExpression; + + BinaryExpression expressionWithoutAssignment = binX( + leftExpression, + Token.newSymbol( + TokenUtil.removeAssignment(expression.getOperation().getType()), + expression.getOperation().getStartLine(), + expression.getOperation().getStartColumn() + ), + expression.getRightExpression() + ); + expressionWithoutAssignment.copyNodeMetaData(expression); + expressionWithoutAssignment.setSafe(expression.isSafe()); + expressionWithoutAssignment.setSourcePosition(expression); + + if (makeSetProperty( + pexp.getObjectExpression(), + pexp.getProperty(), + expressionWithoutAssignment, + pexp.isSafe(), + pexp.isSpreadSafe(), + pexp.isImplicitThis(), + pexp instanceof AttributeExpression)) { + return; + } + } + super.evaluateBinaryExpressionWithAssignment(method, expression); + } + @Override public void evaluateEqual(final BinaryExpression expression, final boolean defineVariable) { Expression leftExpression = expression.getLeftExpression(); diff --git a/src/test/groovy/transform/stc/STCAssignmentTest.groovy b/src/test/groovy/transform/stc/STCAssignmentTest.groovy index cb688ccf379..ace78826cdd 100644 --- a/src/test/groovy/transform/stc/STCAssignmentTest.groovy +++ b/src/test/groovy/transform/stc/STCAssignmentTest.groovy @@ -138,6 +138,21 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase { ''' } + void testPlusEqualsOnProperty() { + assertScript ''' + class C { + int i + + static main(args) { + def c = new C() + c.i = 5 + c.i += 10 + assert c.i == 15 + } + } + ''' + } + // GROOVY-9385 void testPlusEqualsOnPrivateField() { assertScript ''' diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/AssignmentsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/AssignmentsStaticCompileTest.groovy index 24b2f73fbfe..538589f10db 100644 --- a/src/test/org/codehaus/groovy/classgen/asm/sc/AssignmentsStaticCompileTest.groovy +++ b/src/test/org/codehaus/groovy/classgen/asm/sc/AssignmentsStaticCompileTest.groovy @@ -21,7 +21,14 @@ package org.codehaus.groovy.classgen.asm.sc import groovy.transform.stc.STCAssignmentTest /** - * Unit tests for static type checking : assignments. + * Unit tests for static compilation : assignments. */ -class AssignmentsStaticCompileTest extends STCAssignmentTest implements StaticCompilationTestSupport {} +final class AssignmentsStaticCompileTest extends STCAssignmentTest implements StaticCompilationTestSupport { + @Override // GROOVY-8707 + void testPlusEqualsOnProperty() { + super.testPlusEqualsOnProperty() + String bytecode = astTrees['C'][1] + assert !bytecode.contains('ScriptBytecodeAdapter.setGroovyObjectProperty') : '"c.i += 10" should use setter, not dynamic property' + } +}