1 /*
2  * Find classinfos at runtime.
3  */
4 module qcheck.detail.runtimeclass;
5 
6 package:
7 
8 /**
9  * Helper that collects all classinfos from known modules for which
10  * pred returns true.
11  */
12 ClassInfo[] findClasses(bool delegate(ClassInfo) pred) {
13   ClassInfo[] derived;
14   foreach(m; ModuleInfo) {
15     foreach(c; m.localClasses) {
16       if (pred(c))
17         derived ~= c;
18     }
19   }
20   return derived;
21 }
22 
23 
24 /****************************************
25   Predicates
26 */
27 
28 /**
29  * Returns true if base is a baseclass of derived.
30  */
31 bool isDerived(ClassInfo derived, ClassInfo base) {
32   while (derived.base) {
33     derived = derived.base;
34     if (base is derived)
35       return true;
36   }
37   return false;
38 }
39 
40 /**
41  * Returns true if derived implements the interface interf.
42  */
43 bool implements(ClassInfo derived, ClassInfo interf) {
44   foreach(ci; derived.interfaces) {
45     if (ci.classinfo is interf)
46       return true;
47   }
48   return false;
49 }
50 
51 /**
52  * Returns true if derived or any of it's base classes implements the
53  * interface interf.
54  */
55 bool inherits(ClassInfo derived, ClassInfo interf) {
56   while (derived) {
57     if (implements(derived, interf))
58       return true;
59     derived = derived.base;
60   }
61   return false;
62 }
63 
64 
65 version(unittest) {
66   class Base {}
67   class Derived : Base {}
68   interface IBase {}
69   class IImpl : IBase {}
70   class IImpl2 : IImpl {}
71 }
72 
73 unittest {
74   auto classDerivatives =
75     findClasses((ClassInfo c) { return isDerived(c, Base.classinfo); } );
76   assert(classDerivatives == [Derived.classinfo]);
77 
78   auto interfaceDerivatives =
79     findClasses((ClassInfo c) { return isDerived(c, IBase.classinfo); } );
80   assert(interfaceDerivatives.length == 0);
81 
82   auto immediateImpls =
83     findClasses((ClassInfo c) { return implements(c, IBase.classinfo); } );
84   assert(immediateImpls == [IImpl.classinfo]);
85 
86   auto allInterfaceClasses =
87     findClasses((ClassInfo c) { return inherits(c, IBase.classinfo); } );
88   assert(allInterfaceClasses == [IImpl.classinfo, IImpl2.classinfo]);
89 }