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 2022/07/13 19:30:29 UTC
[groovy] branch GROOVY_4_0_X updated: GROOVY-8643: SC: null-safe for-in loop
This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
new d98f6cb840 GROOVY-8643: SC: null-safe for-in loop
d98f6cb840 is described below
commit d98f6cb8408377033251a6534d9745d57b485290
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Jul 12 14:57:36 2022 -0500
GROOVY-8643: SC: null-safe for-in loop
(cherry picked from commit deb32b0f672550fe6f2d634ea45d4b390987f246)
---
.../groovy/classgen/asm/StatementWriter.java | 22 ++++++++--------
.../asm/sc/StaticTypesStatementWriter.java | 16 +++++++-----
src/test/groovy/transform/stc/LoopsSTCTest.groovy | 29 ++++++++++++++++++++--
3 files changed, 49 insertions(+), 18 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
index fca54340ec..36c4f24b3d 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
@@ -60,6 +60,7 @@ import static org.objectweb.asm.Opcodes.ATHROW;
import static org.objectweb.asm.Opcodes.CHECKCAST;
import static org.objectweb.asm.Opcodes.GOTO;
import static org.objectweb.asm.Opcodes.IFEQ;
+import static org.objectweb.asm.Opcodes.IFNULL;
import static org.objectweb.asm.Opcodes.MONITORENTER;
import static org.objectweb.asm.Opcodes.MONITOREXIT;
import static org.objectweb.asm.Opcodes.NOP;
@@ -133,28 +134,29 @@ public class StatementWriter {
BytecodeVariable variable = compileStack.defineVariable(statement.getVariable(), false);
// get the iterator and generate the loop control
- int iteratorIndex = compileStack.defineTemporaryVariable("iterator", ClassHelper.Iterator_TYPE, true);
- Label continueLabel = compileStack.getContinueLabel();
- Label breakLabel = compileStack.getBreakLabel();
+ int iterator = compileStack.defineTemporaryVariable("iterator", ClassHelper.Iterator_TYPE, true);
+ Label breakLabel = compileStack.getBreakLabel(), continueLabel = compileStack.getContinueLabel();
+
+ mv.visitVarInsn(ALOAD, iterator);
+ mv.visitJumpInsn(IFNULL, breakLabel);
mv.visitLabel(continueLabel);
- mv.visitVarInsn(ALOAD, iteratorIndex);
+
+ mv.visitVarInsn(ALOAD, iterator);
writeIteratorHasNext(mv);
- // note: ifeq tests for ==0, a boolean is 0 if it is false
- mv.visitJumpInsn(IFEQ, breakLabel);
+ mv.visitJumpInsn(IFEQ, breakLabel); // jump if zero (aka false)
- mv.visitVarInsn(ALOAD, iteratorIndex);
+ mv.visitVarInsn(ALOAD, iterator);
writeIteratorNext(mv);
operandStack.push(ClassHelper.OBJECT_TYPE);
operandStack.storeVar(variable);
// generate the loop body
statement.getLoopBlock().visit(controller.getAcg());
-
mv.visitJumpInsn(GOTO, continueLabel);
- mv.visitLabel(breakLabel);
- compileStack.removeVar(iteratorIndex);
+ mv.visitLabel(breakLabel);
+ compileStack.removeVar(iterator);
}
protected void writeIteratorHasNext(final MethodVisitor mv) {
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
index 283b4df40d..a61d4a27b8 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
@@ -196,22 +196,25 @@ public class StaticTypesStatementWriter extends StatementWriter {
collectionExpression.visit(controller.getAcg());
- int enumIdx = compileStack.defineTemporaryVariable("$enum", ENUMERATION_CLASSNODE, true);
+ int enumeration = compileStack.defineTemporaryVariable("$enum", ENUMERATION_CLASSNODE, true);
+
+ mv.visitVarInsn(ALOAD, enumeration);
+ mv.visitJumpInsn(IFNULL, breakLabel);
mv.visitLabel(continueLabel);
- mv.visitVarInsn(ALOAD, enumIdx);
+
+ mv.visitVarInsn(ALOAD, enumeration);
ENUMERATION_HASMORE_METHOD.call(mv);
- // note: ifeq tests for ==0, a boolean is 0 if it is false
- mv.visitJumpInsn(IFEQ, breakLabel);
+ mv.visitJumpInsn(IFEQ, breakLabel); // jump if zero (aka false)
- mv.visitVarInsn(ALOAD, enumIdx);
+ mv.visitVarInsn(ALOAD, enumeration);
ENUMERATION_NEXT_METHOD.call(mv);
operandStack.push(ClassHelper.OBJECT_TYPE);
operandStack.storeVar(variable);
loop.getLoopBlock().visit(controller.getAcg());
-
mv.visitJumpInsn(GOTO, continueLabel);
+
mv.visitLabel(breakLabel);
}
@@ -227,6 +230,7 @@ public class StaticTypesStatementWriter extends StatementWriter {
MethodCallExpression call = GeneralUtils.callX(collectionExpression, "iterator");
call.setImplicitThis(false);
call.setMethodTarget(iterator);
+ call.setSafe(true);//GROOVY-8643
call.visit(controller.getAcg());
} else {
collectionExpression.visit(controller.getAcg());
diff --git a/src/test/groovy/transform/stc/LoopsSTCTest.groovy b/src/test/groovy/transform/stc/LoopsSTCTest.groovy
index 5d5f7e87e8..123232a179 100644
--- a/src/test/groovy/transform/stc/LoopsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/LoopsSTCTest.groovy
@@ -174,7 +174,27 @@ class LoopsSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-8643
+ void testForInLoopOnList() {
+ assertScript '''
+ List<String> list = null
+ for (item in list) {
+ item.toUpperCase()
+ }
+ '''
+ }
+
+ // GROOVY-8643
void testForInLoopOnArray() {
+ assertScript '''
+ String[] strings = null
+ for (string in strings) {
+ string.toUpperCase()
+ }
+ '''
+ }
+
+ void testForInLoopOnArray2() {
assertScript '''
String[] strings = ['a','b','c']
for (string in strings) {
@@ -184,7 +204,7 @@ class LoopsSTCTest extends StaticTypeCheckingTestCase {
}
// GROOVY-10579
- void testForInLoopOnArray2() {
+ void testForInLoopOnArray3() {
assertScript '''
int[] numbers = [1,2,3,4,5]
int sum = 0
@@ -212,7 +232,7 @@ class LoopsSTCTest extends StaticTypeCheckingTestCase {
assertScript '''
Vector<String> v = new Vector<>()
v.add('ooo')
- def en = v.elements()
+ Enumeration<String> en = v.elements()
for (e in en) {
assert e.toUpperCase() == 'OOO'
}
@@ -228,6 +248,11 @@ class LoopsSTCTest extends StaticTypeCheckingTestCase {
assert e.toUpperCase() in ['OOO','GROOVY']
if (e=='ooo') continue
}
+
+ en = null
+ for (e in en) {
+ e.toUpperCase()
+ }
'''
}