This is an automated email from the ASF dual-hosted git repository.
emilles 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 24d2ef995b GROOVY-11840: SC: implicit-this reference to outer class
static field
24d2ef995b is described below
commit 24d2ef995b1fc35c3237450f6b4240e7eb27d975
Author: Eric Milles <[email protected]>
AuthorDate: Wed Jan 14 10:11:18 2026 -0600
GROOVY-11840: SC: implicit-this reference to outer class static field
4_0_X backport
---
.../classgen/asm/sc/StaticInvocationWriter.java | 39 ++++++----
.../transformers/BooleanExpressionTransformer.java | 89 ++++++++--------------
.../groovy/gls/innerClass/InnerClassTest.groovy | 4 +-
.../groovy/transform/stc/ClosuresSTCTest.groovy | 24 +++++-
4 files changed, 78 insertions(+), 78 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
index 2e3710c5e1..db4a93ad06 100644
---
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
+++
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
@@ -44,7 +44,6 @@ import org.codehaus.groovy.ast.stmt.ForStatement;
import org.codehaus.groovy.classgen.AsmClassGenerator;
import org.codehaus.groovy.classgen.Verifier;
import org.codehaus.groovy.classgen.asm.BytecodeHelper;
-import org.codehaus.groovy.classgen.asm.CallSiteWriter;
import org.codehaus.groovy.classgen.asm.CompileStack;
import org.codehaus.groovy.classgen.asm.ExpressionAsVariableSlot;
import org.codehaus.groovy.classgen.asm.InvocationWriter;
@@ -520,6 +519,11 @@ public class StaticInvocationWriter extends
InvocationWriter {
}
}
+ @Override
+ protected boolean makeCachedCall(final Expression origin, final
ClassExpression sender, final Expression receiver, final Expression message,
final Expression arguments, final MethodCallerMultiAdapter adapter, final
boolean safe, final boolean spreadSafe, final boolean implicitThis, final
boolean containsSpreadExpression) {
+ return false;
+ }
+
@Override
public void makeCall(final Expression origin, final Expression receiver,
final Expression message, final Expression arguments, final
MethodCallerMultiAdapter adapter, final boolean safe, final boolean spreadSafe,
final boolean implicitThis) {
if (origin.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION) !=
null) {
@@ -639,17 +643,11 @@ public class StaticInvocationWriter extends
InvocationWriter {
mv.visitInsn(ACONST_NULL);
mv.visitLabel(endof);
} else {
- if (origin instanceof AttributeExpression && (adapter ==
AsmClassGenerator.getField || adapter ==
AsmClassGenerator.getGroovyObjectField)) {
- CallSiteWriter callSiteWriter = controller.getCallSiteWriter();
- String fieldName = ((AttributeExpression)
origin).getPropertyAsString();
- if (fieldName != null && callSiteWriter instanceof
StaticTypesCallSiteWriter) {
- ClassNode receiverType =
controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
- if (((StaticTypesCallSiteWriter)
callSiteWriter).makeGetField(receiver, receiverType, fieldName, safe, false)) {
- return;
- }
- }
+ boolean tryGetField = (adapter == AsmClassGenerator.getField
+ || adapter == AsmClassGenerator.getGroovyObjectField);
+ if (!tryGetField || !makeGetField(origin, receiver, safe)) { //
GETFIELD or GETSTATIC
+ super.makeCall(origin, receiver, message, arguments, adapter,
safe, spreadSafe, implicitThis);
}
- super.makeCall(origin, receiver, message, arguments, adapter,
safe, spreadSafe, implicitThis);
}
}
@@ -683,6 +681,20 @@ public class StaticInvocationWriter extends
InvocationWriter {
return false;
}
+ private boolean makeGetField(final Expression origin, final Expression
receiver, final boolean safe) {
+ if (origin instanceof AttributeExpression &&
controller.getCallSiteWriter() instanceof StaticTypesCallSiteWriter) {
+ String fieldName = ((AttributeExpression)
origin).getPropertyAsString();
+ if (fieldName != null) {
+ ClassNode receiverType = receiver.getType();
+ if (!(receiver instanceof ClassExpression)) { // GROOVY-11840
+ receiverType =
controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
+ }
+ return ((StaticTypesCallSiteWriter)
controller.getCallSiteWriter()).makeGetField(receiver, receiverType, fieldName,
safe, /*implicitThis:*/false);
+ }
+ }
+ return false;
+ }
+
private class CheckcastReceiverExpression extends Expression {
private final Expression receiver;
private final MethodNode target;
@@ -756,9 +768,4 @@ public class StaticInvocationWriter extends
InvocationWriter {
return type;
}
}
-
- @Override
- protected boolean makeCachedCall(final Expression origin, final
ClassExpression sender, final Expression receiver, final Expression message,
final Expression arguments, final MethodCallerMultiAdapter adapter, final
boolean safe, final boolean spreadSafe, final boolean implicitThis, final
boolean containsSpreadExpression) {
- return false;
- }
}
diff --git
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/BooleanExpressionTransformer.java
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/BooleanExpressionTransformer.java
index f1cd0b13a0..7746f797dc 100644
---
a/src/main/java/org/codehaus/groovy/transform/sc/transformers/BooleanExpressionTransformer.java
+++
b/src/main/java/org/codehaus/groovy/transform/sc/transformers/BooleanExpressionTransformer.java
@@ -66,12 +66,10 @@ class BooleanExpressionTransformer {
} while (expr instanceof BooleanExpression);
if (!(expr instanceof BinaryExpression)) {
- expr = transformer.transform(expr);
- ClassNode type = transformer.getTypeChooser().resolveType(expr,
transformer.getClassNode());
- Expression opt = new OptimizingBooleanExpression(expr, type);
- if (reverse) opt = new NotExpression(opt);
- opt.setSourcePosition(boolX);
- return opt;
+ expr = new
OptimizingBooleanExpression(transformer.transform(expr));
+ if (reverse) expr = new NotExpression(expr);
+ expr.setSourcePosition(boolX);
+ return expr;
}
return transformer.superTransform(boolX);
@@ -81,17 +79,13 @@ class BooleanExpressionTransformer {
private static class OptimizingBooleanExpression extends BooleanExpression
{
- private final ClassNode type;
-
- OptimizingBooleanExpression(final Expression expression, final
ClassNode type) {
+ OptimizingBooleanExpression(final Expression expression) {
super(expression);
- // we must use the redirect node, otherwise InnerClassNode would
not have the "correct" type
- this.type = type.redirect();
}
@Override
public Expression transformExpression(final ExpressionTransformer
transformer) {
- Expression opt = new
OptimizingBooleanExpression(transformer.transform(getExpression()), type);
+ Expression opt = new
OptimizingBooleanExpression(transformer.transform(getExpression()));
opt.setSourcePosition(this);
opt.copyNodeMetaData(this);
return opt;
@@ -107,58 +101,37 @@ class BooleanExpressionTransformer {
int mark = os.getStackLength();
getExpression().visit(visitor);
- if (ClassHelper.isPrimitiveType(type) &&
!ClassHelper.isPrimitiveVoid(type)) { // GROOVY-10920
- if (ClassHelper.isPrimitiveBoolean(type)) {
- os.doGroovyCast(ClassHelper.boolean_TYPE);
- } else {
- BytecodeHelper.convertPrimitiveToBoolean(mv, type);
- os.replace(ClassHelper.boolean_TYPE);
- }
- return;
- }
+ ClassNode type = os.getTopOperand(); // GROOVY-6270,
GROOVY-9501, GROOVY-9569, GROOVY-10920, GROOVY-11840
- if (ClassHelper.isWrapperBoolean(type)) {
- Label unbox = new Label();
- Label exit = new Label();
- // check for null
+ if (ClassHelper.isPrimitiveType(type)) {
+ BytecodeHelper.convertPrimitiveToBoolean(mv, type);
+ } else {
mv.visitInsn(DUP);
- mv.visitJumpInsn(IFNONNULL, unbox);
- mv.visitInsn(POP);
- mv.visitInsn(ICONST_0);
- mv.visitJumpInsn(GOTO, exit);
- mv.visitLabel(unbox);
- if (!os.getTopOperand().equals(type))
BytecodeHelper.doCast(mv, type); // GROOVY-6270
- mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean",
"booleanValue", "()Z", false);
- mv.visitLabel(exit);
- os.replace(ClassHelper.boolean_TYPE);
- return;
- }
-
- mv.visitInsn(DUP);
- Label end = new Label();
- Label asBoolean = new Label();
- mv.visitJumpInsn(IFNONNULL, asBoolean);
+ Label end = new Label();
+ Label asBoolean = new Label();
+ mv.visitJumpInsn(IFNONNULL, asBoolean);
- // null => false
- mv.visitInsn(POP);
- mv.visitInsn(ICONST_0);
- mv.visitJumpInsn(GOTO, end);
-
- mv.visitLabel(asBoolean);
- ClassLoader loader =
controller.getSourceUnit().getClassLoader();
- if (replaceAsBooleanWithCompareToNull(type, loader)) {
- // value => true
+ // null => false
mv.visitInsn(POP);
- mv.visitInsn(ICONST_1);
- } else {
- os.castToBool(mark, true);
+ mv.visitInsn(ICONST_0);
+ mv.visitJumpInsn(GOTO, end);
+
+ mv.visitLabel(asBoolean);
+ if (ClassHelper.isWrapperBoolean(type)) {
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean",
"booleanValue", "()Z", false);
+ } else if (replaceAsBooleanWithCompareToNull(type,
controller.getSourceUnit().getClassLoader())) {
+ // value => true
+ mv.visitInsn(POP);
+ mv.visitInsn(ICONST_1);
+ } else {
+ os.castToBool(mark, true);
+ }
+ mv.visitLabel(end);
}
- mv.visitLabel(end);
os.replace(ClassHelper.boolean_TYPE);
- return;
+ } else {
+ super.visit(visitor);
}
-
- super.visit(visitor);
}
/**
@@ -172,7 +145,7 @@ class BooleanExpressionTransformer {
private static boolean replaceAsBooleanWithCompareToNull(final
ClassNode type, final ClassLoader dgmProvider) {
if (type.getMethod("asBoolean", Parameter.EMPTY_ARRAY) != null) {
// GROOVY-10711
- } else if (Modifier.isFinal(type.getModifiers()) ||
isEffectivelyFinal(type)) {
+ } else if (Modifier.isFinal(type.getModifiers()) ||
isEffectivelyFinal(type.redirect())) {
List<MethodNode> asBoolean =
findDGMMethodsByNameAndArguments(dgmProvider, type, "asBoolean",
ClassNode.EMPTY_ARRAY);
if (asBoolean.size() == 1) {
MethodNode theAsBoolean = asBoolean.get(0);
diff --git a/src/test/groovy/gls/innerClass/InnerClassTest.groovy
b/src/test/groovy/gls/innerClass/InnerClassTest.groovy
index 1f1b6259c9..b524bdab66 100644
--- a/src/test/groovy/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/groovy/gls/innerClass/InnerClassTest.groovy
@@ -729,8 +729,8 @@ final class InnerClassTest {
@Override
void run() {
try {
- if (!flag) {
- // do work
+ if (flag) {
+ assert false : 'boolean conversion'
}
} catch (e) {
error = e
diff --git a/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy
b/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy
index 6db7712637..e9a333f703 100644
--- a/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -779,7 +779,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
// GROOVY-6343
void testAccessStaticFieldFromNestedClosure() {
assertScript '''
- class A {
+ class C {
public static final CONST = "a"
static List doSomething() {
@@ -790,11 +790,31 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
}
}
}
- def result = A.doSomething()
+ def result = C.doSomething()
assert result == [['a','a'],['a','a']]
'''
}
+ // GROOVY-11840
+ void testAccessStaticFieldFromNestedClosure2() {
+ assertScript '''
+ class C {
+ private static final boolean FLAG = false
+
+ static main(args) {
+ (1..100).each {
+ if (FLAG) {
+ assert false : 'boolean conversion'
+ }
+ if (FLAG == true) {
+ assert false : 'boolean comparison'
+ }
+ }
+ }
+ }
+ '''
+ }
+
// GROOVY-11360
void testLexicalScopeVersusGetDynamicProperty() {
config.warningLevel =
org.codehaus.groovy.control.messages.WarningMessage.POSSIBLE_ERRORS