This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY_2_5_X in repository https://gitbox.apache.org/repos/asf/groovy.git
commit e7d918f11e044c89096d73d4a6938203534662cf Author: Eric Milles <[email protected]> AuthorDate: Mon Mar 13 11:15:46 2023 -0500 GROOVY-10299, GROOVY-10611: stubgen: primitive or integer/decimal values 2_5_X backport --- .../groovy/tools/javac/JavaStubGenerator.java | 104 +++++++++++++-------- src/test/groovy/bugs/Groovy5260Bug.groovy | 91 +++++++++--------- .../AnnotationDefaultValuesStubTest.groovy | 6 +- .../groovy/tools/stubgenerator/Groovy10299.groovy | 46 +++++++++ .../groovy/tools/stubgenerator/Groovy10611.groovy | 50 ++++++++++ 5 files changed, 210 insertions(+), 87 deletions(-) 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 8a1a7d07b0..fbf1190678 100644 --- a/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java +++ b/src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java @@ -80,6 +80,8 @@ import java.util.Set; 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; @@ -451,24 +453,33 @@ public class JavaStubGenerator { out.print(field.getName()); if (interfaceOrTrait || field.isFinal()) { - // GROOVY-5150: initialize field with a value so Java compiles correctly out.print(" = "); - Expression valueExpr = field.getInitialValueExpression(); - if (valueExpr instanceof ConstantExpression && !type.equals(ClassHelper.STRING_TYPE)) { - valueExpr = Verifier.transformToPrimitiveConstantIfPossible((ConstantExpression) valueExpr); - } - ClassNode valueType; - if (field.isStatic() - && valueExpr instanceof ConstantExpression - && (valueType = valueExpr.getType()).equals(type) - && ClassHelper.isStaticConstantInitializerType(valueType)) { - if (ClassHelper.isNumberType(valueType)) { - out.print("(" + type.toString(false) + ") "); + if (field.isStatic() && field.hasInitialExpression()) { + Expression value = ExpressionUtils.transformInlineConstants(field.getInitialValueExpression(), type); + if (value instanceof ConstantExpression) { + if (ClassHelper.isPrimitiveType(type)) { // do not pass string of length 1 for String field: + value = Verifier.transformToPrimitiveConstantIfPossible((ConstantExpression) value); + } + if ((type.equals(value.getType()) // GROOVY-10611: integer/decimal value + || (isLongCategory(type) && value.getType().equals(ClassHelper.int_TYPE)) + || (isFloatingCategory(type) && ClassHelper.BigDecimal_TYPE.equals(value.getType()))) + && (type.equals(ClassHelper.boolean_TYPE) || ClassHelper.isStaticConstantInitializerType(type))) { + printValue(out, (ConstantExpression) value); + out.println(';'); + return; + } + } + + // GROOVY-5150, GROOVY-10902, GROOVY-10928: output dummy value + if (ClassHelper.isPrimitiveType(type) || type.equals(ClassHelper.STRING_TYPE)) { + out.print("new " + ClassHelper.getWrapper(type) + "("); + printDefaultValue(out, type); + out.print(')'); + } else { + out.print("null"); } - printValue(out, valueExpr, false); } else if (ClassHelper.isPrimitiveType(type)) { - String value = type.equals(ClassHelper.boolean_TYPE) ? "false" : "(" + type.toString(false) + ")0"; - out.print("new " + ClassHelper.getWrapper(type) + "(" + value + ")"); + printDefaultValue(out, type); } else { out.print("null"); } @@ -685,7 +696,8 @@ public class JavaStubGenerator { Expression re = es.getExpression(); out.print(" default "); ClassNode rt = methodNode.getReturnType(); - boolean classReturn = ClassHelper.CLASS_Type.equals(rt) || (rt.isArray() && ClassHelper.CLASS_Type.equals(rt.getComponentType())); + boolean classReturn = rt.equals(ClassHelper.CLASS_Type) + || (rt.isArray() && rt.getComponentType().equals(ClassHelper.CLASS_Type)); if (re instanceof ListExpression) { out.print("{ "); ListExpression le = (ListExpression) re; @@ -733,36 +745,50 @@ public class JavaStubGenerator { return Traits.isTrait(methodNode.getDeclaringClass()) && Traits.hasDefaultImplementation(methodNode); } - private static void printValue(PrintWriter out, Expression re, boolean assumeClass) { + private void printValue(final PrintWriter out, final Expression exp, final boolean assumeClass) { if (assumeClass) { - if (re.getType().getName().equals("groovy.lang.Closure")) { + if (exp.getType().getName().equals("groovy.lang.Closure")) { out.print("groovy.lang.Closure.class"); return; } - String className = re.getText(); + String className = exp.getText(); out.print(className); if (!className.endsWith(".class")) { out.print(".class"); } - } else if (re instanceof ConstantExpression) { - ConstantExpression ce = (ConstantExpression) re; - Object value = ce.getValue(); - if (ClassHelper.STRING_TYPE.equals(ce.getType())) { - out.print("\"" + escapeSpecialChars((String) value) + "\""); - } else if (ClassHelper.char_TYPE.equals(ce.getType()) - || ClassHelper.Character_TYPE.equals(ce.getType())) { - out.print("'" + escapeSpecialChars("" + value.toString().charAt(0)) + "'"); - } else if (ClassHelper.long_TYPE.equals(ce.getType())) { - out.print("" + value + "L"); - } else if (ClassHelper.float_TYPE.equals(ce.getType())) { - out.print("" + value + "f"); - } else if (ClassHelper.double_TYPE.equals(ce.getType())) { - out.print("" + value + "d"); - } else { - out.print(re.getText()); - } + } else if (exp instanceof ConstantExpression) { + printValue(out, (ConstantExpression) exp); + } else { + out.print(exp.getText()); + } + } + + private void printValue(final PrintWriter out, final ConstantExpression ce) { + ClassNode type = ClassHelper.getUnwrapper(ce.getType()); + if (type == ClassHelper.char_TYPE) { + out.print("'"); + out.print(escapeSpecialChars(ce.getText().substring(0, 1))); + out.print("'"); + } else if (type.equals(ClassHelper.STRING_TYPE)) { + out.print('"'); + out.print(escapeSpecialChars(ce.getText())); + out.print('"'); + } else if (type == ClassHelper.double_TYPE) { + out.print(ce.getText()); + out.print('d'); + } else if (type == ClassHelper.float_TYPE) { + out.print(ce.getText()); + out.print('f'); + } else if (type == ClassHelper.long_TYPE) { + out.print(ce.getText()); + out.print('L'); } else { - out.print(re.getText()); + if (type != ClassHelper.int_TYPE && type != ClassHelper.boolean_TYPE && !type.equals(ClassHelper.BigDecimal_TYPE)) { + out.print('('); + printType(out, type); + out.print(')'); + } + out.print(ce.getText()); } } @@ -776,9 +802,9 @@ public class JavaStubGenerator { private void printDefaultValue(final PrintWriter out, final ClassNode type) { if (type != null && !type.equals(ClassHelper.boolean_TYPE)) { - out.print("("); + out.print('('); printType(out, type); - out.print(")"); + out.print(')'); } if (type != null && ClassHelper.isPrimitiveType(type)) { if (type.equals(ClassHelper.boolean_TYPE)) { diff --git a/src/test/groovy/bugs/Groovy5260Bug.groovy b/src/test/groovy/bugs/Groovy5260Bug.groovy index 05be441129..d854ae1b20 100644 --- a/src/test/groovy/bugs/Groovy5260Bug.groovy +++ b/src/test/groovy/bugs/Groovy5260Bug.groovy @@ -18,22 +18,22 @@ */ package groovy.bugs +import org.codehaus.groovy.ast.ClassHelper import org.codehaus.groovy.ast.ClassNode import org.codehaus.groovy.ast.CompileUnit import org.codehaus.groovy.ast.ModuleNode import org.codehaus.groovy.tools.javac.JavaStubGenerator -import org.objectweb.asm.Opcodes -import org.codehaus.groovy.ast.ClassHelper -import org.codehaus.groovy.ast.FieldNode -import org.codehaus.groovy.ast.expr.ConstantExpression -class Groovy5260Bug extends GroovyTestCase implements Opcodes { - File outputDir - +import static org.codehaus.groovy.ast.tools.GeneralUtils.constX + +final class Groovy5260Bug extends GroovyTestCase implements org.objectweb.asm.Opcodes { + + private File outputDir + @Override protected void setUp() { super.setUp() - outputDir = File.createTempFile("stub","groovy") + outputDir = File.createTempFile('stub', 'groovy') outputDir.mkdirs() } @@ -43,77 +43,78 @@ class Groovy5260Bug extends GroovyTestCase implements Opcodes { outputDir.delete() } - private void checkConstant(ConstantExpression constant, String expectation) { - ClassNode cn = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE) - ModuleNode module = new ModuleNode(new CompileUnit(null,null)) - cn.setModule(module) - cn.addField(new FieldNode("constant", ACC_PUBLIC+ACC_STATIC+ACC_FINAL, constant.type, cn, constant)) - StringWriter wrt = new StringWriter() - PrintWriter out = new PrintWriter(wrt) - JavaStubGenerator generator = new StringJavaStubGenerator(outputDir, out) - generator.generateClass(cn) - - String stub = wrt.toString() - assert (stub =~ expectation) + void testIntConstant() { + checkConstant(ClassHelper.int_TYPE, 666, /final int constant = 666;/) } void testLongConstant() { - def constant = new ConstantExpression(666, true) - constant.type = ClassHelper.long_TYPE - checkConstant(constant, /\(long\) 666L/) + checkConstant(ClassHelper.long_TYPE, 666, 'final long constant = 666L;') } - void testIntConstant() { - def constant = new ConstantExpression(666, true) - constant.type = ClassHelper.int_TYPE - checkConstant(constant, /\(int\) 666/) + void testFloatConstant() { + checkConstant(ClassHelper.float_TYPE, 3.14f, 'final float constant = 3.14f;') } void testByteConstant() { - def constant = new ConstantExpression(123, true) - constant.type = ClassHelper.byte_TYPE - checkConstant(constant, /\(byte\) 123/) + checkConstant(ClassHelper.byte_TYPE, 123, /final byte constant = \(byte\)123;/) } - void testBooleanConstant() { - def constant = new ConstantExpression(false, true) - constant.type = ClassHelper.boolean_TYPE - // boolean type is not optimized yet - checkConstant(constant, /new java.lang.Boolean\(false\)/) + void testCharConstant() { + checkConstant(ClassHelper.char_TYPE, 'c', 'final char constant = \'c\';') } void testStringConstant() { - def constant = new ConstantExpression('foo', true) - constant.type = ClassHelper.STRING_TYPE - checkConstant(constant, /"foo"/) + checkConstant(ClassHelper.STRING_TYPE, 'foo', 'final java.lang.String constant = "foo";') + } + + void testBooleanConstant() { + checkConstant(ClassHelper.boolean_TYPE, true, 'final boolean constant = true;') + } + + //-------------------------------------------------------------------------- + + private void checkConstant(ClassNode type, Object value, String expectation) { + def constant = constX(value, true) + constant.type = type + + ClassNode cn = new ClassNode('script', ACC_PUBLIC, ClassHelper.OBJECT_TYPE) + cn.addField('constant', ACC_PUBLIC | ACC_STATIC | ACC_FINAL, constant.type, constant) + ModuleNode module = new ModuleNode(new CompileUnit(null, null)) + cn.setModule(module) + + StringWriter wrt = new StringWriter() + PrintWriter out = new PrintWriter(wrt) + JavaStubGenerator generator = new StringJavaStubGenerator(outputDir, out) + generator.generateClass(cn) + + String stub = wrt.toString() + assert (stub =~ expectation) } /** * Helper class, which generates code in a string instead of an output file. */ private static final class StringJavaStubGenerator extends JavaStubGenerator { + PrintWriter out + StringJavaStubGenerator(File outFile, PrintWriter out) { super(outFile) this.out = out } - public void generateClass(ClassNode classNode) throws FileNotFoundException { - + public void generateClass(ClassNode classNode) throws FileNotFoundException { try { String packageName = classNode.getPackageName(); if (packageName != null) { out.println("package " + packageName + ";\n"); } - super.printImports(out, classNode); super.printClassContents(out, classNode); - } finally { try { - out.close(); - } catch (Exception e) { - // ignore + out.close() + } catch (ignore) { } } } diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/AnnotationDefaultValuesStubTest.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/AnnotationDefaultValuesStubTest.groovy index d4d038cff0..6b34a22c7e 100644 --- a/src/test/org/codehaus/groovy/tools/stubgenerator/AnnotationDefaultValuesStubTest.groovy +++ b/src/test/org/codehaus/groovy/tools/stubgenerator/AnnotationDefaultValuesStubTest.groovy @@ -21,7 +21,7 @@ package org.codehaus.groovy.tools.stubgenerator /** * Checks that default values from annotation definitions appear within stubs. */ -class AnnotationDefaultValuesStubTest extends StringSourcesStubTestCase { +final class AnnotationDefaultValuesStubTest extends StringSourcesStubTestCase { Map<String, String> provideSources() { [ @@ -73,8 +73,8 @@ class AnnotationDefaultValuesStubTest extends StringSourcesStubTestCase { assert stubSource.contains('float f() default 3.0f;') assert stubSource.contains('double d() default 3.0d;') assert stubSource.contains('long l() default 3L;') - assert stubSource.contains('byte me() default 3;') - assert stubSource.contains('short s() default 3;') + assert stubSource.contains('byte me() default (byte)3;') + assert stubSource.contains('short s() default (short)3;') assert stubSource.contains("char c1() default 'A';") assert stubSource.contains("char c2() default 'A';") assert stubSource.contains("char c3() default 'A';") diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10299.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10299.groovy new file mode 100644 index 0000000000..991936477d --- /dev/null +++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10299.groovy @@ -0,0 +1,46 @@ +/* + * 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 Groovy10299 extends StringSourcesStubTestCase { + + @Override + Map<String, String> provideSources() { + [ + 'Pogo.groovy': ''' + class Pogo { + public final boolean must_init + } + ''', + 'Main.java': ''' + public class Main { + public static void main(String[] args) { + new Pogo(); + } + } + ''', + ] + } + + @Override + void verifyStubs() { + String stub = stubJavaSourceFor('Pogo') + assert stub.contains('final boolean must_init = false;') + } +} 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";'); + } +}
