This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY-9530 in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 35e4f871ef1efb7b8b9eafd8c79cc702f70a69d0 Author: Eric Milles <[email protected]> AuthorDate: Sat Apr 19 10:53:25 2025 -0500 GROOVY-9530: use parsed static field value for constant inlining --- .../apache/groovy/ast/tools/ExpressionUtils.java | 39 ++++++++++--------- .../ast/decompiled/MemberSignatureParser.java | 2 +- src/test/groovy/bugs/Groovy9530.groovy | 45 ++++++++++++++++++++++ 3 files changed, 66 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/apache/groovy/ast/tools/ExpressionUtils.java b/src/main/java/org/apache/groovy/ast/tools/ExpressionUtils.java index 178a96e5b6..1731dcbd7d 100644 --- a/src/main/java/org/apache/groovy/ast/tools/ExpressionUtils.java +++ b/src/main/java/org/apache/groovy/ast/tools/ExpressionUtils.java @@ -32,8 +32,6 @@ import org.codehaus.groovy.ast.expr.VariableExpression; import org.codehaus.groovy.runtime.DefaultGroovyMethods; import org.codehaus.groovy.runtime.typehandling.NumberMath; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.util.List; import java.util.ListIterator; @@ -258,6 +256,7 @@ public final class ExpressionUtils { * <li>Binary expressions - string concatenation and numeric +, -, /, *</li> * <li>List expressions - list of constants</li> * </ul> + * * @param exp the original expression * @param attrType the type that the final constant should be * @return the transformed type or the original if no transformation was possible @@ -265,26 +264,28 @@ public final class ExpressionUtils { public static Expression transformInlineConstants(final Expression exp, final ClassNode attrType) { if (exp instanceof PropertyExpression) { PropertyExpression pe = (PropertyExpression) exp; - ClassNode type = pe.getObjectExpression().getType(); - if (pe.getObjectExpression() instanceof ClassExpression && !type.isEnum()) { - if (type.isPrimaryClassNode()) { - FieldNode fn = type.getField(pe.getPropertyAsString()); - if (fn != null && fn.isStatic() && fn.isFinal()) { - Expression e = transformInlineConstants(fn.getInitialValueExpression(), attrType); - if (e != null) { - return e; - } + Expression e = pe.getObjectExpression(); + ClassNode cn; + FieldNode fn; + if (e instanceof ClassExpression + && !(cn = e.getType().redirect()).isEnum() + && (cn.isPrimaryClassNode() || cn.isResolved()) + && (fn = ClassNodeUtils.getField(cn, pe.getPropertyAsString())) != null + && fn.isStatic() + && fn.isFinal()) { + if (fn.hasInitialExpression()) { + e = transformInlineConstants(fn.getInitialValueExpression(), attrType); + if (e instanceof ConstantExpression) { + return e; } - } else if (type.isResolved()) { + } else if (cn.isResolved()) { try { - Field field = type.redirect().getTypeClass().getField(pe.getPropertyAsString()); - if (field != null && Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) { - ConstantExpression ce = new ConstantExpression(field.get(null), true); - configure(exp, ce); - return ce; + var field = cn.getTypeClass().getField(pe.getPropertyAsString()); + if (field != null) { + return configure(exp, new ConstantExpression(field.get(null), true)); } - } catch (Exception | LinkageError e) { - // ignore, leave property expression in place and we'll report later + } catch (Exception | LinkageError ignore) { + // leave property expression and we will report later } } } diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java b/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java index 6e25c3f9ae..48426dedbc 100644 --- a/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java +++ b/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java @@ -53,7 +53,7 @@ class MemberSignatureParser { // ex: java.util.Collections#EMPTY_LIST/EMPTY_MAP/EMPTY_SET type[0] = GenericsUtils.nonGeneric(type[0]); } - return new FieldNode(field.fieldName, field.accessModifiers, type[0], owner, field.value != null ? new ConstantExpression(field.value) : null); + return new FieldNode(field.fieldName, field.accessModifiers, type[0], owner, field.value != null ? new ConstantExpression(field.value, true) : null); } static MethodNode createMethodNode(final AsmReferenceResolver resolver, final MethodStub method) { diff --git a/src/test/groovy/bugs/Groovy9530.groovy b/src/test/groovy/bugs/Groovy9530.groovy new file mode 100644 index 0000000000..20f985a96c --- /dev/null +++ b/src/test/groovy/bugs/Groovy9530.groovy @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package bugs + +import org.junit.jupiter.api.Test + +import static groovy.test.GroovyAssert.assertScript + +final class Groovy9530 { + + static class StaticClass { + public static final int STATIC_VALUE = getStaticValue() + + private static int getStaticValue() { + return 'resource from classpath'.length() + } + } + + @Test + void testConstantInlining() { + assertScript """import bugs.Groovy9530.StaticClass + class C { + public static final int VALUE = StaticClass.STATIC_VALUE + } + + assert C.VALUE == 23 + """ + } +}
