1 module introspection.module_; 2 3 import std.traits; 4 import std.conv; 5 6 import introspection.type; 7 import introspection.callable; 8 import introspection.aggregate; 9 import introspection.template_; 10 import introspection.location; 11 import introspection.protection; 12 import introspection.property; 13 import introspection.unittest_; 14 import introspection.manifestConstant; 15 16 version(unittest) { 17 import fluent.asserts; 18 } 19 20 /// Stores information about modules 21 struct Module { 22 /// The constant name 23 string name; 24 25 /// 26 string fullyQualifiedName; 27 28 /// 29 Callable[] functions; 30 31 /// 32 Aggregate[] aggregates; 33 34 /// 35 Template[] templates; 36 37 /// 38 Property[] globals; 39 40 /// 41 ManifestConstant[] manifestConstants; 42 43 /// 44 UnitTest[] unitTests; 45 46 /// 47 Location location; 48 } 49 50 /// Describe a module and containing members 51 Module describeModule(alias T, bool withUnitTests = false)() if(__traits(isModule, T)) { 52 Module module_; 53 54 module_.name = T.stringof; 55 module_.fullyQualifiedName = fullyQualifiedName!T; 56 Location location; 57 58 static foreach(member; __traits(allMembers, T)) static if(member.stringof != `"object"` && __traits(compiles, __traits(getMember, T, member))) {{ 59 alias M = __traits(getMember, T, member); 60 61 static if(__traits(compiles, __traits(getLocation, M))) { 62 if(module_.location.file == "") { 63 module_.location.file = __traits(getLocation, M)[0]; 64 } 65 } 66 67 static if(isCallable!M) { 68 static foreach(index, overload; __traits(getOverloads, T, member)) { 69 module_.functions ~= describeCallable!(overload, index); 70 } 71 } 72 else static if(__traits(isTemplate, M)) { 73 module_.templates ~= describeTemplate!M; 74 } 75 else static if(isTypeTuple!M && isAggregateType!M) { 76 module_.aggregates ~= describeAggregate!M; 77 } 78 else static if(isManifestConstant!M) { 79 module_.manifestConstants ~= describeManifestConstant!(T, member); 80 } 81 else static if(__traits(compiles, describeProperty!M)) { 82 module_.globals ~= describeProperty!M; 83 } 84 }} 85 86 static if(withUnitTests) { 87 module_.unitTests = describeUnitTests!T; 88 } 89 90 return module_; 91 } 92 93 /// It should describe a module with all functions, aggregates, templates, and global vars 94 unittest { 95 import introspection.test.moduleDef; 96 97 auto result = describeModule!(introspection.test.moduleDef, true); 98 99 result.name.should.equal("module moduleDef"); 100 result.fullyQualifiedName.should.equal("introspection.test.moduleDef"); 101 102 /// check functions 103 result.functions.length.should.equal(2); 104 result.functions[0].name.should.equal("testFunction"); 105 result.functions[1].name.should.equal("privateFunction"); 106 107 /// check aggregates 108 result.aggregates.length.should.equal(4); 109 result.aggregates[0].name.should.equal("TestStructure"); 110 result.aggregates[1].name.should.equal("TestClass"); 111 result.aggregates[2].name.should.equal("TestInterface"); 112 result.aggregates[3].name.should.equal("TestUnion"); 113 114 /// check templates 115 result.templates.length.should.equal(2); 116 result.templates[0].name.should.equal("TestTpl"); 117 result.templates[1].name.should.equal("templatedFunction"); 118 119 /// check globals 120 result.globals.length.should.equal(1); 121 result.globals[0].name.should.equal("globalVar"); 122 123 /// check manifest constants 124 result.manifestConstants.length.should.equal(1); 125 result.manifestConstants[0].name.should.equal("someManifestConstant"); 126 127 /// check unittests 128 result.unitTests.length.should.equal(2); 129 130 /// 131 result.location.file.should.equal("source/introspection/test/moduleDef.d"); 132 result.location.line.should.equal(0); 133 result.location.column.should.equal(0); 134 } 135 136 /// It should be able to describe the std.array module 137 unittest { 138 import std.array; 139 140 auto result = describeModule!(std.array); 141 142 result.name.should.equal("module array"); 143 result.fullyQualifiedName.should.equal("std.array"); 144 145 result.functions.length.should.equal(1); 146 result.functions[0].name.should.equal("_d_newarrayU"); 147 148 result.templates.length.should.equal(31); 149 } 150 151 /// It should be able to describe the std.stdio module 152 unittest { 153 import std.stdio; 154 155 auto result = describeModule!(std.stdio); 156 157 result.name.should.equal("module stdio"); 158 result.fullyQualifiedName.should.equal("std.stdio"); 159 160 result.functions.length.should.equal(22); 161 result.functions[0].name.should.equal("fputc_unlocked"); 162 163 result.templates.length.should.equal(15); 164 }