1 /**
2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved.
3 License: MPL-2
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 This Source Code Form is subject to the terms of the Mozilla Public License,
7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain
8 one at http://mozilla.org/MPL/2.0/.
9 */
10 module dextool.plugin.cpptestdouble.backend.type;
11 
12 import cpptooling.data : CppRoot, CppClass, CppMethod, CppCtor, CppDtor, CFunction, CppNamespace;
13 import cpptooling.data.symbol : USRType;
14 
15 import dsrcgen.cpp : CppModule, noIndent;
16 
17 import cpptooling.data.type : CppClassName, CppNs;
18 
19 import dextool.type : AbsolutePath;
20 
21 @safe:
22 
23 enum Kind {
24     none,
25     /// Adapter class
26     adapter,
27     /// gmock class
28     gmock,
29     // generate a pretty print function for the class/struct
30     gtestPrettyPrint,
31     /// interface for globals
32     testDoubleNamespace,
33     testDoubleSingleton,
34     testDoubleInterface,
35 }
36 
37 struct ImplData {
38     import cpptooling.data.type : CppMethodName;
39     import cpptooling.data.symbol.types : FullyQualifiedNameType;
40 
41     CppRoot root;
42 
43     IncludeHooks includeHooks;
44 
45     /// Tagging of nodes in the root determining how they are handled by the
46     /// code generator step.
47     Kind[size_t] kind;
48     /// Classes found during src analysis.
49     CppClass[FullyQualifiedNameType] classes;
50 
51     /// Tag an ID with a kind.
52     void tag(size_t id, Kind kind_) {
53         kind[id] = kind_;
54     }
55 
56     /// Lookup the tag for an ID.
57     Kind lookup(size_t id) {
58         if (auto k = id in kind) {
59             return *k;
60         }
61 
62         return Kind.none;
63     }
64 
65     /// Copy an AA of classes.
66     void putForLookup(ref CppClass[FullyQualifiedNameType] other) @trusted {
67         foreach (v; other.byKeyValue) {
68             classes[v.key] = v.value;
69         }
70     }
71 
72     /// Returns: a range containing the class matching fqn, if found.
73     auto lookupClass(FullyQualifiedNameType fqn) @safe {
74         import std.range : only;
75         import std.typecons : NullableRef;
76 
77         typeof(only(NullableRef!CppClass())) rval;
78         if (auto c = fqn in classes) {
79             rval = only(NullableRef!CppClass(c));
80         }
81 
82         return rval;
83     }
84 }
85 
86 struct IncludeHooks {
87     AbsolutePath preInclude;
88     AbsolutePath postInclude;
89 
90     static auto make(T)(T transf) {
91         immutable file_cpp_pre_incl = "_pre_includes";
92         immutable file_cpp_post_incl = "_post_includes";
93 
94         return IncludeHooks(transf.createHeaderFile(file_cpp_pre_incl),
95                 transf.createHeaderFile(file_cpp_post_incl));
96     }
97 }
98 
99 struct Code {
100     enum Kind {
101         hdr,
102         impl,
103     }
104 
105     CppModule cpp;
106     alias cpp this;
107 }
108 
109 struct Mock {
110     // Use to generate a unique filename.
111     CppClassName name;
112     CppNs[] nesting;
113 
114     CppModule cpp;
115     alias cpp this;
116 }
117 
118 struct GtestPrettyPrint {
119     // Use to generate a unique filename.
120     CppClassName name;
121     CppNs[] nesting;
122 
123     CppModule cpp;
124     alias cpp this;
125 }
126 
127 struct GeneratedData {
128     @disable this(this);
129 
130     /// Code kinds that can't be duplicated.
131     Code[Code.Kind] uniqueData;
132 
133     /// All gmocks to write
134     Mock[] gmocks;
135 
136     GtestPrettyPrint[] gtestPPHdr;
137     GtestPrettyPrint[] gtestPPImpl;
138 
139     IncludeHooks includeHooks;
140 
141     auto make(Code.Kind kind) {
142         if (auto c = kind in uniqueData) {
143             return *c;
144         }
145 
146         Code m;
147         m.cpp = (new CppModule).noIndent;
148 
149         uniqueData[kind] = m;
150         return m;
151     }
152 
153     auto makeMock(CppNs[] ns, CppClassName name) {
154         auto m = Mock(name, ns);
155         m.cpp = (new CppModule).noIndent;
156         gmocks ~= m;
157 
158         return m;
159     }
160 
161     auto makeGtestPrettyPrintHdr(CppNs[] ns, CppClassName name) {
162         auto m = GtestPrettyPrint(name, ns);
163         m.cpp = (new CppModule).noIndent;
164         gtestPPHdr ~= m;
165 
166         return m;
167     }
168 
169     auto makeGtestPrettyPrintImpl(CppNs[] ns, CppClassName name) {
170         auto m = GtestPrettyPrint(name, ns);
171         m.cpp = (new CppModule).noIndent;
172         gtestPPImpl ~= m;
173 
174         return m;
175     }
176 }