| /* |
| * Copyright 2003-2007 the original author or authors. |
| * |
| * Licensed 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.ast; |
| |
| import groovy.lang.Closure; |
| import groovy.lang.GString; |
| import groovy.lang.MetaClass; |
| import groovy.lang.Range; |
| import groovy.lang.Reference; |
| import groovy.lang.Script; |
| |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.regex.Pattern; |
| |
| import org.codehaus.groovy.runtime.GeneratedClosure; |
| import org.objectweb.asm.Opcodes; |
| |
| /** |
| * This class is a Helper for ClassNode and classes handling ClassNodes. |
| * It does contain a set of predefined ClassNodes for the most used |
| * types and some code for cached ClassNode creation and basic |
| * ClassNode handling |
| * |
| * @author Jochen Theodorou |
| */ |
| public class ClassHelper { |
| |
| private static final Class[] classes = new Class[] { |
| Object.class, Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, |
| Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE, |
| Closure.class, GString.class, List.class, Map.class, Range.class, |
| Pattern.class, Script.class, String.class, Boolean.class, |
| Character.class, Byte.class, Short.class, Integer.class, Long.class, |
| Double.class, Float.class, BigDecimal.class, BigInteger.class, Void.class, |
| Reference.class, Class.class, MetaClass.class, |
| }; |
| |
| private static final String[] primitiveClassNames = new String[] { |
| "", "boolean", "char", "byte", "short", |
| "int", "long", "double", "float", "void" |
| }; |
| |
| public static final ClassNode |
| DYNAMIC_TYPE = new ClassNode(Object.class), OBJECT_TYPE = DYNAMIC_TYPE, |
| VOID_TYPE = new ClassNode(Void.TYPE), CLOSURE_TYPE = new ClassNode(Closure.class), |
| GSTRING_TYPE = new ClassNode(GString.class), LIST_TYPE = new ClassNode(List.class), |
| MAP_TYPE = new ClassNode(Map.class), RANGE_TYPE = new ClassNode(Range.class), |
| PATTERN_TYPE = new ClassNode(Pattern.class), STRING_TYPE = new ClassNode(String.class), |
| SCRIPT_TYPE = new ClassNode(Script.class), REFERENCE_TYPE = new ClassNode(Reference.class), |
| |
| boolean_TYPE = new ClassNode(boolean.class), char_TYPE = new ClassNode(char.class), |
| byte_TYPE = new ClassNode(byte.class), int_TYPE = new ClassNode(int.class), |
| long_TYPE = new ClassNode(long.class), short_TYPE = new ClassNode(short.class), |
| double_TYPE = new ClassNode(double.class), float_TYPE = new ClassNode(float.class), |
| Byte_TYPE = new ClassNode(Byte.class), Short_TYPE = new ClassNode(Short.class), |
| Integer_TYPE = new ClassNode(Integer.class), Long_TYPE = new ClassNode(Long.class), |
| Character_TYPE = new ClassNode(Character.class), Float_TYPE = new ClassNode(Float.class), |
| Double_TYPE = new ClassNode(Double.class), Boolean_TYPE = new ClassNode(Boolean.class), |
| BigInteger_TYPE = new ClassNode(java.math.BigInteger.class), |
| BigDecimal_TYPE = new ClassNode(java.math.BigDecimal.class), |
| void_WRAPPER_TYPE = new ClassNode(Void.class), |
| |
| CLASS_Type = new ClassNode(Class.class), METACLASS_TYPE = new ClassNode(MetaClass.class), |
| GENERATED_CLOSURE_Type = new ClassNode(GeneratedClosure.class), |
| Enum_Type = new ClassNode("java.lang.Enum",0,OBJECT_TYPE); |
| |
| static { |
| Enum_Type.isPrimaryNode = false; |
| } |
| |
| private static ClassNode[] types = new ClassNode[] { |
| OBJECT_TYPE, |
| boolean_TYPE, char_TYPE, byte_TYPE, short_TYPE, |
| int_TYPE, long_TYPE, double_TYPE, float_TYPE, |
| VOID_TYPE, CLOSURE_TYPE, GSTRING_TYPE, |
| LIST_TYPE, MAP_TYPE, RANGE_TYPE, PATTERN_TYPE, |
| SCRIPT_TYPE, STRING_TYPE, Boolean_TYPE, Character_TYPE, |
| Byte_TYPE, Short_TYPE, Integer_TYPE, Long_TYPE, |
| Double_TYPE, Float_TYPE, BigDecimal_TYPE, BigInteger_TYPE, |
| void_WRAPPER_TYPE, REFERENCE_TYPE, CLASS_Type, METACLASS_TYPE, |
| GENERATED_CLOSURE_Type, Enum_Type |
| }; |
| |
| |
| private static ClassNode[] numbers = new ClassNode[] { |
| char_TYPE, byte_TYPE, short_TYPE, int_TYPE, long_TYPE, |
| double_TYPE, float_TYPE, Short_TYPE, Byte_TYPE, Character_TYPE, |
| Integer_TYPE, Float_TYPE, Long_TYPE, Double_TYPE, BigInteger_TYPE, |
| BigDecimal_TYPE |
| }; |
| |
| protected static final ClassNode[] EMPTY_TYPE_ARRAY = {}; |
| |
| public static final String OBJECT = "java.lang.Object"; |
| |
| |
| /** |
| * Creates an array of ClassNodes using an array of classes. |
| * For each of the given classes a new ClassNode will be |
| * created |
| * @see #make(Class) |
| * @param classes an array of classes used to create the ClassNodes |
| * @return an array of ClassNodes |
| */ |
| public static ClassNode[] make(Class[] classes) { |
| ClassNode[] cns = new ClassNode[classes.length]; |
| for (int i=0; i<cns.length; i++) { |
| cns[i] = make(classes[i]); |
| } |
| |
| return cns; |
| } |
| |
| /** |
| * Creates a ClassNode using a given class. |
| * A new ClassNode object is only created if the class |
| * is not one of the predefined ones |
| * |
| * @param c class used to created the ClassNode |
| * @return ClassNode instance created from the given class |
| */ |
| public static ClassNode make(Class c) { |
| for (int i=0; i<classes.length; i++) { |
| if (c==classes[i]) return types[i]; |
| } |
| if (c.isArray()) { |
| ClassNode cn = make(c.getComponentType()); |
| return cn.makeArray(); |
| } |
| ClassNode t = new ClassNode(c); |
| return t; |
| } |
| |
| /** |
| * Creates a ClassNode using a given class. |
| * Unlike make(String) this method will not use the cache |
| * to create the ClassNode. This means the ClassNode created |
| * from this method using the same name will have a different |
| * references |
| * |
| * @see #make(String) |
| * @param name of the class the ClassNode is representing |
| */ |
| public static ClassNode makeWithoutCaching(String name) { |
| ClassNode cn = new ClassNode(name,Opcodes.ACC_PUBLIC,OBJECT_TYPE); |
| cn.isPrimaryNode = false; |
| return cn; |
| } |
| |
| /** |
| * Creates a ClassNode using a given class. |
| * If the name is one of the predefined ClassNodes then the |
| * corresponding ClassNode instance will be returned. If the |
| * is null of of length 0 the dynamic type is returned |
| * |
| * @param name of the class the ClassNode is representing |
| */ |
| public static ClassNode make(String name) { |
| if (name == null || name.length() == 0) return DYNAMIC_TYPE; |
| |
| for (int i=0; i<primitiveClassNames.length; i++) { |
| if (primitiveClassNames[i].equals(name)) return types[i]; |
| } |
| |
| for (int i=0; i<classes.length; i++) { |
| String cname = classes[i].getName(); |
| if (name.equals(cname)) return types[i]; |
| } |
| return makeWithoutCaching(name); |
| } |
| |
| /** |
| * Creates a ClassNode containing the wrapper of a ClassNode |
| * of primitive type. Any ClassNode representing a primitive |
| * type should be created using the predefined types used in |
| * class. The method will check the parameter for known |
| * references of ClassNode representing a primitive type. If |
| * Reference is found, then a ClassNode will be contained that |
| * represents the wrapper class. For exmaple for boolean, the |
| * wrapper class is java.lang.Boolean. |
| * |
| * If the parameter is no primitve type, the redirected |
| * ClassNode will be returned |
| * |
| * @see #make(Class) |
| * @see #make(String) |
| * @param cn the ClassNode containing a possible primitive type |
| */ |
| public static ClassNode getWrapper(ClassNode cn) { |
| cn = cn.redirect(); |
| if (!isPrimitiveType(cn)) return cn; |
| if (cn==boolean_TYPE) { |
| return Boolean_TYPE; |
| } else if (cn==byte_TYPE) { |
| return Byte_TYPE; |
| } else if (cn==char_TYPE) { |
| return Character_TYPE; |
| } else if (cn==short_TYPE) { |
| return Short_TYPE; |
| } else if (cn==int_TYPE) { |
| return Integer_TYPE; |
| } else if (cn==long_TYPE) { |
| return Long_TYPE; |
| } else if (cn==float_TYPE) { |
| return Float_TYPE; |
| } else if (cn==double_TYPE) { |
| return Double_TYPE; |
| } else if (cn==VOID_TYPE) { |
| return void_WRAPPER_TYPE; |
| } |
| else { |
| return cn; |
| } |
| } |
| |
| /** |
| * Test to determine if a ClasNode is a primitve type. |
| * Note: this only works for ClassNodes created using a |
| * predefined ClassNode |
| * |
| * @see #make(Class) |
| * @see #make(String) |
| * @param cn the ClassNode containing a possible primitive type |
| * @return true if the ClassNode is a primitve type |
| */ |
| public static boolean isPrimitiveType(ClassNode cn) { |
| return cn == boolean_TYPE || |
| cn == char_TYPE || |
| cn == byte_TYPE || |
| cn == short_TYPE || |
| cn == int_TYPE || |
| cn == long_TYPE || |
| cn == float_TYPE || |
| cn == double_TYPE || |
| cn == VOID_TYPE; |
| } |
| |
| public static ClassNode makeReference() { |
| return make(Reference.class); |
| } |
| |
| public static boolean isUnresolvedEnum(ClassNode node) { |
| if (Enum_Type.isResolved()) return false; |
| if (node.isResolved()) return false; |
| ClassNode superClass = node.getSuperClass(); |
| if (superClass==null) return false; |
| return superClass.redirect()==Enum_Type; |
| } |
| |
| } |