1 /**
2  * Provides runtime traits, which provide much of the functionality of tango.core.Traits and
3  * is-expressions, as well as some functionality that is only available at runtime, using
4  * runtime type information.
5  *
6  * Authors: Chris Wright (dhasenan) <dhasenan@gmail.com>
7  * License: tango license, apache 2.0
8  * Copyright (c) 2009, CHRISTOPHER WRIGHT
9  */
10 module java.nonstandard.RuntimeTraits;
11 import java.lang.all;
12 
13 version(Tango){
14     alias ClassInfo ConstClassInfo;
15     alias TypeInfo ConstTypeInfo;
16 } else { // Phobos
17     mixin("alias const(TypeInfo_Class) ConstClassInfo;");
18     mixin("alias const(TypeInfo) ConstTypeInfo;");
19 }
20 
21 // Only DWT
22 public bool isJavaPrimitive( in TypeInfo type ){
23     return isBool(type) || isInteger(type) || isCharacter(type) || isFloat(type);
24 }
25 
26 public TypeInfo_Class getTypeInfo( in ClassInfo ci ){
27     return null;
28 }
29 
30 public TypeInfo_Class getSuperclass( in ClassInfo ci ){
31     return getSuperclass(getTypeInfo(ci));
32 }
33 public TypeInfo_Class getSuperclass( in TypeInfo ti ){
34     return null;
35 }
36 
37 public TypeInfo_Interface[] getInterfaces( in ClassInfo ci ){
38     return getInterfaces(getTypeInfo(ci));
39 }
40 public TypeInfo_Interface[] getInterfaces( in TypeInfo ti ){
41     return null;
42 }
43 
44 public String getName( in ClassInfo ci ){
45     return ci.name;
46 }
47 public String getName( in TypeInfo ti ){
48     if( isClass(ti) ){
49         return getName( asClass(ti));
50     }
51     return null;
52 }
53 
54 // End DWT. Start Tango...
55 /// If the given type represents a typedef, return the actual type.
56 ConstTypeInfo realType (in TypeInfo type)
57 {
58     // The current D Programming Language does not have typedef.
59     //
60     // // TypeInfo_Typedef.next() doesn't return the actual type.
61     // // I think it returns TypeInfo_Typedef.base.next().
62     // // So, a slightly different method.
63     // auto def = cast(TypeInfo_Typedef) type;
64     // if (def !is null)
65     // {
66     //     return def.base;
67     // }
68     return type;
69 }
70 
71 /// If the given type represents a class, return its ClassInfo; else return null;
72 ConstClassInfo asClass (in TypeInfo type)
73 {
74     if (isInterface (type))
75     {
76         auto klass = cast(TypeInfo_Interface) type;
77         return klass.info;
78     }
79     if (isClass (type))
80     {
81         auto klass = cast(TypeInfo_Class) type;
82         return klass.info;
83     }
84     return null;
85 }
86 
87 /** Returns true iff one type is an ancestor of the other, or if the types are the same.
88  * If either is null, returns false. */
89 bool isDerived (in ClassInfo derived, in ClassInfo base)
90 {
91     if (derived is null || base is null)
92         return false;
93     ConstClassInfo* pderived = &derived;
94     do
95         if (*pderived is base)
96             return true;
97     while ((pderived = &derived.base) !is null);
98     return false;
99 }
100 
101 /** Returns true iff implementor implements the interface described
102  * by iface. This is an expensive operation (linear in the number of
103  * interfaces and base classes).
104  */
105 bool implements (in ClassInfo implementor, in ClassInfo iface)
106 {
107     foreach (info; applyInterfaces (implementor))
108     {
109         if (iface is info)
110             return true;
111     }
112     return false;
113 }
114 
115 /** Returns true iff an instance of class test is implicitly castable to target.
116  * This is an expensive operation (isDerived + implements). */
117 bool isImplicitly (in ClassInfo test, in ClassInfo target)
118 {
119     // Keep isDerived first.
120     // isDerived will be much faster than implements.
121     return (isDerived (test, target) || implements (test, target));
122 }
123 
124 /** Returns true iff an instance of type test is implicitly castable to target.
125  * If the types describe classes or interfaces, this is an expensive operation. */
126 bool isImplicitly (in TypeInfo test, in TypeInfo target)
127 {
128     // A lot of special cases. This is ugly.
129     if (test is target)
130         return true;
131     if (isStaticArray (test) && isDynamicArray (target) && valueType (test) is valueType (target))
132     {
133         // you can implicitly cast static to dynamic (currently) if they
134         // have the same value type. Other casts should be forbidden.
135         return true;
136     }
137     auto klass1 = asClass (test);
138     auto klass2 = asClass (target);
139     if (isClass (test) && isClass (target))
140     {
141         return isDerived (klass1, klass2);
142     }
143     if (isInterface (test) && isInterface (target))
144     {
145         return isDerived (klass1, klass2);
146     }
147     if (klass1 && klass2)
148     {
149         return isImplicitly (klass1, klass2);
150     }
151     if (klass1 || klass2)
152     {
153         // no casts from class to non-class
154         return false;
155     }
156     if ((isSignedInteger (test) && isSignedInteger (target)) || (isUnsignedInteger (test) && isUnsignedInteger (target)) || (isFloat (
157             test) && isFloat (target)) || (isCharacter (test) && isCharacter (target)))
158     {
159         return test.tsize () <= target.tsize ();
160     }
161     if (isSignedInteger (test) && isUnsignedInteger (target))
162     {
163         // potential loss of data
164         return false;
165     }
166     if (isUnsignedInteger (test) && isSignedInteger (target))
167     {
168         // if the sizes are the same, you could be losing data
169         // the upper half of the range wraps around to negatives
170         // if the target type is larger, you can safely hold it
171         return test.tsize () < target.tsize ();
172     }
173     // delegates and functions: no can do
174     // pointers: no
175     // structs: no
176     return false;
177 }
178 
179 ///
180 ConstClassInfo[] baseClasses (in ClassInfo type)
181 {
182     if (type is null)
183         return null;
184     ConstClassInfo[] types;
185     ConstClassInfo* ptype = &type;
186     while ((ptype = &ptype.base) !is null)
187         types ~= *ptype;
188     return types;
189 }
190 
191 /** Returns a list of all interfaces that this type implements, directly
192  * or indirectly. This includes base interfaces of types the class implements,
193  * and interfaces that base classes implement, and base interfaces of interfaces
194  * that base classes implement. This is an expensive operation. */
195 ConstClassInfo[] baseInterfaces (in ClassInfo type)
196 {
197     if (type is null)
198         return null;
199     ConstClassInfo[] types = directInterfaces (type);
200     ConstClassInfo* ptype = &type;
201     while ((ptype = &ptype.base) !is null)
202     {
203         types ~= interfaceGraph (*ptype);
204     }
205     return types;
206 }
207 
208 /** Returns all the interfaces that this type directly implements, including
209  * inherited interfaces. This is an expensive operation.
210  *
211  * Examples:
212  * ---
213  * interface I1 {}
214  * interface I2 : I1 {}
215  * class A : I2 {}
216  *
217  * auto interfaces = interfaceGraph (A.classinfo);
218  * // interfaces = [I1.classinfo, I2.classinfo]
219  * ---
220  *
221  * ---
222  * interface I1 {}
223  * interface I2 {}
224  * class A : I1 {}
225  * class B : A, I2 {}
226  *
227  * auto interfaces = interfaceGraph (B.classinfo);
228  * // interfaces = [I2.classinfo]
229  * ---
230  */
231 ConstClassInfo[] interfaceGraph (in ClassInfo type)
232 {
233     ConstClassInfo[] info;
234     foreach (iface; type.interfaces)
235     {
236         info ~= iface.classinfo;
237         info ~= interfaceGraph (iface.classinfo);
238     }
239     return info;
240 }
241 
242 /** Iterate through all interfaces that type implements, directly or indirectly, including base interfaces. */
243 struct applyInterfaces
244 {
245     ///
246     int opApply (int delegate (ref ConstClassInfo) dg)
247     {
248         int result = 0;
249         ConstClassInfo* ptype = &type;
250         for (; *ptype !is null; ptype = &type.base)
251         {
252             foreach (iface; ptype.interfaces)
253             {
254                 result = dg (iface.classinfo);
255                 if (result)
256                     return result;
257                 result = applyInterfaces (iface.classinfo).opApply (dg);
258                 if (result)
259                     return result;
260             }
261         }
262         return result;
263     }
264 
265     ConstClassInfo type;
266 }
267 
268 ///
269 ConstClassInfo[] baseTypes (in ClassInfo type)
270 {
271     if (type is null)
272         return null;
273     return baseClasses (type) ~ baseInterfaces (type);
274 }
275 
276 ///
277 version(Tango){
278     ModuleInfo moduleOf (in ClassInfo type)
279     {
280         foreach (modula; ModuleInfo)
281             foreach (klass; modula.localClasses)
282                 if (klass is type)
283                     return modula;
284         return null;
285     }
286 } else { // Phobos
287     ModuleInfo* moduleOf (in ClassInfo type)
288     {
289         foreach (modula; ModuleInfo)
290             foreach (klass; modula.localClasses)
291                 if (klass is type)
292                     return modula;
293         return null;
294     }
295 }
296 
297 /// Returns a list of interfaces that this class directly implements.
298 ConstClassInfo[] directInterfaces (in ClassInfo type)
299 {
300     ConstClassInfo[] types;
301     foreach (iface; type.interfaces)
302         types ~= iface.classinfo;
303     return types;
304 }
305 
306 /** Returns a list of all types that are derived from the given type. This does not
307  * count interfaces; that is, if type is an interface, you will only get derived
308  * interfaces back. It is an expensive operations. */
309 ConstClassInfo[] derivedTypes (in ClassInfo type)
310 {
311     ConstClassInfo[] types;
312     foreach (modula; ModuleInfo)
313         foreach (klass; modula.localClasses)
314             if (isDerived (klass, type) && (klass !is type))
315                 types ~= klass;
316     return types;
317 }
318 
319 ///
320 bool isDynamicArray (in TypeInfo type)
321 {
322     // This implementation is evil.
323     // Array typeinfos are named TypeInfo_A?, and defined individually for each
324     // possible type aside from structs. For example, typeinfo for int[] is
325     // TypeInfo_Ai; for uint[], TypeInfo_Ak.
326     // So any TypeInfo with length 11 and starting with TypeInfo_A is an array
327     // type.
328     // Also, TypeInfo_Array is an array type.
329     auto type2 = realType (type);
330     return ((type2.classinfo.name[9] == 'A') && (type2.classinfo.name.length == 11)) || ((cast(TypeInfo_Array) type2) !is null);
331 }
332 
333 ///
334 bool isStaticArray (in TypeInfo type)
335 {
336     auto type2 = realType (type);
337     return (cast(TypeInfo_StaticArray) type2) !is null;
338 }
339 
340 /** Returns true iff the given type is a dynamic or static array (false for associative
341  * arrays and non-arrays). */
342 bool isArray (in TypeInfo type)
343 {
344     auto type2 = realType (type);
345     return isDynamicArray (type2) || isStaticArray (type2);
346 }
347 
348 ///
349 bool isAssociativeArray (in TypeInfo type)
350 {
351     auto type2 = realType (type);
352     return (cast(TypeInfo_AssociativeArray) type2) !is null;
353 }
354 
355 ///
356 bool isCharacter (in TypeInfo type)
357 {
358     auto type2 = realType (type);
359     return (type2 is typeid(char) || type2 is typeid(wchar) || type2 is typeid(dchar));
360 }
361 
362 ///
363 bool isString (in TypeInfo type)
364 {
365     auto type2 = realType (type);
366     return isArray (type2) && isCharacter (valueType (type2));
367 }
368 
369 ///
370 bool isUnsignedInteger (in TypeInfo type)
371 {
372     auto type2 = realType (type);
373     return (type2 is typeid(uint) || type2 is typeid(ulong) || type2 is typeid(ushort) || type2 is typeid(ubyte));
374 }
375 
376 ///
377 bool isSignedInteger (in TypeInfo type)
378 {
379     auto type2 = realType (type);
380     return (type2 is typeid(int) || type2 is typeid(long) || type2 is typeid(short) || type2 is typeid(byte));
381 }
382 
383 ///
384 bool isInteger (in TypeInfo type)
385 {
386     auto type2 = realType (type);
387     return isSignedInteger (type2) || isUnsignedInteger (type2);
388 }
389 
390 ///
391 bool isBool (in TypeInfo type)
392 {
393     auto type2 = realType (type);
394     return (type2 is typeid(bool));
395 }
396 
397 ///
398 bool isFloat (in TypeInfo type)
399 {
400     auto type2 = realType (type);
401     return (type2 is typeid(float) || type2 is typeid(double) || type2 is typeid(real));
402 }
403 
404 ///
405 bool isPrimitive (in TypeInfo type)
406 {
407     auto type2 = realType (type);
408     return (isArray (type2) || isAssociativeArray (type2) || isCharacter (type2) || isFloat (type2) || isInteger (type2));
409 }
410 
411 /// Returns true iff the given type represents an interface.
412 bool isInterface (in TypeInfo type)
413 {
414     return (cast(TypeInfo_Interface) type) !is null;
415 }
416 
417 ///
418 bool isPointer (in TypeInfo type)
419 {
420     auto type2 = realType (type);
421     return (cast(TypeInfo_Pointer) type2) !is null;
422 }
423 
424 /// Returns true iff the type represents a class (false for interfaces).
425 bool isClass (in TypeInfo type)
426 {
427     auto type2 = realType (type);
428     return (cast(TypeInfo_Class) type2) !is null;
429 }
430 
431 ///
432 bool isStruct (in TypeInfo type)
433 {
434     auto type2 = realType (type);
435     return (cast(TypeInfo_Struct) type2) !is null;
436 }
437 
438 ///
439 bool isFunction (in TypeInfo type)
440 {
441     auto type2 = realType (type);
442     return ((cast(TypeInfo_Function) type2) !is null) || ((cast(TypeInfo_Delegate) type2) !is null);
443 }
444 
445 /** Returns true iff the given type is a reference type. */
446 bool isReferenceType (in TypeInfo type)
447 {
448     return isClass (type) || isPointer (type) || isDynamicArray (type);
449 }
450 
451 /** Returns true iff the given type represents a user-defined type.
452  * This does not include functions, delegates, aliases, or typedefs. */
453 bool isUserDefined (in TypeInfo type)
454 {
455     return isClass (type) || isStruct (type);
456 }
457 
458 /** Returns true for all value types, false for all reference types.
459  * For functions and delegates, returns false (is this the way it should be?). */
460 bool isValueType (in TypeInfo type)
461 {
462     return !(isDynamicArray (type) || isAssociativeArray (type) || isPointer (type) || isClass (type) || isFunction (
463             type));
464 }
465 
466 /** The key type of the given type. For an array, size_t; for an associative
467  * array T[U], U. */
468 ConstTypeInfo keyType (in TypeInfo type)
469 {
470     auto type2 = realType (type);
471     auto assocArray = cast(TypeInfo_AssociativeArray) type2;
472     if (assocArray)
473         return assocArray.key;
474     if (isArray (type2))
475         return typeid(size_t);
476     return null;
477 }
478 
479 /** The value type of the given type -- given T[] or T[n], T; given T[U],
480  * T; given T*, T; anything else, null. */
481 ConstTypeInfo valueType (in TypeInfo type)
482 {
483     auto type2 = realType (type);
484     if (isArray (type2))
485         return type2.next;
486     auto assocArray = cast(TypeInfo_AssociativeArray) type2;
487     if (assocArray)
488         return assocArray.value;
489     auto pointer = cast(TypeInfo_Pointer) type2;
490     if (pointer)
491         return pointer.m_next;
492     return null;
493 }
494 
495 /** If the given type represents a delegate or function, the return type
496  * of that function. Otherwise, null. */
497 ConstTypeInfo returnType (in TypeInfo type)
498 {
499     auto type2 = realType (type);
500     auto delegat = cast(TypeInfo_Delegate) type2;
501     if (delegat)
502         return delegat.next;
503     auto func = cast(TypeInfo_Function) type2;
504     if (func)
505         return func.next;
506     return null;
507 }
508 
509 debug (UnitTest)
510 {
511 
512     interface I1
513     {
514     }
515 
516     interface I2
517     {
518     }
519 
520     interface I3
521     {
522     }
523 
524     interface I4
525     {
526     }
527 
528     class A
529     {
530     }
531 
532     class B : A, I1
533     {
534     }
535 
536     class C : B, I2, I3
537     {
538     }
539 
540     class D : A, I1
541     {
542         int foo (int i)
543         {
544             return i;
545         }
546     }
547 
548     struct S1
549     {
550     }
551 
552     unittest {
553         // Struct-related stuff.
554         auto type = typeid(S1);
555         assert (isStruct (type));
556         assert (isValueType (type));
557         assert (isUserDefined (type));
558         assert (!isClass (type));
559         assert (!isPointer (type));
560         assert (null is returnType (type));
561         assert (!isPrimitive (type));
562         assert (valueType (type) is null);
563     }
564 
565     unittest {
566         auto type = A.classinfo;
567         assert (baseTypes (type) == [Object.classinfo]);
568         assert (baseClasses (type) == [Object.classinfo]);
569         assert (baseInterfaces (type).length == 0);
570         type = C.classinfo;
571         assert (baseClasses (type) == [B.classinfo, A.classinfo, Object.classinfo]);
572         assert (baseInterfaces (type) == [I2.classinfo, I3.classinfo, I1.classinfo]);
573         assert (baseTypes (type) == [B.classinfo, A.classinfo, Object.classinfo, I2.classinfo, I3.classinfo,
574                 I1.classinfo]);
575     }
576 
577     unittest {
578         assert (isPointer (typeid(S1*)));
579         assert (isArray (typeid(S1[])));
580         assert (valueType (typeid(S1*)) is typeid(S1));
581         auto d = new D;
582         assert (returnType (typeid(typeof(&d.foo))) is typeid(int));
583         assert (isFloat (typeid(real)));
584         assert (isFloat (typeid(double)));
585         assert (isFloat (typeid(float)));
586         assert (!isFloat (typeid(creal)));
587         assert (!isFloat (typeid(cdouble)));
588         assert (!isInteger (typeid(float)));
589         assert (!isInteger (typeid(creal)));
590         assert (isInteger (typeid(ulong)));
591         assert (isInteger (typeid(ubyte)));
592         assert (isCharacter (typeid(char)));
593         assert (isCharacter (typeid(wchar)));
594         assert (isCharacter (typeid(dchar)));
595         assert (!isCharacter (typeid(ubyte)));
596         assert (isArray (typeid(typeof("hello"))));
597         assert (isCharacter (typeid(typeof("hello"[0]))));
598         assert (valueType (typeid(typeof("hello"))) is typeid(typeof('h')));
599         assert (isString (typeid(typeof("hello"))), typeof("hello").stringof);
600         auto staticString = typeid(typeof("hello"d));
601         auto dynamicString = typeid(typeof("hello"d[0 .. $]));
602         assert (isString (staticString));
603         assert (isStaticArray (staticString));
604         assert (isDynamicArray (dynamicString), dynamicString.toString () ~ dynamicString.classinfo.name);
605         assert (isString (dynamicString));
606 
607         auto type = typeid(int[char[]]);
608         assert (valueType (type) is typeid(int), valueType (type).toString ());
609         assert (keyType (type) is typeid(char[]), keyType (type).toString ());
610         void delegate (int) dg = (int i)
611         {
612         };
613         assert (returnType (typeid(typeof(dg))) is typeid(void));
614         assert (returnType (typeid(int delegate (int))) is typeid(int));
615 
616         assert (!isDynamicArray (typeid(int[4])));
617         assert (isStaticArray (typeid(int[4])));
618     }
619 
620     unittest {
621         enum myint : int {
622             init = int.init
623         }
624         assert (typeid(myint) !is null, "null typeid(myint)");
625         assert (isInteger (typeid(myint)));
626     }
627 
628 }
629