You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/05/01 18:54:34 UTC

[groovy] branch master updated: GROOVY-10611: stubgen: static final field with integer or decimal value

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 469e4d02ad GROOVY-10611: stubgen: static final field with integer or decimal value
469e4d02ad is described below

commit 469e4d02ad95d8dcf0366c778c58addd9b5677b0
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun May 1 13:47:14 2022 -0500

    GROOVY-10611: stubgen: static final field with integer or decimal value
---
 .../org/codehaus/groovy/classgen/Verifier.java     |  6 +-
 .../groovy/control/AnnotationConstantsVisitor.java | 49 +++++++--------
 .../groovy/tools/javac/JavaStubGenerator.java      | 71 +++++++++++++---------
 .../groovy/tools/stubgenerator/Groovy10611.groovy  | 50 +++++++++++++++
 4 files changed, 117 insertions(+), 59 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
index 99f52fbc2a..6cd9d6528a 100644
--- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -1136,7 +1136,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         ConstructorCallExpression specialCtorCall = getFirstIfSpecialConstructorCall(firstStatement);
 
         // in case of this(...) let the other constructor initialize
-        if (specialCtorCall != null && (specialCtorCall.isThisCall())) return;
+        if (specialCtorCall != null && specialCtorCall.isThisCall()) return;
 
         boolean isEnum = node.isEnum();
         List<Statement> statements = new ArrayList<>();
