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/07/06 22:50:52 UTC
[groovy] 01/02: GROOVY-6025, GROOVY-7252, GROOVY-9206, GROOVY-9366: attribute value type
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
commit 5fe6fbc7dfef4df52fff6cf96a95b6d46d4fbf3c
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Jul 6 17:12:19 2022 -0500
GROOVY-6025, GROOVY-7252, GROOVY-9206, GROOVY-9366: attribute value type
---
.../apache/groovy/ast/tools/ExpressionUtils.java | 72 ++++++++---
.../groovy/classgen/AnnotationVisitor.java | 140 ++++++++++-----------
.../groovy/control/AnnotationConstantsVisitor.java | 80 +-----------
src/test/gls/annotations/AnnotationTest.groovy | 57 ++++++++-
.../groovy/tools/stubgenerator/Groovy10611.groovy | 2 +-
5 files changed, 174 insertions(+), 177 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 aaf4d3e7a0..f43646e485 100644
--- a/src/main/java/org/apache/groovy/ast/tools/ExpressionUtils.java
+++ b/src/main/java/org/apache/groovy/ast/tools/ExpressionUtils.java
@@ -22,6 +22,7 @@ import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.Expression;
@@ -33,17 +34,11 @@ import org.codehaus.groovy.runtime.typehandling.NumberMath;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperByte;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperCharacter;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperDouble;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperFloat;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperInteger;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperLong;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperShort;
import static org.codehaus.groovy.syntax.Types.BITWISE_AND;
import static org.codehaus.groovy.syntax.Types.BITWISE_OR;
import static org.codehaus.groovy.syntax.Types.BITWISE_XOR;
@@ -55,6 +50,7 @@ import static org.codehaus.groovy.syntax.Types.PLUS;
import static org.codehaus.groovy.syntax.Types.POWER;
import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT;
import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_UNSIGNED;
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor.inferLoopElementType;
public final class ExpressionUtils {
@@ -181,24 +177,27 @@ public final class ExpressionUtils {
break;
}
if (result != null) {
- if (isWrapperByte(wrapperType)) {
- return configure(be, new ConstantExpression(result.byteValue(), true));
+ if (ClassHelper.isWrapperInteger(wrapperType)) {
+ return configure(be, new ConstantExpression(result.intValue(), true));
}
- if (isWrapperShort(wrapperType)) {
- return configure(be, new ConstantExpression(result.shortValue(), true));
+ if (ClassHelper.isWrapperByte(wrapperType)) {
+ return configure(be, new ConstantExpression(result.byteValue(), true));
}
- if (isWrapperLong(wrapperType)) {
+ if (ClassHelper.isWrapperLong(wrapperType)) {
return configure(be, new ConstantExpression(result.longValue(), true));
}
- if (isWrapperInteger(wrapperType) || isWrapperCharacter(wrapperType)) {
- return configure(be, new ConstantExpression(result.intValue(), true));
+ if (ClassHelper.isWrapperShort(wrapperType)) {
+ return configure(be, new ConstantExpression(result.shortValue(), true));
}
- if (isWrapperFloat(wrapperType)) {
+ if (ClassHelper.isWrapperFloat(wrapperType)) {
return configure(be, new ConstantExpression(result.floatValue(), true));
}
- if (isWrapperDouble(wrapperType)) {
+ if (ClassHelper.isWrapperDouble(wrapperType)) {
return configure(be, new ConstantExpression(result.doubleValue(), true));
}
+ if (ClassHelper.isWrapperCharacter(wrapperType)) {
+ return configure(be, new ConstantExpression((char) result.intValue(), true));
+ }
return configure(be, new ConstantExpression(result, true));
}
}
@@ -266,9 +265,10 @@ public final class ExpressionUtils {
* Handles:
* <ul>
* <li>Property expressions - referencing constants</li>
- * <li>Simple binary expressions - String concatenation and numeric +, -, /, *</li>
- * <li>List expressions - list of constants</li>
* <li>Variable expressions - referencing constants</li>
+ * <li>Typecast expressions - referencing constants</li>
+ * <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
@@ -311,6 +311,39 @@ public final class ExpressionUtils {
}
}
}
+ } else if (exp instanceof ConstantExpression) {
+ Object value = ((ConstantExpression) exp).getValue();
+ ClassNode targetType = ClassHelper.getWrapper(attrType);
+ if (value instanceof Integer) {
+ Integer integer = (Integer) value;
+ if (ClassHelper.isWrapperByte(targetType)) {
+ return configure(exp, new ConstantExpression(integer.byteValue(), true));
+ }
+ if (ClassHelper.isWrapperShort(targetType)) {
+ return configure(exp, new ConstantExpression(integer.shortValue(), true));
+ }
+ if (ClassHelper.isWrapperCharacter(targetType)) {
+ return configure(exp, new ConstantExpression((char) integer.intValue(), true));
+ }
+ } else if (value instanceof BigDecimal) {
+ BigDecimal decimal = (BigDecimal) value;
+ if (ClassHelper.isWrapperFloat(targetType)) {
+ return configure(exp, new ConstantExpression(decimal.floatValue(), true));
+ }
+ if (ClassHelper.isWrapperDouble(targetType)) {
+ return configure(exp, new ConstantExpression(decimal.doubleValue(), true));
+ }
+ } else if (value instanceof String) {
+ String string = (String) value;
+ if (ClassHelper.isWrapperCharacter(targetType) && string.length() == 1) {
+ return configure(exp, new ConstantExpression(string.charAt(0), true));
+ }
+ }
+ } else if (exp instanceof CastExpression) {
+ Expression e = transformInlineConstants(((CastExpression) exp).getExpression(), exp.getType());
+ if (ClassHelper.getWrapper(e.getType()).isDerivedFrom(ClassHelper.getWrapper(attrType))) {
+ return e;
+ }
} else if (exp instanceof BinaryExpression) {
ConstantExpression ce = transformBinaryConstantExpression((BinaryExpression) exp, attrType);
if (ce != null) {
@@ -329,8 +362,9 @@ public final class ExpressionUtils {
* @param attrType the target type
* @return the transformed list or the original if nothing was changed
*/
- public static Expression transformListOfConstants(final ListExpression origList, final ClassNode attrType) {
+ public static Expression transformListOfConstants(final ListExpression origList, ClassNode attrType) {
ListExpression newList = new ListExpression();
+ attrType = inferLoopElementType(attrType);
boolean changed = false;
for (Expression e : origList.getExpressions()) {
try {
diff --git a/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java b/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java
index de0d332dcb..875c588587 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java
@@ -35,16 +35,12 @@ import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.control.ErrorCollector;
import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
-import org.codehaus.groovy.syntax.SyntaxException;
import org.codehaus.groovy.vmplugin.VMPluginFactory;
import java.util.List;
import java.util.Map;
import static org.apache.groovy.ast.tools.ExpressionUtils.transformInlineConstants;
-import static org.codehaus.groovy.ast.ClassHelper.isClassType;
-import static org.codehaus.groovy.ast.ClassHelper.isStringType;
/**
* An Annotation visitor responsible for:
@@ -55,23 +51,25 @@ import static org.codehaus.groovy.ast.ClassHelper.isStringType;
* </ul>
*/
public class AnnotationVisitor {
+
private final SourceUnit source;
private final ErrorCollector errorCollector;
+
private AnnotationNode annotation;
private ClassNode reportClass;
- public AnnotationVisitor(SourceUnit source, ErrorCollector errorCollector) {
+ public AnnotationVisitor(final SourceUnit source, final ErrorCollector errorCollector) {
this.source = source;
this.errorCollector = errorCollector;
}
- public void setReportClass(ClassNode cn) {
- reportClass = cn;
+ public void setReportClass(final ClassNode node) {
+ this.reportClass = node;
}
- public AnnotationNode visit(AnnotationNode node) {
+ public AnnotationNode visit(final AnnotationNode node) {
this.annotation = node;
- this.reportClass = node.getClassNode();
+ setReportClass(node.getClassNode());
if (!isValidAnnotationClass(node.getClassNode())) {
addError("class " + node.getClassNode().getName() + " is not an annotation");
@@ -88,8 +86,7 @@ public class AnnotationVisitor {
return node;
}
- Map<String, Expression> attributes = node.getMembers();
- for (Map.Entry<String, Expression> entry : attributes.entrySet()) {
+ for (Map.Entry<String, Expression> entry : node.getMembers().entrySet()) {
String attrName = entry.getKey();
ClassNode attrType = getAttributeType(node, attrName);
Expression attrExpr = transformInlineConstants(entry.getValue(), attrType);
@@ -100,7 +97,7 @@ public class AnnotationVisitor {
return this.annotation;
}
- private boolean checkIfValidEnumConstsAreUsed(AnnotationNode node) {
+ private boolean checkIfValidEnumConstsAreUsed(final AnnotationNode node) {
Map<String, Expression> attributes = node.getMembers();
for (Map.Entry<String, Expression> entry : attributes.entrySet()) {
if (!validateEnumConstant(entry.getValue()))
@@ -109,7 +106,7 @@ public class AnnotationVisitor {
return true;
}
- private boolean validateEnumConstant(Expression exp) {
+ private boolean validateEnumConstant(final Expression exp) {
if (exp instanceof PropertyExpression) {
PropertyExpression pe = (PropertyExpression) exp;
String name = pe.getPropertyAsString();
@@ -134,14 +131,13 @@ public class AnnotationVisitor {
return true;
}
- private boolean checkIfMandatoryAnnotationValuesPassed(AnnotationNode node) {
+ private boolean checkIfMandatoryAnnotationValuesPassed(final AnnotationNode node) {
boolean ok = true;
- Map attributes = node.getMembers();
ClassNode classNode = node.getClassNode();
for (MethodNode mn : classNode.getMethods()) {
String methodName = mn.getName();
// if the annotation attribute has a default, getCode() returns a ReturnStatement with the default value
- if (mn.getCode() == null && !attributes.containsKey(methodName)) {
+ if (mn.getCode() == null && !node.getMembers().containsKey(methodName)) {
addError("No explicit/default value found for annotation attribute '" + methodName + "'", node);
ok = false;
}
@@ -149,74 +145,71 @@ public class AnnotationVisitor {
return ok;
}
- private ClassNode getAttributeType(AnnotationNode node, String attrName) {
+ private ClassNode getAttributeType(final AnnotationNode node, final String attrName) {
ClassNode classNode = node.getClassNode();
- List methods = classNode.getMethods(attrName);
+ List<MethodNode> methods = classNode.getMethods(attrName);
// if size is >1, then the method was overwritten or something, we ignore that
// if it is an error, we have to test it at another place. But size==0 is
// an error, because it means that no such attribute exists.
if (methods.isEmpty()) {
- addError("'" + attrName + "'is not part of the annotation " + classNode.getNameWithoutPackage(), node);
+ addError("'" + attrName + "' is not part of the annotation " + classNode.getNameWithoutPackage(), node);
return ClassHelper.OBJECT_TYPE;
}
- MethodNode method = (MethodNode) methods.get(0);
- return method.getReturnType();
+ return methods.get(0).getReturnType();
}
- private static boolean isValidAnnotationClass(ClassNode node) {
- return node.implementsInterface(ClassHelper.Annotation_TYPE);
+ private static boolean isValidAnnotationClass(final ClassNode type) {
+ return type.implementsInterface(ClassHelper.Annotation_TYPE);
}
- protected void visitExpression(String attrName, Expression attrExp, ClassNode attrType) {
+ protected void visitExpression(final String attrName, final Expression valueExpr, final ClassNode attrType) {
if (attrType.isArray()) {
// check needed as @Test(attr = {"elem"}) passes through the parser
- if (attrExp instanceof ListExpression) {
- ListExpression le = (ListExpression) attrExp;
+ if (valueExpr instanceof ListExpression) {
+ ListExpression le = (ListExpression) valueExpr;
visitListExpression(attrName, le, attrType.getComponentType());
- } else if (attrExp instanceof ClosureExpression) {
- addError("Annotation list attributes must use Groovy notation [el1, el2]", attrExp);
+ } else if (valueExpr instanceof ClosureExpression) {
+ addError("Annotation list attributes must use Groovy notation [el1, el2]", valueExpr);
} else {
// treat like a singleton list as per Java
ListExpression listExp = new ListExpression();
- listExp.addExpression(attrExp);
+ listExp.addExpression(valueExpr);
if (annotation != null) {
annotation.setMember(attrName, listExp);
}
visitExpression(attrName, listExp, attrType);
}
- } else if (ClassHelper.isPrimitiveType(attrType)) {
- visitConstantExpression(attrName, getConstantExpression(attrExp, attrType), ClassHelper.getWrapper(attrType));
- } else if (isStringType(attrType)) {
- visitConstantExpression(attrName, getConstantExpression(attrExp, attrType), ClassHelper.STRING_TYPE);
- } else if (isClassType(attrType)) {
- if (!(attrExp instanceof ClassExpression || attrExp instanceof ClosureExpression)) {
- addError("Only classes and closures can be used for attribute '" + attrName + "'", attrExp);
+ } else if (ClassHelper.isPrimitiveType(attrType) || ClassHelper.isStringType(attrType)) {
+ visitConstantExpression(attrName, getConstantExpression(valueExpr, attrType), ClassHelper.getWrapper(attrType));
+ } else if (ClassHelper.isClassType(attrType)) {
+ if (!(valueExpr instanceof ClassExpression || valueExpr instanceof ClosureExpression)) {
+ addError("Only classes and closures can be used for attribute '" + attrName + "'", valueExpr);
}
} else if (attrType.isDerivedFrom(ClassHelper.Enum_Type)) {
- if (attrExp instanceof PropertyExpression) {
- visitEnumExpression(attrName, (PropertyExpression) attrExp, attrType);
- } else if (attrExp instanceof ConstantExpression) {
- visitConstantExpression(attrName, getConstantExpression(attrExp, attrType), attrType);
+ if (valueExpr instanceof PropertyExpression) {
+ visitEnumExpression(attrName, (PropertyExpression) valueExpr, attrType);
+ } else if (valueExpr instanceof ConstantExpression) {
+ visitConstantExpression(attrName, getConstantExpression(valueExpr, attrType), attrType);
} else {
- addError("Expected enum value for attribute " + attrName, attrExp);
+ addError("Expected enum value for attribute " + attrName, valueExpr);
}
} else if (isValidAnnotationClass(attrType)) {
- if (attrExp instanceof AnnotationConstantExpression) {
- visitAnnotationExpression(attrName, (AnnotationConstantExpression) attrExp, attrType);
+ if (valueExpr instanceof AnnotationConstantExpression) {
+ visitAnnotationExpression(attrName, (AnnotationConstantExpression) valueExpr, attrType);
} else {
- addError("Expected annotation of type '" + attrType.getName() + "' for attribute " + attrName, attrExp);
+ addError("Expected annotation of type '" + attrType.getName() + "' for attribute " + attrName, valueExpr);
}
} else {
- addError("Unexpected type " + attrType.getName(), attrExp);
+ addError("Unexpected type " + attrType.getName(), valueExpr);
}
}
- public void checkReturnType(ClassNode attrType, ASTNode node) {
+ public void checkReturnType(final ClassNode attrType, final ASTNode node) {
if (attrType.isArray()) {
checkReturnType(attrType.getComponentType(), node);
} else if (ClassHelper.isPrimitiveType(attrType)) {
- } else if (isStringType(attrType)) {
- } else if (isClassType(attrType)) {
+ } else if (ClassHelper.isStringType(attrType)) {
+ } else if (ClassHelper.isClassType(attrType)) {
} else if (attrType.isDerivedFrom(ClassHelper.Enum_Type)) {
} else if (isValidAnnotationClass(attrType)) {
} else {
@@ -224,7 +217,7 @@ public class AnnotationVisitor {
}
}
- private ConstantExpression getConstantExpression(Expression exp, ClassNode attrType) {
+ private ConstantExpression getConstantExpression(final Expression exp, final ClassNode attrType) {
Expression result = exp;
if (!(result instanceof ConstantExpression)) {
result = transformInlineConstants(result, attrType);
@@ -232,6 +225,7 @@ public class AnnotationVisitor {
if (result instanceof ConstantExpression) {
return (ConstantExpression) result;
}
+
String base = "Expected '" + exp.getText() + "' to be an inline constant of type " + attrType.getName();
if (exp instanceof PropertyExpression) {
addError(base + " not a property expression", exp);
@@ -240,56 +234,48 @@ public class AnnotationVisitor {
} else {
addError(base, exp);
}
+
ConstantExpression ret = new ConstantExpression(null);
ret.setSourcePosition(exp);
return ret;
}
- protected void visitAnnotationExpression(String attrName, AnnotationConstantExpression expression, ClassNode attrType) {
- AnnotationNode annotationNode = (AnnotationNode) expression.getValue();
- AnnotationVisitor visitor = new AnnotationVisitor(this.source, this.errorCollector);
- // TODO track Deprecated usage and give a warning?
- visitor.visit(annotationNode);
- }
-
- protected void visitListExpression(String attrName, ListExpression listExpr, ClassNode elementType) {
+ protected void visitListExpression(final String attrName, final ListExpression listExpr, final ClassNode elementType) {
for (Expression expression : listExpr.getExpressions()) {
visitExpression(attrName, expression, elementType);
}
}
- protected void visitConstantExpression(String attrName, ConstantExpression constExpr, ClassNode attrType) {
- ClassNode constType = constExpr.getType();
- ClassNode wrapperType = ClassHelper.getWrapper(constType);
- if (!hasCompatibleType(attrType, wrapperType)) {
- addError("Attribute '" + attrName + "' should have type '" + attrType.getName()
- + "'; but found type '" + constType.getName() + "'", constExpr);
+ protected void visitEnumExpression(final String attrName, final PropertyExpression valueExpr, final ClassNode attrType) {
+ ClassNode valueType = valueExpr.getObjectExpression().getType();
+ if (!valueType.isDerivedFrom(attrType)) {
+ addError("Attribute '" + attrName + "' should have type '" + attrType.getName() + "' (Enum), but found " + valueType.getName(), valueExpr);
}
}
- private static boolean hasCompatibleType(ClassNode attrType, ClassNode wrapperType) {
- return wrapperType.isDerivedFrom(ClassHelper.getWrapper(attrType));
+ protected void visitConstantExpression(final String attrName, final ConstantExpression valueExpr, final ClassNode attrType) {
+ ClassNode valueType = valueExpr.getType();
+ if (!ClassHelper.getWrapper(valueType).isDerivedFrom(ClassHelper.getWrapper(attrType))) {
+ addError("Attribute '" + attrName + "' should have type '" + attrType.getName() + "'; but found type '" + valueType.getName() + "'", valueExpr);
+ }
}
- protected void visitEnumExpression(String attrName, PropertyExpression propExpr, ClassNode attrType) {
- if (!propExpr.getObjectExpression().getType().isDerivedFrom(attrType)) {
- addError("Attribute '" + attrName + "' should have type '" + attrType.getName() + "' (Enum), but found "
- + propExpr.getObjectExpression().getType().getName(),
- propExpr);
- }
+ protected void visitAnnotationExpression(final String attrName, final AnnotationConstantExpression valueExpr, final ClassNode attrType) {
+ AnnotationNode annotationNode = (AnnotationNode) valueExpr.getValue();
+ AnnotationVisitor visitor = new AnnotationVisitor(this.source, this.errorCollector);
+ // TODO: Track @Deprecated usage and give a warning?
+ visitor.visit(annotationNode);
}
- protected void addError(String msg) {
+ protected void addError(final String msg) {
addError(msg, this.annotation);
}
- protected void addError(String msg, ASTNode expr) {
- this.errorCollector.addErrorAndContinue(
- new SyntaxErrorMessage(new SyntaxException(msg + " in @" + this.reportClass.getName() + '\n', expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), this.source)
- );
+ protected void addError(final String msg, final ASTNode node) {
+ this.errorCollector.addErrorAndContinue(msg + " in @" + this.reportClass.getName() + '\n', node, this.source);
}
- public void checkCircularReference(ClassNode searchClass, ClassNode attrType, Expression startExp) {
+ public void checkCircularReference(final ClassNode searchClass, final ClassNode attrType, final Expression startExp) {
if (!isValidAnnotationClass(attrType)) return;
if (!(startExp instanceof AnnotationConstantExpression)) {
addError("Found '" + startExp.getText() + "' when expecting an Annotation Constant", startExp);
diff --git a/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java b/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
index 7de3e635a5..bb1760ac67 100644
--- a/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
@@ -19,28 +19,13 @@
package org.codehaus.groovy.control;
import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
-import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.MethodNode;
-import org.codehaus.groovy.ast.expr.CastExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.ast.stmt.Statement;
-import org.codehaus.groovy.classgen.Verifier;
-
-import java.math.BigDecimal;
import static org.apache.groovy.ast.tools.ExpressionUtils.transformInlineConstants;
-import static org.codehaus.groovy.ast.ClassHelper.isBigDecimalType;
-import static org.codehaus.groovy.ast.ClassHelper.isStringType;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperByte;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperCharacter;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperDouble;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperFloat;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperInteger;
-import static org.codehaus.groovy.ast.ClassHelper.isWrapperShort;
/**
* Resolves constants in annotation definitions.
@@ -68,72 +53,11 @@ public class AnnotationConstantsVisitor extends ClassCodeVisitorSupport {
Statement statement = node.getFirstStatement();
if (statement instanceof ReturnStatement) {
ReturnStatement rs = (ReturnStatement) statement;
- rs.setExpression(transformConstantExpression(rs.getExpression(), node.getReturnType()));
+ rs.setExpression(transformInlineConstants(rs.getExpression(), node.getReturnType()));
} else if (statement instanceof ExpressionStatement) {
ExpressionStatement es = (ExpressionStatement) statement;
- es.setExpression(transformConstantExpression(es.getExpression(), node.getReturnType()));
- }
- }
- }
-
- private static Expression transformConstantExpression(Expression val, ClassNode returnType) {
- ClassNode returnWrapperType = ClassHelper.getWrapper(returnType);
- if (val instanceof ConstantExpression) {
- Expression result = revertType(val, returnWrapperType);
- if (result != null) {
- return result;
+ es.setExpression(transformInlineConstants(es.getExpression(), node.getReturnType()));
}
- return val;
- }
- if (val instanceof CastExpression) {
- CastExpression castExp = (CastExpression) val;
- Expression castee = castExp.getExpression();
- if (castee instanceof ConstantExpression) {
- if (ClassHelper.getWrapper(castee.getType()).isDerivedFrom(returnWrapperType)) {
- return castee;
- }
- Expression result = revertType(castee, returnWrapperType);
- if (result != null) {
- return result;
- }
- return castee;
- }
- }
- return transformInlineConstants(val, returnType);
- }
-
- private static Expression revertType(Expression val, ClassNode returnWrapperType) {
- ConstantExpression ce = (ConstantExpression) val;
- if (isWrapperCharacter(returnWrapperType) && isStringType(val.getType())) {
- return configure(val, Verifier.transformToPrimitiveConstantIfPossible((ConstantExpression) val));
}
- ClassNode valWrapperType = ClassHelper.getWrapper(val.getType());
- if (isWrapperInteger(valWrapperType)) {
- Integer i = (Integer) ce.getValue();
- if (isWrapperCharacter(returnWrapperType)) {
- return configure(val, new ConstantExpression((char) i.intValue(), true));
- }
- if (isWrapperShort(returnWrapperType)) {
- return configure(val, new ConstantExpression(i.shortValue(), true));
- }
- if (isWrapperByte(returnWrapperType)) {
- return configure(val, new ConstantExpression(i.byteValue(), true));
- }
- }
- if (isBigDecimalType(valWrapperType)) {
- BigDecimal bd = (BigDecimal) ce.getValue();
- if (isWrapperFloat(returnWrapperType)) {
- return configure(val, new ConstantExpression(bd.floatValue(), true));
- }
- if (isWrapperDouble(returnWrapperType)) {
- return configure(val, new ConstantExpression(bd.doubleValue(), true));
- }
- }
- return null;
- }
-
- private static Expression configure(Expression orig, Expression result) {
- result.setSourcePosition(orig);
- return result;
}
}
diff --git a/src/test/gls/annotations/AnnotationTest.groovy b/src/test/gls/annotations/AnnotationTest.groovy
index 291ec12af9..c59279a46c 100644
--- a/src/test/gls/annotations/AnnotationTest.groovy
+++ b/src/test/gls/annotations/AnnotationTest.groovy
@@ -18,6 +18,7 @@
*/
package gls.annotations
+import groovy.test.NotYetImplemented
import org.junit.Test
import static groovy.test.GroovyAssert.assertScript
@@ -619,6 +620,42 @@ final class AnnotationTest {
'''
}
+ @Test // GROOVY-7252
+ void testAttributeValueConstants7() {
+ assertScript shell, '''
+ @interface A {
+ short value()
+ }
+
+ @A(12345)
+ def local
+ '''
+ }
+
+ @Test // GROOVY-9366
+ void testAttributeValueConstants8() {
+ assertScript shell, '''
+ @interface A {
+ byte value()
+ }
+
+ @A(0xFF)
+ def local
+ '''
+ }
+
+ @Test // GROOVY-9206
+ void testAttributeValueConstants9() {
+ assertScript shell, '''
+ @interface A {
+ char value()
+ }
+
+ @A( 'c' )
+ def local
+ '''
+ }
+
@Test
void testRuntimeRetentionAtAllLevels() {
assertScript shell, '''
@@ -748,9 +785,9 @@ final class AnnotationTest {
int i1() default 0
int i2() default (int)1
short s1() default 2
- short s2() default (byte)3
+ short s2() default (short)3
short s3() default (Short)4
- short s4() default (int)5
+ short s4() default 5 as short
byte b() default 6
char c1() default 65
char c2() default 'B'
@@ -765,6 +802,7 @@ final class AnnotationTest {
double d3() default (double)2.2
double d4() default 2.3 as double
}
+
@Foo method() {}
def string = getClass().getMethod('method').getAnnotation(Foo).toString()[5..-2].tokenize(', ').sort().join('|')
assert string == 'b=6|c1=A|c2=B|c3=C|c4=D|d1=2.0|d2=2.1|d3=2.2|d4=2.3|f1=1.0|f2=1.1|f3=1.2|f4=1.3|i1=0|i2=1|s1=2|s2=3|s3=4|s4=5' ||
@@ -775,6 +813,21 @@ final class AnnotationTest {
'''
}
+ @NotYetImplemented @Test // GROOVY-6025
+ void testAnnotationDefinitionDefaultValues2() {
+ assertScript shell, '''
+ @interface A {
+ short s1() default (byte)1
+ short s2() default (char)2
+ short s3() default (long)3
+ }
+
+ assert A.getMethod('s1').defaultValue == 1
+ assert A.getMethod('s2').defaultValue == 2
+ assert A.getMethod('s3').defaultValue == 3
+ '''
+ }
+
@Test // GROOVY-6093
void testAnnotationOnEnumConstant() {
assertScript shell, '''
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10611.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10611.groovy
index f2cca7f3f6..824f338751 100644
--- a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10611.groovy
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy10611.groovy
@@ -44,7 +44,7 @@ final class Groovy10611 extends StringSourcesStubTestCase {
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 float FLOAT = 78.9f;');
assert stub.contains('final java.lang.String STRING = "xy";');
}
}