1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.codehaus.groovy.ast;
47
48 import groovy.lang.Closure;
49 import groovy.lang.GString;
50 import groovy.lang.MetaClass;
51 import groovy.lang.Range;
52 import groovy.lang.Reference;
53 import groovy.lang.Script;
54
55 import java.math.BigDecimal;
56 import java.math.BigInteger;
57 import java.util.List;
58 import java.util.Map;
59 import java.util.regex.Pattern;
60
61 import org.objectweb.asm.Opcodes;
62
63 /***
64 * This class is a Helper for ClassNode and classes handling ClassNodes.
65 * It does contain a set of predefined ClassNodes for the most used
66 * types and some code for cached ClassNode creation and basic
67 * ClassNode handling
68 *
69 * @author Jochen Theodorou
70 */
71 public class ClassHelper {
72
73
74 private static String[] names = new String[] {
75 boolean.class.getName(), char.class.getName(),
76 byte.class.getName(), short.class.getName(),
77 int.class.getName(), long.class.getName(),
78 double.class.getName(), float.class.getName(),
79 Object.class.getName(), Void.TYPE.getName(),
80 Closure.class.getName(), GString.class.getName(),
81 List.class.getName(), Map.class.getName(),
82 Range.class.getName(), Pattern.class.getName(),
83 Script.class.getName(), String.class.getName(),
84 Boolean.class.getName(), Character.class.getName(),
85 Byte.class.getName(), Short.class.getName(),
86 Integer.class.getName(), Long.class.getName(),
87 Double.class.getName(), Float.class.getName(),
88 BigDecimal.class.getName(), BigInteger.class.getName(),
89 Void.class.getName(), Reference.class.getName(),
90 Class.class.getName(), MetaClass.class.getName()
91 };
92
93 private static Class[] classes = new Class[] {
94 Object.class, Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
95 Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE,
96 Closure.class, GString.class, List.class, Map.class, Range.class,
97 Pattern.class, Script.class, String.class, Boolean.class,
98 Character.class, Byte.class, Short.class, Integer.class, Long.class,
99 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 }