001 /* 002 $Id: ClassHelper.java 4215 2006-11-13 11:18:35Z blackdrag $ created on 25.10.2005 003 004 Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved. 005 006 Redistribution and use of this software and associated documentation 007 ("Software"), with or without modification, are permitted provided 008 that the following conditions are met: 009 010 1. Redistributions of source code must retain copyright 011 statements and notices. Redistributions must also contain a 012 copy of this document. 013 014 2. Redistributions in binary form must reproduce the 015 above copyright notice, this list of conditions and the 016 following disclaimer in the documentation and/or other 017 materials provided with the distribution. 018 019 3. The name "groovy" must not be used to endorse or promote 020 products derived from this Software without prior written 021 permission of The Codehaus. For written permission, 022 please contact info@codehaus.org. 023 024 4. Products derived from this Software may not be called "groovy" 025 nor may "groovy" appear in their names without prior written 026 permission of The Codehaus. "groovy" is a registered 027 trademark of The Codehaus. 028 029 5. Due credit should be given to The Codehaus - 030 http://groovy.codehaus.org/ 031 032 THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS 033 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 034 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 035 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 036 THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 037 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 038 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 039 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 040 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 041 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 042 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 043 OF THE POSSIBILITY OF SUCH DAMAGE. 044 */ 045 046 package org.codehaus.groovy.ast; 047 048 import groovy.lang.Closure; 049 import groovy.lang.GString; 050 import groovy.lang.MetaClass; 051 import groovy.lang.Range; 052 import groovy.lang.Reference; 053 import groovy.lang.Script; 054 055 import java.math.BigDecimal; 056 import java.math.BigInteger; 057 import java.util.List; 058 import java.util.Map; 059 import java.util.regex.Pattern; 060 061 import org.objectweb.asm.Opcodes; 062 063 /** 064 * This class is a Helper for ClassNode and classes handling ClassNodes. 065 * It does contain a set of predefined ClassNodes for the most used 066 * types and some code for cached ClassNode creation and basic 067 * ClassNode handling 068 * 069 * @author Jochen Theodorou 070 */ 071 public class ClassHelper { 072 073 074 private static String[] names = new String[] { 075 boolean.class.getName(), char.class.getName(), 076 byte.class.getName(), short.class.getName(), 077 int.class.getName(), long.class.getName(), 078 double.class.getName(), float.class.getName(), 079 Object.class.getName(), Void.TYPE.getName(), 080 Closure.class.getName(), GString.class.getName(), 081 List.class.getName(), Map.class.getName(), 082 Range.class.getName(), Pattern.class.getName(), 083 Script.class.getName(), String.class.getName(), 084 Boolean.class.getName(), Character.class.getName(), 085 Byte.class.getName(), Short.class.getName(), 086 Integer.class.getName(), Long.class.getName(), 087 Double.class.getName(), Float.class.getName(), 088 BigDecimal.class.getName(), BigInteger.class.getName(), 089 Void.class.getName(), Reference.class.getName(), 090 Class.class.getName(), MetaClass.class.getName() 091 }; 092 093 private static Class[] classes = new Class[] { 094 Object.class, Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, 095 Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE, 096 Closure.class, GString.class, List.class, Map.class, Range.class, 097 Pattern.class, Script.class, String.class, Boolean.class, 098 Character.class, Byte.class, Short.class, Integer.class, Long.class, 099 Double.class, Float.class, BigDecimal.class, BigInteger.class, Void.class, 100 Reference.class, Class.class, MetaClass.class 101 }; 102 103 public static final ClassNode 104 DYNAMIC_TYPE = new ClassNode(Object.class), OBJECT_TYPE = DYNAMIC_TYPE, 105 VOID_TYPE = new ClassNode(Void.TYPE), CLOSURE_TYPE = new ClassNode(Closure.class), 106 GSTRING_TYPE = new ClassNode(GString.class), LIST_TYPE = new ClassNode(List.class), 107 MAP_TYPE = new ClassNode(Map.class), RANGE_TYPE = new ClassNode(Range.class), 108 PATTERN_TYPE = new ClassNode(Pattern.class), STRING_TYPE = new ClassNode(String.class), 109 SCRIPT_TYPE = new ClassNode(Script.class), REFERENCE_TYPE = new ClassNode(Reference.class), 110 111 boolean_TYPE = new ClassNode(boolean.class), char_TYPE = new ClassNode(char.class), 112 byte_TYPE = new ClassNode(byte.class), int_TYPE = new ClassNode(int.class), 113 long_TYPE = new ClassNode(long.class), short_TYPE = new ClassNode(short.class), 114 double_TYPE = new ClassNode(double.class), float_TYPE = new ClassNode(float.class), 115 Byte_TYPE = new ClassNode(Byte.class), Short_TYPE = new ClassNode(Short.class), 116 Integer_TYPE = new ClassNode(Integer.class), Long_TYPE = new ClassNode(Long.class), 117 Character_TYPE = new ClassNode(Character.class), Float_TYPE = new ClassNode(Float.class), 118 Double_TYPE = new ClassNode(Double.class), Boolean_TYPE = new ClassNode(Boolean.class), 119 BigInteger_TYPE = new ClassNode(java.math.BigInteger.class), 120 BigDecimal_TYPE = new ClassNode(java.math.BigDecimal.class), 121 void_WRAPPER_TYPE = new ClassNode(Void.class), 122 123 CLASS_Type = new ClassNode(Class.class), METACLASS_TYPE = new ClassNode(MetaClass.class); 124 125 126 private static ClassNode[] types = new ClassNode[] { 127 OBJECT_TYPE, 128 boolean_TYPE, char_TYPE, byte_TYPE, short_TYPE, 129 int_TYPE, long_TYPE, double_TYPE, float_TYPE, 130 VOID_TYPE, CLOSURE_TYPE, GSTRING_TYPE, 131 LIST_TYPE, MAP_TYPE, RANGE_TYPE, PATTERN_TYPE, 132 SCRIPT_TYPE, STRING_TYPE, Boolean_TYPE, Character_TYPE, 133 Byte_TYPE, Short_TYPE, Integer_TYPE, Long_TYPE, 134 Double_TYPE, Float_TYPE, BigDecimal_TYPE, BigInteger_TYPE, 135 void_WRAPPER_TYPE, REFERENCE_TYPE, CLASS_Type, METACLASS_TYPE 136 }; 137 138 139 private static ClassNode[] numbers = new ClassNode[] { 140 char_TYPE, byte_TYPE, short_TYPE, int_TYPE, long_TYPE, 141 double_TYPE, float_TYPE, Short_TYPE, Byte_TYPE, Character_TYPE, 142 Integer_TYPE, Float_TYPE, Long_TYPE, Double_TYPE, BigInteger_TYPE, 143 BigDecimal_TYPE 144 }; 145 146 protected static final ClassNode[] EMPTY_TYPE_ARRAY = {}; 147 148 public static final String OBJECT = "java.lang.Object"; 149 150 151 /** 152 * Creates an array of ClassNodes using an array of classes. 153 * For each of the given classes a new ClassNode will be 154 * created 155 * @see #make(Class) 156 * @param classes an array of classes used to create the ClassNodes 157 * @return an array of ClassNodes 158 */ 159 public static ClassNode[] make(Class[] classes) { 160 ClassNode[] cns = new ClassNode[classes.length]; 161 for (int i=0; i<cns.length; i++) { 162 cns[i] = make(classes[i]); 163 } 164 165 return cns; 166 } 167 168 /** 169 * Creates a ClassNode using a given class. 170 * A new ClassNode object is only created if the class 171 * is not one of the predefined ones 172 * 173 * @param c class used to created the ClassNode 174 * @return ClassNode instance created from the given class 175 */ 176 public static ClassNode make(Class c) { 177 for (int i=0; i<classes.length; i++) { 178 if (c==classes[i]) return types[i]; 179 } 180 if (c.isArray()) { 181 ClassNode cn = make(c.getComponentType()); 182 return cn.makeArray(); 183 } 184 ClassNode t = new ClassNode(c); 185 return t; 186 } 187 188 /** 189 * Creates a ClassNode using a given class. 190 * Unlike make(String) this method will not use the cache 191 * to create the ClassNode. This means the ClassNode created 192 * from this method using the same name will have a different 193 * references 194 * 195 * @see #make(String) 196 * @param name of the class the ClassNode is representing 197 */ 198 public static ClassNode makeWithoutCaching(String name) { 199 ClassNode cn = new ClassNode(name,Opcodes.ACC_PUBLIC,OBJECT_TYPE); 200 cn.isPrimaryNode = false; 201 return cn; 202 } 203 204 /** 205 * Creates a ClassNode using a given class. 206 * If the name is one of the predefined ClassNodes then the 207 * corresponding ClassNode instance will be returned. If the 208 * is null of of length 0 the dynamic type is returned 209 * 210 * @param name of the class the ClassNode is representing 211 */ 212 public static ClassNode make(String name) { 213 if (name == null || name.length() == 0) return DYNAMIC_TYPE; 214 215 for (int i=0; i<classes.length; i++) { 216 String cname = classes[i].getName(); 217 if (name.equals(cname)) return types[i]; 218 } 219 return makeWithoutCaching(name); 220 } 221 222 /** 223 * Creates a ClassNode containing the wrapper of a ClassNode 224 * of primitive type. Any ClassNode representing a primitive 225 * type should be created using the predefined types used in 226 * class. The method will check the parameter for known 227 * references of ClassNode representing a primitive type. If 228 * Reference is found, then a ClassNode will be contained that 229 * represents the wrapper class. For exmaple for boolean, the 230 * wrapper class is java.lang.Boolean. 231 * 232 * If the parameter is no primitve type, the redirected 233 * ClassNode will be returned 234 * 235 * @see #make(Class) 236 * @see #make(String) 237 * @param cn the ClassNode containing a possible primitive type 238 */ 239 public static ClassNode getWrapper(ClassNode cn) { 240 cn = cn.redirect(); 241 if (!isPrimitiveType(cn)) return cn; 242 if (cn==boolean_TYPE) { 243 return Boolean_TYPE; 244 } else if (cn==byte_TYPE) { 245 return Byte_TYPE; 246 } else if (cn==char_TYPE) { 247 return Character_TYPE; 248 } else if (cn==short_TYPE) { 249 return Short_TYPE; 250 } else if (cn==int_TYPE) { 251 return Integer_TYPE; 252 } else if (cn==long_TYPE) { 253 return Long_TYPE; 254 } else if (cn==float_TYPE) { 255 return Float_TYPE; 256 } else if (cn==double_TYPE) { 257 return Double_TYPE; 258 } else if (cn==VOID_TYPE) { 259 return void_WRAPPER_TYPE; 260 } 261 else { 262 return cn; 263 } 264 } 265 266 /** 267 * Test to determine if a ClasNode is a primitve type. 268 * Note: this only works for ClassNodes created using a 269 * predefined ClassNode 270 * 271 * @see #make(Class) 272 * @see #make(String) 273 * @param cn the ClassNode containing a possible primitive type 274 * @return true if the ClassNode is a primitve type 275 */ 276 public static boolean isPrimitiveType(ClassNode cn) { 277 return cn == boolean_TYPE || 278 cn == char_TYPE || 279 cn == byte_TYPE || 280 cn == short_TYPE || 281 cn == int_TYPE || 282 cn == long_TYPE || 283 cn == float_TYPE || 284 cn == double_TYPE || 285 cn == VOID_TYPE; 286 } 287 288 public static ClassNode makeReference() { 289 return make(Reference.class); 290 } 291 292 }