@@ -1283,8 +1283,8 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                     expression
             ));
             if (fieldNode.isStatic()) {
-                // GROOVY-3311: pre-defined constants added by groovy compiler for numbers/characters should be
-                // initialized first so that code dependent on it does not see their values as empty
+                // GROOVY-3311: pre-defined constants added by compiler for numbers/characters should be
+                // initialized first so that code dependent on them does not see their values as empty
                 Expression initialValueExpression = fieldNode.getInitialValueExpression();
                 Expression transformed = transformInlineConstants(initialValueExpression, fieldNode.getType());
                 if (transformed instanceof ConstantExpression) {
diff --git a/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java b/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
index 9e48fcfa46..7de3e635a5 100644
--- a/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
@@ -43,34 +43,36 @@ import static org.codehaus.groovy.ast.ClassHelper.isWrapperInteger;
 import static org.codehaus.groovy.ast.ClassHelper.isWrapperShort;
 
 /**
- * Visitor to resolve constants in annotation definitions.
+ * Resolves constants in annotation definitions.
  */
 public class AnnotationConstantsVisitor extends ClassCodeVisitorSupport {
-    private SourceUnit source;
-    private boolean inAnnotationDef;
 
-    public void visitClass(ClassNode node, SourceUnit source) {
-        this.source = source;
-        this.inAnnotationDef = node.isAnnotationDefinition();
-        super.visitClass(node);
-        this.inAnnotationDef = false;
-    }
+    private boolean annotationDef;
+    private SourceUnit sourceUnit;
 
     @Override
-    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
-        if (!inAnnotationDef) return;
-        visitStatement(node.getFirstStatement(), node.getReturnType());
+    protected SourceUnit getSourceUnit() {
+        return sourceUnit;
     }
 
-    private static void visitStatement(Statement statement, ClassNode returnType) {
-        if (statement instanceof ReturnStatement) {
-            // normal path
-            ReturnStatement rs = (ReturnStatement) statement;
-            rs.setExpression(transformConstantExpression(rs.getExpression(), returnType));
-        } else if (statement instanceof ExpressionStatement) {
-            // path for JavaStubGenerator
-            ExpressionStatement es = (ExpressionStatement) statement;
-            es.setExpression(transformConstantExpression(es.getExpression(), returnType));
+    public void visitClass(final ClassNode classNode, final SourceUnit sourceUnit) {
+        this.sourceUnit = sourceUnit;
+        this.annotationDef = classNode.isAnnotationDefinition();
+        super.visitClass(classNode);
+        this.annotationDef = false;
+    }
+
+    @Override
+    protected void visitConstructorOrMethod(final MethodNode node, final boolean isConstructor) {
+        if (annotationDef) {
+            Statement statement = node.getFirstStatement();
+            if (statement instanceof ReturnStatement) {
+                ReturnStatement rs = (ReturnStatement) statement;
+                rs.setExpression(transformConstantExpression(rs.getExpression(), node.getReturnType()));
+            } else if (statement instanceof ExpressionStatement) {
+                ExpressionStatement es = (ExpressionStatement) statement;
+                es.setExpression(transformConstantExpression(es.getExpression(), node.getReturnType()));
+            }
         }
     }
 
@@ -134,9 +136,4 @@ public class AnnotationConstantsVisitor extends ClassCodeVisitorSupport {
         result.setSourcePosition(orig);
         return result;
     }
-
-    @Override
-    protected SourceUnit getSourceUnit() {
-        return source;
-    }
 }
diff --git a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
index 6509911596..31a51afbcf 100644
--- a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
+++ b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
@@ -83,6 +83,7 @@ import java.util.stream.Stream;
 import static org.apache.groovy.ast.tools.ConstructorNodeUtils.getFirstIfSpecialConstructorCall;
 import static org.codehaus.groovy.ast.ClassHelper.CLASS_Type;
 import static org.codehaus.groovy.ast.ClassHelper.getUnwrapper;
+import static org.codehaus.groovy.ast.ClassHelper.isBigDecimalType;
 import static org.codehaus.groovy.ast.ClassHelper.isCachedType;
 import static org.codehaus.groovy.ast.ClassHelper.isClassType;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveBoolean;
@@ -100,6 +101,8 @@ import static org.codehaus.groovy.ast.ClassHelper.isStringType;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isFloatingCategory;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isLongCategory;
 
 public class JavaStubGenerator {
     private final boolean java5;
@@ -251,38 +254,41 @@ public class JavaStubGenerator {
                 }
 
                 @Override
-                public void visitProperty(PropertyNode node) {
+                public void visitProperty(PropertyNode pn) {
                     // GROOVY-8233 skip static properties for traits since they don't make the interface
-                    if (!node.isStatic() || !Traits.isTrait(node.getDeclaringClass())) {
-                        super.visitProperty(node);
+                    if (!pn.isStatic() || !Traits.isTrait(pn.getDeclaringClass())) {
+                        super.visitProperty(pn);
                     }
                 }
 
                 @Override
                 public void addCovariantMethods(ClassNode cn) {}
                 @Override
-                protected void addInitialization(ClassNode node) {}
+                protected void addInitialization(ClassNode cn) {}
                 @Override
-                protected void addPropertyMethod(MethodNode method) {
-                    doAddMethod(method);
+                protected void addInitialization(ClassNode cn, ConstructorNode c) {}
+                @Override
+                protected void addPropertyMethod(MethodNode mn) {
+                    doAddMethod(mn);
                 }
                 @Override
-                protected void addReturnIfNeeded(MethodNode node) {}
+                protected void addReturnIfNeeded(MethodNode mn) {}
+
                 @Override
-                protected MethodNode addMethod(ClassNode node, boolean shouldBeSynthetic, String name, int modifiers, ClassNode returnType, Parameter[] parameters, ClassNode[] exceptions, Statement code) {
+                protected MethodNode addMethod(ClassNode cn, boolean shouldBeSynthetic, String name, int modifiers, ClassNode returnType, Parameter[] parameters, ClassNode[] exceptions, Statement code) {
                     return doAddMethod(new MethodNode(name, modifiers, returnType, parameters, exceptions, code));
                 }
 
                 @Override
-                protected void addConstructor(Parameter[] newParams, ConstructorNode ctor, Statement code, ClassNode node) {
-                    if (code instanceof ExpressionStatement) {//GROOVY-4508
-                        Statement temp = code;
+                protected void addConstructor(Parameter[] params, ConstructorNode ctor, Statement code, ClassNode node) {
+                    if (code instanceof ExpressionStatement) { //GROOVY-4508
+                        Statement stmt = code;
                         code = new BlockStatement();
-                        ((BlockStatement) code).addStatement(temp);
+                        ((BlockStatement) code).addStatement(stmt);
                     }
-                    ConstructorNode ctrNode = new ConstructorNode(ctor.getModifiers(), newParams, ctor.getExceptions(), code);
-                    ctrNode.setDeclaringClass(node);
-                    constructors.add(ctrNode);
+                    ConstructorNode newCtor = new ConstructorNode(ctor.getModifiers(), params, ctor.getExceptions(), code);
+                    newCtor.setDeclaringClass(node);
+                    constructors.add(newCtor);
                 }
 
                 @Override
@@ -399,8 +405,7 @@ public class JavaStubGenerator {
     private void printMethods(PrintWriter out, ClassNode classNode, boolean isEnum) {
         if (!isEnum) printConstructors(out, classNode);
 
-        @SuppressWarnings("unchecked")
-        List<MethodNode> methods = (List) propertyMethods.clone();
+        List<MethodNode> methods = new ArrayList<>(propertyMethods);
         methods.addAll(classNode.getMethods());
         for (MethodNode method : methods) {
             if (isEnum && method.isSynthetic()) {
@@ -527,16 +532,22 @@ public class JavaStubGenerator {
         out.print(fieldNode.getName());
         if (isInterface || fieldNode.isFinal()) {
             out.print(" = ");
-            Expression valueExpr = fieldNode.getInitialValueExpression();
-            if (valueExpr instanceof ConstantExpression) {
-                valueExpr = Verifier.transformToPrimitiveConstantIfPossible((ConstantExpression) valueExpr);
+            if (fieldNode.isStatic()) {
+                Expression value = fieldNode.getInitialValueExpression();
+                value = ExpressionUtils.transformInlineConstants(value, type);
+                if (value instanceof ConstantExpression) {
+                    value = Verifier.transformToPrimitiveConstantIfPossible((ConstantExpression) value);
+                    if ((type.equals(value.getType()) // GROOVY-10611: integer/decimal value
+                                || (isLongCategory(type) && isPrimitiveInt(value.getType()))
+                                || (isFloatingCategory(type) && isBigDecimalType(value.getType())))
+                            && (isPrimitiveBoolean(type) || isStaticConstantInitializerType(type))) {
+                        printValue(out, (ConstantExpression) value);
+                        out.println(';');
+                        return;
+                    }
+                }
             }
-            if (valueExpr instanceof ConstantExpression
-                    && fieldNode.isStatic() && fieldNode.isFinal()
-                    && fieldNode.getType().equals(valueExpr.getType())
-                    && (isStaticConstantInitializerType(valueExpr.getType()) || isPrimitiveBoolean(valueExpr.getType()))) {
-                printValue(out, (ConstantExpression) valueExpr);
-            } else if (isPrimitiveType(type)) {
+            if (isPrimitiveType(type)) {
                 if (isPrimitiveBoolean(type)) {
                     out.print("false");
                 } else {
@@ -826,7 +837,7 @@ public class JavaStubGenerator {
             out.print(ce.getText());
             out.print('L');
         } else {
-            if (!isPrimitiveInt(type) && !isPrimitiveBoolean(type)) {
+            if (!isPrimitiveInt(type) && !isPrimitiveBoolean(type) && !isBigDecimalType(type)) {
                 out.print('(');
                 printType(out, type);
                 out.print(')');
@@ -835,10 +846,10 @@ public class JavaStubGenerator {
         }
     }
 
-    private void printReturn(PrintWriter out, ClassNode retType) {
-        if (!isPrimitiveVoid(retType)) {
+    private void printReturn(final PrintWriter out, final ClassNode type) {
+        if (!isPrimitiveVoid(type)) {
             out.print("return ");
-            printDefaultValue(out, retType);
+            printDefaultValue(out, type);
             out.print(";");
         }
     }
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10611.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10611.groovy
new file mode 100644
index 0000000000..f2cca7f3f6
--- /dev/null
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10611.groovy
@@ -0,0 +1,50 @@
+/*
+ *  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 org.codehaus.groovy.tools.stubgenerator
+
+final class Groovy10611 extends StringSourcesStubTestCase {
+
+    @Override
+    Map<String, String> provideSources() {
+        [
+            'C.groovy': '''
+                class C {
+                    public static final long LONG = 123_456
+                    public static final float FLOAT = 78.90
+                    public static final String STRING = 'x'+'y'
+                }
+            ''',
+            'Main.java': '''
+                public class Main {
+                    public static void main(String[] args) {
+                        new C();
+                    }
+                }
+            ''',
+        ]
+    }
+
+    @Override
+    void verifyStubs() {
+        String stub = stubJavaSourceFor('C')
+        assert stub.contains('final long LONG = 123456;');
+        assert stub.contains('final float FLOAT = 78.90;');
+        assert stub.contains('final java.lang.String STRING = "xy";');
+    }
+}