1 /**
2 Date: 2015-2017, Joakim Brännström
3 License: MPL-2, Mozilla Public License 2.0
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 Utilities for translation, making and generation of test doubles for functions.
7 */
8 module cpptooling.generator.func;
9 
10 import logger = std.experimental.logger;
11 
12 import dsrcgen.cpp : CppModule;
13 
14 import dextool.type : MainInterface;
15 import cpptooling.data : CFunction, CppClass, CppClassName, CppNsStack;
16 
17 @safe:
18 
19 /// Generates a C implementation calling the test double via the matching
20 /// interface.
21 void generateFuncImpl(CFunction f, CppModule impl) {
22     import cpptooling.data : joinParams, joinParamNames, toStringDecl;
23     import dsrcgen.c : E;
24 
25     // assuming that a function declaration void a() in C is meant to be void
26     // a(void), not variadic.
27     string params;
28     auto p_range = f.paramRange();
29     if (p_range.length == 1 && !f.isVariadic || p_range.length > 1) {
30         params = joinParams(p_range);
31     }
32     string names = joinParamNames(f.paramRange());
33 
34     with (impl.func_body(f.returnType.toStringDecl, f.name, params)) {
35         if (f.returnType.toStringDecl == "void") {
36             stmt(E("test_double_inst->" ~ f.name)(names));
37         } else {
38             return_(E("test_double_inst->" ~ f.name)(names));
39         }
40     }
41     impl.sep(2);
42 }
43 
44 /** Create a C++ interface of funcs in range to allow the user to supply an
45  * implementation.
46  */
47 CppClass makeFuncInterface(Tr)(Tr r, const CppClassName main_if) {
48     import cpptooling.data.type : CppNs;
49 
50     return makeFuncInterface(r, main_if, CppNsStack(CppNs[].init));
51 }
52 
53 /** Create a C++ interface of funcs in range to allow the user to supply an
54  * implementation.
55  *
56  * Params:
57  *  r = InputRange of functions the class is intended to wrap.
58  *  name = the name of the class.
59  *  ns = namespace the class reside in
60  */
61 CppClass makeFuncInterface(Tr)(Tr r, const CppClassName name, const CppNsStack ns) {
62     import cpptooling.data.representation;
63     import std.array : array;
64 
65     auto c = CppClass(name, CppInherit[].init, ns);
66     c.put(CppDtor(makeUniqueUSR, CppMethodName("~" ~ name),
67             CppAccess(AccessType.Public), CppVirtualMethod(MemberVirtualType.Virtual)));
68 
69     foreach (f; r) {
70         auto params = f.paramRange().array();
71         if (f.isVariadic) {
72             params = params[0 .. $ - 1];
73         }
74 
75         auto meth_name = CppMethodName(f.name);
76         auto m = CppMethod(f.usr, meth_name, params, f.returnType(), CppAccess(AccessType.Public),
77                 CppConstMethod(false), CppVirtualMethod(MemberVirtualType.Pure));
78 
79         c.put(m);
80     }
81 
82     return c;
83 }