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 }