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