/* * 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.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; /** * Visitor to resolve constants in annotation definitions. * * @author Paul King */ 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; } @Override protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) { if (!inAnnotationDef) return; visitStatement(node.getFirstStatement(), node.getReturnType()); } 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)); } } 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; } 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 val; } private static Expression revertType(Expression val, ClassNode returnWrapperType) { ConstantExpression ce = (ConstantExpression) val; if (ClassHelper.Character_TYPE.equals(returnWrapperType) && ClassHelper.STRING_TYPE.equals(val.getType())) { return configure(val, Verifier.transformToPrimitiveConstantIfPossible((ConstantExpression) val)); } ClassNode valWrapperType = ClassHelper.getWrapper(val.getType()); if (ClassHelper.Integer_TYPE.equals(valWrapperType)) { Integer i = (Integer) ce.getValue(); if (ClassHelper.Character_TYPE.equals(returnWrapperType)) { return configure(val, new ConstantExpression((char) i.intValue(), true)); } if (ClassHelper.Short_TYPE.equals(returnWrapperType)) { return configure(val, new ConstantExpression(i.shortValue(), true)); } if (ClassHelper.Byte_TYPE.equals(returnWrapperType)) { return configure(val, new ConstantExpression(i.byteValue(), true)); } } if (ClassHelper.BigDecimal_TYPE.equals(valWrapperType)) { BigDecimal bd = (BigDecimal) ce.getValue(); if (ClassHelper.Float_TYPE.equals(returnWrapperType)) { return configure(val, new ConstantExpression(bd.floatValue(), true)); } if (ClassHelper.Double_TYPE.equals(returnWrapperType)) { return configure(val, new ConstantExpression(bd.doubleValue(), true)); } } return null; } private static Expression configure(Expression orig, Expression result) { result.setSourcePosition(orig); return result; } protected SourceUnit getSourceUnit() { return source; } }