1 /**
2  * Internal reflection templates for implementing mocking behaviour.
3  *
4  * License:
5  *     MIT. See LICENSE for full details.
6  */
7 module dunit.reflection;
8 
9 /**
10  * Imports.
11  */
12 import dunit.toolkit;
13 import std.array;
14 import std.range;
15 import std..string;
16 import std.traits;
17 
18 /**
19  * Generate a string containing the protection level of the passed function.
20  *
21  * Params:
22  *     func = The function to inspect.
23  */
24 private template MethodProtection(func...) if (func.length == 1 && isCallable!(func))
25 {
26 	enum MethodProtection = __traits(getProtection, func);
27 }
28 
29 unittest
30 {
31 	class T
32 	{
33 		public void method1(){}
34 		protected void method2(){}
35 		private void method3(){}
36 	}
37 
38 	MethodProtection!(T.method1).assertEqual("public");
39 	MethodProtection!(T.method2).assertEqual("protected");
40 	MethodProtection!(T.method3).assertEqual("private");
41 }
42 
43 /**
44  * Generate a string containing the synchronization of the passed function.
45  *
46  * Params:
47  *     func = The function to inspect.
48  */
49 private template MethodSynchonization(func...) if (func.length == 1 && isCallable!(func))
50 {
51 	enum MethodSynchonization = isMethodShared!(func) ? "shared" : "";
52 }
53 
54 unittest
55 {
56 	class T
57 	{
58 		public shared void method1(){}
59 		public synchronized void method2(){}
60 		public void method3(){}
61 	}
62 
63 	MethodSynchonization!(T.method1).assertEqual("shared");
64 	MethodSynchonization!(T.method2).assertEqual("shared");
65 	MethodSynchonization!(T.method3).assertEqual("");
66 }
67 
68 /**
69  * Generate a string containing the attributes of the passed function.
70  *
71  * Params:
72  *     func = The function to inspect.
73  */
74 private template MethodAttributes(func...) if (func.length == 1 && isCallable!(func))
75 {
76 	private string getMethodAttributes()
77 	{
78 		string code = "";
79 
80 		with (FunctionAttribute)
81 		{
82 			static if (functionAttributes!(func) & property)
83 			{
84 				code ~= "@property ";
85 			}
86 
87 			static if (functionAttributes!(func) & trusted)
88 			{
89 				code ~= "@trusted ";
90 			}
91 
92 			static if (functionAttributes!(func) & safe)
93 			{
94 				code ~= "@safe ";
95 			}
96 
97 			static if (functionAttributes!(func) & pure_)
98 			{
99 				code ~= "pure ";
100 			}
101 
102 			static if (functionAttributes!(func) & nothrow_)
103 			{
104 				code ~= "nothrow ";
105 			}
106 
107 			static if (functionAttributes!(func) & ref_)
108 			{
109 				code ~= "ref ";
110 			}
111 		}
112 		return code.stripRight();
113 	}
114 	enum MethodAttributes = getMethodAttributes();
115 }
116 
117 unittest
118 {
119 	class T
120 	{
121 		public @property @trusted void method1(){}
122 		public @safe pure nothrow void method2(){}
123 		public ref int method3(ref int foo){return foo;}
124 	}
125 
126 	MethodAttributes!(T.method1).assertEqual("@property @trusted");
127 	MethodAttributes!(T.method2).assertEqual("@safe pure nothrow");
128 	MethodAttributes!(T.method3).assertEqual("ref");
129 }
130 
131 /**
132  * Generate a string containing the return type of the passed function.
133  *
134  * Params:
135  *     func = The function to inspect.
136  */
137 private template MethodReturnType(func...) if (func.length == 1 && isCallable!(func))
138 {
139 	enum MethodReturnType = ReturnType!(func).stringof;
140 }
141 
142 unittest
143 {
144 	class T
145 	{
146 		public int method1(){return 1;}
147 		public string method2(){return "foo";}
148 		public char method3(){return 'a';}
149 	}
150 
151 	MethodReturnType!(T.method1).assertEqual("int");
152 	MethodReturnType!(T.method2).assertEqual("string");
153 	MethodReturnType!(T.method3).assertEqual("char");
154 }
155 
156 /**
157  * Generate a string containing the name of the passed function.
158  *
159  * Params:
160  *     func = The function to inspect.
161  */
162 private template MethodName(func...) if (func.length == 1 && isCallable!(func))
163 {
164 	enum MethodName = __traits(identifier, func);
165 }
166 
167 unittest
168 {
169 	class T
170 	{
171 		public void method1(){}
172 		public void method2(){}
173 		public void method3(){}
174 	}
175 
176 	MethodName!(T.method1).assertEqual("method1");
177 	MethodName!(T.method2).assertEqual("method2");
178 	MethodName!(T.method3).assertEqual("method3");
179 }
180 
181 /**
182  * Generate a string array containing the storage classes of each parameter (if any) of the passed function.
183  *
184  * Params:
185  *     func = The function to inspect.
186  */
187 private template MethodParameterStorageClasses(func...) if (func.length == 1 && isCallable!(func))
188 {
189 	private string[] getMethodParameterStorageClasses()
190 	{
191 		string[] storageClasses;
192 		string code;
193 
194 		foreach (storageClass; ParameterStorageClassTuple!(func))
195 		{
196 			code = "";
197 
198 			static if (storageClass == ParameterStorageClass.scope_)
199 			{
200 				code ~= "scope ";
201 			}
202 
203 			static if (storageClass == ParameterStorageClass.lazy_)
204 			{
205 				code ~= "lazy ";
206 			}
207 
208 			static if (storageClass == ParameterStorageClass.out_)
209 			{
210 				code ~= "out ";
211 			}
212 
213 			static if (storageClass == ParameterStorageClass.ref_)
214 			{
215 				code ~= "ref ";
216 			}
217 
218 			storageClasses ~= code;
219 		}
220 
221 		return storageClasses;
222 	}
223 	enum MethodParameterStorageClasses = getMethodParameterStorageClasses();
224 }
225 
226 unittest
227 {
228 	class T
229 	{
230 		public void method1(scope int* foo){}
231 		public void method2(lazy int bar){}
232 		public void method3(out int baz){}
233 		public void method4(ref int qux){}
234 	}
235 
236 	MethodParameterStorageClasses!(T.method1).assertEqual(["scope "]);
237 	MethodParameterStorageClasses!(T.method2).assertEqual(["lazy "]);
238 	MethodParameterStorageClasses!(T.method3).assertEqual(["out "]);
239 	MethodParameterStorageClasses!(T.method4).assertEqual(["ref "]);
240 }
241 
242 /**
243  * Generate a string array containing the parameter types of the passed function.
244  *
245  * Params:
246  *     func = The function to inspect.
247  */
248 private template MethodParameterTypes(func...) if (func.length == 1 && isCallable!(func))
249 {
250 	private string[] getMethodParameterTypes()
251 	{
252 		string[] types;
253 
254 		foreach (type; ParameterTypeTuple!(func))
255 		{
256 			types ~= type.stringof;
257 		}
258 
259 		return types;
260 	}
261 	enum MethodParameterTypes = getMethodParameterTypes();
262 }
263 
264 unittest
265 {
266 	class T
267 	{
268 		public void method1(const int foo){}
269 		public void method2(string bar){}
270 		public void method3(bool baz){}
271 	}
272 
273 	MethodParameterTypes!(T.method1).assertEqual(["const(int)"]);
274 	MethodParameterTypes!(T.method2).assertEqual(["string"]);
275 	MethodParameterTypes!(T.method3).assertEqual(["bool"]);
276 }
277 
278 /**
279  * Generate a string array containing the parameter identifiers of the passed function.
280  *
281  * Params:
282  *     func = The function to inspect.
283  */
284 private template MethodParameterIdentifiers(func...) if (func.length == 1 && isCallable!(func))
285 {
286 	private string[] getMethodParameterIdentifiers()
287 	{
288 		string[] names;
289 
290 		foreach (name; ParameterIdentifierTuple!(func))
291 		{
292 			names ~= name;
293 		}
294 
295 		return names;
296 	}
297 	enum MethodParameterIdentifiers = getMethodParameterIdentifiers();
298 }
299 
300 unittest
301 {
302 	class T
303 	{
304 		public void method1(const int foo){}
305 		public void method2(string bar){}
306 		public void method3(bool baz){}
307 	}
308 
309 	MethodParameterIdentifiers!(T.method1).assertEqual(["foo"]);
310 	MethodParameterIdentifiers!(T.method2).assertEqual(["bar"]);
311 	MethodParameterIdentifiers!(T.method3).assertEqual(["baz"]);
312 }
313 
314 /**
315  * Generate a string array containing the default values of each parameter (if any) of the passed function.
316  *
317  * Params:
318  *     func = The function to inspect.
319  */
320 private template MethodParameterDefaultValues(func...) if (func.length == 1 && isCallable!(func))
321 {
322 	private string[] getMethodParameterDefaultValues()
323 	{
324 		string[] defaultValues;
325 
326 		foreach (defaultValue; ParameterDefaultValueTuple!(func))
327 		{
328 			static if (is(defaultValue == void))
329 			{
330 				defaultValues ~= "";
331 			}
332 			else
333 			{
334 				defaultValues ~= " = " ~ defaultValue.stringof;
335 			}
336 		}
337 
338 		return defaultValues;
339 	}
340 	enum MethodParameterDefaultValues = getMethodParameterDefaultValues();
341 }
342 
343 unittest
344 {
345 	class T
346 	{
347 		public void method1(const int foo){}
348 		public void method2(string bar = "qux"){}
349 		public void method3(bool baz = true){}
350 	}
351 
352 	MethodParameterDefaultValues!(T.method1).assertEqual([""]);
353 	MethodParameterDefaultValues!(T.method2).assertEqual([" = \"qux\""]);
354 	MethodParameterDefaultValues!(T.method3).assertEqual([" = true"]);
355 }
356 
357 /**
358  * Generate a string containing the full parameter signature of the passed function.
359  *
360  * Params:
361  *     func = The function to inspect.
362  */
363 private template MethodParameters(func...) if (func.length == 1 && isCallable!(func))
364 {
365 	private string getMethodParameters()
366 	{
367 		string[] storageClasses = MethodParameterStorageClasses!(func);
368 		string[] types          = MethodParameterTypes!(func);
369 		string[] names          = MethodParameterIdentifiers!(func);
370 		string[] defaultValues  = MethodParameterDefaultValues!(func);
371 
372 		string[] parameters;
373 
374 		foreach (storageClass, type, name, defaultValue; zip(storageClasses, types, names, defaultValues))
375 		{
376 			parameters ~= format("%s%s %s%s", storageClass, type, name, defaultValue);
377 		}
378 
379 		return format("(%s)", parameters.join(", "));
380 	}
381 	enum MethodParameters = getMethodParameters();
382 }
383 
384 unittest
385 {
386 	class T
387 	{
388 		public void method1(const int foo){}
389 		public void method2(string bar = "qux"){}
390 		public void method3(bool baz = true){}
391 	}
392 
393 	MethodParameters!(T.method1).assertEqual("(const(int) foo)");
394 	MethodParameters!(T.method2).assertEqual("(string bar = \"qux\")");
395 	MethodParameters!(T.method3).assertEqual("(bool baz = true)");
396 }
397 
398 /**
399  * Generate a string containing the mangled name of the passed function.
400  *
401  * Params:
402  *     func = The function to inspect.
403  */
404 private template MethodMangledName(func...) if (func.length == 1 && isCallable!(func))
405 {
406 	enum MethodMangledName = mangledName!(func);
407 }
408 
409 /**
410  * Returns true if the passed function is nothrow, false if not.
411  *
412  * Params:
413  *     func = The function to inspect.
414  */
415 private template isMethodNoThrow(func...) if (func.length == 1 && isCallable!(func))
416 {
417 	enum isMethodNoThrow = cast(bool)(functionAttributes!(func) & FunctionAttribute.nothrow_);
418 }
419 
420 unittest
421 {
422 	class T
423 	{
424 		public void method1() nothrow {}
425 		public void method2() {}
426 	}
427 
428 	isMethodNoThrow!(T.method1).assertTrue();
429 	isMethodNoThrow!(T.method2).assertFalse();
430 }
431 
432 /**
433  * Returns true if the passed function is const, false if not.
434  *
435  * Params:
436  *     func = The function to inspect.
437  */
438 private template isMethodConst(func...) if (func.length == 1 && isCallable!(func))
439 {
440 	enum isMethodConst = !isMutable!(FunctionTypeOf!(func));
441 }
442 
443 unittest
444 {
445 	class T
446 	{
447 		public void method1() const {}
448 		public void method2() immutable {}
449 		public void method3(){}
450 	}
451 
452 	isMethodConst!(T.method1).assertTrue();
453 	isMethodConst!(T.method2).assertTrue();
454 	isMethodConst!(T.method3).assertFalse();
455 }
456 
457 /**
458  * Returns true if the passed function is shared or synchronized, false if not.
459  *
460  * Params:
461  *     func = The function to inspect.
462  */
463 private template isMethodShared(func...) if (func.length == 1 && isCallable!(func))
464 {
465 	enum isMethodShared = is(shared(FunctionTypeOf!(func)) == FunctionTypeOf!(func));
466 }
467 
468 unittest
469 {
470 	static class T
471 	{
472 		public synchronized void method1() {}
473 		public shared void method2(int value) {}
474 		public shared void method3(int value) const pure nothrow @safe @property {}
475 		public shared shared(T) method4() { return null; }
476 		public shared(T) method5() { return null; }
477 		public void method6() {}
478 	}
479 
480 	isMethodShared!(T.method1).assertTrue();
481 	isMethodShared!(T.method2).assertTrue();
482 	isMethodShared!(T.method3).assertTrue();
483 	isMethodShared!(T.method4).assertTrue();
484 	isMethodShared!(T.method5).assertFalse();
485 	isMethodShared!(T.method6).assertFalse();
486 }
487 
488 /**
489  * Generate a string containing the body of the passed function.
490  *
491  * Params:
492  *     hasParent = true if this function is replacing a parent implementation.
493  *     func = The function to inspect and generate code for.
494  */
495 private template MethodBody(bool hasParent, func...)
496 {
497 	private string getMethodBody()
498 	{
499 		string code = "";
500 		code ~= "\ttry\n";
501 		code ~= "\t{\n";
502 
503 		static if (!isMethodConst!(func))
504 		{
505 			code ~= "\t\tif (\"" ~ MethodSignature!(func) ~ "\" in this._methodCount)\n";
506 			code ~= "\t\t{\n";
507 			code ~= "\t\t\tthis._methodCount[\"" ~ MethodSignature!(func) ~ "\"].actual++;\n";
508 			code ~= "\t\t}\n";
509 		}
510 
511 		code ~= "\t\tif (this." ~ MethodMangledName!(func) ~ ")\n";
512 		code ~= "\t\t{\n";
513 		code ~= "\t\t\treturn this." ~ MethodMangledName!(func) ~ "(" ~ MethodParameterIdentifiers!(func).join(", ") ~ ");\n";
514 		code ~= "\t\t}\n";
515 		code ~= "\t\telse\n";
516 		code ~= "\t\t{\n";
517 
518 		static if (hasParent)
519 		{
520 			code ~= "\t\t\tif (this._useParentMethods)\n";
521 			code ~= "\t\t\t{\n";
522 			code ~= "\t\t\t\treturn super." ~ MethodName!(func) ~ "(" ~ MethodParameterIdentifiers!(func).join(", ") ~ ");\n";
523 			code ~= "\t\t\t}\n";
524 			code ~= "\t\t\telse\n";
525 			code ~= "\t\t\t{\n";
526 			code ~= "\t\t\t\tauto error = new DUnitAssertError(\"Mock method not implemented\", this._disableMethodsLocation.file, this._disableMethodsLocation.line);\n";
527 			code ~= "\t\t\t\terror.addInfo(\"Method\", this.className ~ \"." ~ MethodSignature!(func) ~ "\");\n";
528 			code ~= "\t\t\t\tthrow error;\n";
529 			code ~= "\t\t\t}\n";
530 		}
531 		else
532 		{
533 			code ~= "\t\t\t\tauto error = new DUnitAssertError(\"Mock method not implemented\", this._disableMethodsLocation.file, this._disableMethodsLocation.line);\n";
534 			code ~= "\t\t\t\terror.addInfo(\"Method\", this.className ~ \"." ~ MethodSignature!(func) ~ "\");\n";
535 			code ~= "\t\t\t\tthrow error;\n";
536 		}
537 
538 		code ~= "\t\t}\n";
539 		code ~= "\t}\n";
540 		code ~= "\tcatch(Exception ex)\n";
541 		code ~= "\t{\n";
542 
543 		static if (isMethodNoThrow!(func))
544 		{
545 			code ~= "\t\tassert(false, ex.msg);\n";
546 		}
547 		else
548 		{
549 			code ~= "\t\tthrow ex;\n";
550 		}
551 
552 		code ~= "\t}\n";
553 		code ~= "\tassert(false, \"Critical error occurred!\");\n";
554 		return code;
555 	}
556 	enum MethodBody = getMethodBody();
557 }
558 
559 /**
560  * Generate a string containing the code for a delegate property.
561  *
562  * Params:
563  *     func = The function to inspect.
564  */
565 private template MethodDelegateProperty(func...) if (func.length == 1 && isCallable!(func))
566 {
567 	private string getMethodDelegateProperty()
568 	{
569 		return format("private %s %s;\n", MethodDelegateSignature!(func), MethodMangledName!(func));
570 	}
571 	enum MethodDelegateProperty = getMethodDelegateProperty();
572 }
573 
574 /**
575  * Generate a string containing the entire code for the passed method.
576  *
577  * Params:
578  *     hasParent = true if this function is replacing a parent implementation.
579  *     func = The function to inspect and generate code for.
580  */
581 private template Method(bool hasParent, func...) if (func.length == 1 && isCallable!(func))
582 {
583 	private string getMethod()
584 	{
585 		string code = "";
586 
587 		static if (hasParent)
588 		{
589 			code ~= "override ";
590 		}
591 
592 		code ~= MethodProtection!(func) ~ " ";
593 		code ~= MethodAttributes!(func) ~ " ";
594 		code ~= MethodReturnType!(func) ~ " ";
595 		code ~= MethodName!(func);
596 		code ~= MethodParameters!(func) ~ (isMethodConst!(func) ? " const \n" : "\n");
597 		code ~= "{\n";
598 		code ~= MethodBody!(hasParent, func);
599 		code ~= "}\n";
600 		return code;
601 	}
602 	enum Method = getMethod();
603 }
604 
605 /**
606  * Iterate through the methods of T generating code using the generator.
607  *
608  * Params:
609  *     T = The class to inspect.
610  *     generator = The template to use to generate code for each method.
611  *     index = The beginning index of the members.
612  */
613 public template DUnitMethodIterator(T, string generator, int index = 0) if (is(T == class) || is(T == interface))
614 {
615 	private string getResult()
616 	{
617 		string code = "";
618 		static if (index < __traits(allMembers, T).length)
619 		{
620 			static if (MemberFunctionsTuple!(T, __traits(allMembers, T)[index]).length)
621 			{
622 				foreach (func; __traits(getVirtualMethods, T, __traits(allMembers, T)[index]))
623 				{
624 					static if (!__traits(isFinalFunction, func))
625 					{
626 						mixin("code ~= " ~ generator ~ ";");
627 					}
628 				}
629 			}
630 			code ~= DUnitMethodIterator!(T, generator, index + 1);
631 		}
632 		return code;
633 	}
634 	enum DUnitMethodIterator = getResult();
635 }
636 
637 /**
638  * Generate a string containing the entire override code for the passed constructor.
639  *
640  * Params:
641  *     T = The class to inspect.
642  *     func = The function to inspect.
643  */
644 private template Constructor(T, func...) if (is(T == class) && func.length == 1 && isCallable!(func))
645 {
646 	private string getConstructor()
647 	{
648 		string code = "";
649 		code ~= "this";
650 		code ~= MethodParameters!(func) ~ "\n";
651 		code ~= "{\n";
652 		code ~= "\tsuper(" ~ MethodParameterIdentifiers!(func).join(", ") ~ ");\n";
653 		code ~= "}\n";
654 		return code;
655 	}
656 	enum Constructor = getConstructor();
657 }
658 
659 unittest
660 {
661 	class T
662 	{
663 		this(int foo, int bar)
664 		{
665 		}
666 	}
667 
668 	string code = "this(int foo, int bar)
669 {
670 	super(foo, bar);
671 }\n";
672 
673 	Constructor!(T, T.__ctor).assertEqual(code);
674 }
675 
676 /**
677  * Iterate through the constructors of T generating code using the generator.
678  *
679  * Params:
680  *     T = The class to inspect.
681  *     generator = The template to use to generate code for each constructor.
682  */
683 public template DUnitConstructorIterator(T, string generator) if (is(T == class))
684 {
685 	private string getResult()
686 	{
687 		string code = "";
688 		static if (__traits(hasMember, T, "__ctor"))
689 		{
690 			foreach (func; __traits(getOverloads, T, "__ctor"))
691 			{
692 				mixin("code ~= " ~ generator ~ ";");
693 			}
694 		}
695 		return code;
696 	}
697 	enum DUnitConstructorIterator = getResult();
698 }
699 
700 unittest
701 {
702 	class A
703 	{
704 		this(){}
705 		this(int foo, int bar)
706 		{
707 		}
708 	}
709 
710 	class B {}
711 
712 	string code = "this()
713 {
714 	super();
715 }
716 this(int foo, int bar)
717 {
718 	super(foo, bar);
719 }\n";
720 
721 	DUnitConstructorIterator!(A, "Constructor!(T, func)").assertEqual(code);
722 	DUnitConstructorIterator!(B, "Constructor!(T, func)").assertEqual("");
723 }
724 
725 /**
726  * Generate a string containing the parameter signature of the passed function.
727  *
728  * Params:
729  *     func = The function to inspect.
730  */
731 private template MethodParameterSignature(func...) if (func.length == 1 && isCallable!(func))
732 {
733 	private string getMethodParameterSignature()
734 	{
735 		string[] storageClasses = MethodParameterStorageClasses!(func);
736 		string[] types          = MethodParameterTypes!(func);
737 		string[] parameters;
738 
739 		foreach (storageClass, type; zip(storageClasses, types))
740 		{
741 			parameters ~= format("%s%s", storageClass, type);
742 		}
743 
744 		return parameters.join(", ");
745 	}
746 	enum MethodParameterSignature = getMethodParameterSignature();
747 }
748 
749 unittest
750 {
751 	class T
752 	{
753 		public void method1(const int foo, string bar){}
754 		public void method2(string baz, bool qux){}
755 		public void method3(ref char quux){}
756 	}
757 
758 	MethodParameterSignature!(T.method1).assertEqual("const(int), string");
759 	MethodParameterSignature!(T.method2).assertEqual("string, bool");
760 	MethodParameterSignature!(T.method3).assertEqual("ref char");
761 }
762 
763 /**
764  * Generate a string containing the signature of the passed function.
765  *
766  * Params:
767  *     func = The function to inspect.
768  */
769 private template MethodSignature(func...) if (func.length == 1 && isCallable!(func))
770 {
771 	private string getMethodSignature()
772 	{
773 		return format("%s:%s(%s)", MethodReturnType!(func), MethodName!(func), MethodParameterSignature!(func));
774 	}
775 	enum MethodSignature = getMethodSignature();
776 }
777 
778 unittest
779 {
780 	class T
781 	{
782 		public int method1(const int foo, string bar){return 1;}
783 		public void method2(string baz, bool qux){}
784 		public bool method3(ref char quux){return true;}
785 	}
786 
787 	MethodSignature!(T.method1).assertEqual("int:method1(const(int), string)");
788 	MethodSignature!(T.method2).assertEqual("void:method2(string, bool)");
789 	MethodSignature!(T.method3).assertEqual("bool:method3(ref char)");
790 }
791 
792 /**
793  * Generate a string containing the delegate signature of the passed function.
794  *
795  * Bugs:
796  *     The 'ref' attribute is not supported in the delegate signature due to a compiler bug.
797  *     Once this bug is fixed we can enable it. http://d.puremagic.com/issues/show_bug.cgi?id=5050
798  *
799  * Params:
800  *     func = The function to inspect.
801  */
802 private template MethodDelegateSignature(func...) if (func.length == 1 && isCallable!(func))
803 {
804 	private string getMethodDelegateSignature()
805 	{
806 		return format("%s delegate(%s) %s", MethodReturnType!(func), MethodParameterSignature!(func), MethodAttributes!(func))
807 			.replace(" ref", "")
808 			.stripRight();
809 	}
810 	enum MethodDelegateSignature = getMethodDelegateSignature();
811 }
812 
813 unittest
814 {
815 	interface T
816 	{
817 		public void method1(const int foo, string bar) @safe pure nothrow;
818 		public void method2(string baz, bool qux);
819 		public void method3(ref char quux);
820 		public ref int method4(string bux);
821 	}
822 
823 	MethodDelegateSignature!(T.method1).assertEqual("void delegate(const(int), string) @safe pure nothrow");
824 	MethodDelegateSignature!(T.method2).assertEqual("void delegate(string, bool)");
825 	MethodDelegateSignature!(T.method3).assertEqual("void delegate(ref char)");
826 	MethodDelegateSignature!(T.method4).assertEqual("int delegate(string)");
827 }
828 
829 /**
830  * Generate a string containing the signature switch.
831  *
832  * Params:
833  *     func = The function to inspect.
834  */
835 private template MethodSignatureSwitch(func...) if (func.length == 1 && isCallable!(func))
836 {
837 	private string getMethodSignatureSwitch()
838 	{
839 		string code = "";
840 		code ~= "case \"" ~ MethodSignature!(func) ~ "\":\n";
841 		code ~= "\tthis." ~ MethodMangledName!(func) ~ " = cast(" ~ MethodDelegateSignature!(func) ~ ")delegate_;\n";
842 		code ~= "\tbreak;\n";
843 		return code;
844 	}
845 	enum MethodSignatureSwitch = getMethodSignatureSwitch();
846 }