Skip to content

Commit 35e4f87

Browse files
committed
GROOVY-9530: use parsed static field value for constant inlining
1 parent 6302c23 commit 35e4f87

3 files changed

Lines changed: 66 additions & 20 deletions

File tree

src/main/java/org/apache/groovy/ast/tools/ExpressionUtils.java

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
3333
import org.codehaus.groovy.runtime.typehandling.NumberMath;
3434

35-
import java.lang.reflect.Field;
36-
import java.lang.reflect.Modifier;
3735
import java.math.BigDecimal;
3836
import java.util.List;
3937
import java.util.ListIterator;
@@ -258,33 +256,36 @@ public static Expression transformInlineConstants(final Expression exp) {
258256
* <li>Binary expressions - string concatenation and numeric +, -, /, *</li>
259257
* <li>List expressions - list of constants</li>
260258
* </ul>
259+
*
261260
* @param exp the original expression
262261
* @param attrType the type that the final constant should be
263262
* @return the transformed type or the original if no transformation was possible
264263
*/
265264
public static Expression transformInlineConstants(final Expression exp, final ClassNode attrType) {
266265
if (exp instanceof PropertyExpression) {
267266
PropertyExpression pe = (PropertyExpression) exp;
268-
ClassNode type = pe.getObjectExpression().getType();
269-
if (pe.getObjectExpression() instanceof ClassExpression && !type.isEnum()) {
270-
if (type.isPrimaryClassNode()) {
271-
FieldNode fn = type.getField(pe.getPropertyAsString());
272-
if (fn != null && fn.isStatic() && fn.isFinal()) {
273-
Expression e = transformInlineConstants(fn.getInitialValueExpression(), attrType);
274-
if (e != null) {
275-
return e;
276-
}
267+
Expression e = pe.getObjectExpression();
268+
ClassNode cn;
269+
FieldNode fn;
270+
if (e instanceof ClassExpression
271+
&& !(cn = e.getType().redirect()).isEnum()
272+
&& (cn.isPrimaryClassNode() || cn.isResolved())
273+
&& (fn = ClassNodeUtils.getField(cn, pe.getPropertyAsString())) != null
274+
&& fn.isStatic()
275+
&& fn.isFinal()) {
276+
if (fn.hasInitialExpression()) {
277+
e = transformInlineConstants(fn.getInitialValueExpression(), attrType);
278+
if (e instanceof ConstantExpression) {
279+
return e;
277280
}
278-
} else if (type.isResolved()) {
281+
} else if (cn.isResolved()) {
279282
try {
280-
Field field = type.redirect().getTypeClass().getField(pe.getPropertyAsString());
281-
if (field != null && Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) {
282-
ConstantExpression ce = new ConstantExpression(field.get(null), true);
283-
configure(exp, ce);
284-
return ce;
283+
var field = cn.getTypeClass().getField(pe.getPropertyAsString());
284+
if (field != null) {
285+
return configure(exp, new ConstantExpression(field.get(null), true));
285286
}
286-
} catch (Exception | LinkageError e) {
287-
// ignore, leave property expression in place and we'll report later
287+
} catch (Exception | LinkageError ignore) {
288+
// leave property expression and we will report later
288289
}
289290
}
290291
}

src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ void finished(final ClassNode result) {
5353
// ex: java.util.Collections#EMPTY_LIST/EMPTY_MAP/EMPTY_SET
5454
type[0] = GenericsUtils.nonGeneric(type[0]);
5555
}
56-
return new FieldNode(field.fieldName, field.accessModifiers, type[0], owner, field.value != null ? new ConstantExpression(field.value) : null);
56+
return new FieldNode(field.fieldName, field.accessModifiers, type[0], owner, field.value != null ? new ConstantExpression(field.value, true) : null);
5757
}
5858

5959
static MethodNode createMethodNode(final AsmReferenceResolver resolver, final MethodStub method) {
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package bugs
20+
21+
import org.junit.jupiter.api.Test
22+
23+
import static groovy.test.GroovyAssert.assertScript
24+
25+
final class Groovy9530 {
26+
27+
static class StaticClass {
28+
public static final int STATIC_VALUE = getStaticValue()
29+
30+
private static int getStaticValue() {
31+
return 'resource from classpath'.length()
32+
}
33+
}
34+
35+
@Test
36+
void testConstantInlining() {
37+
assertScript """import bugs.Groovy9530.StaticClass
38+
class C {
39+
public static final int VALUE = StaticClass.STATIC_VALUE
40+
}
41+
42+
assert C.VALUE == 23
43+
"""
44+
}
45+
}

0 commit comments

Comments
 (0)