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     static auto make() {
52         return ImplData(CppRoot.make);
53     }
54 
55     /// Tag an ID with a kind.
56     void tag(size_t id, Kind kind_) {
57         kind[id] = kind_;
58     }
59 
60     /// Lookup the tag for an ID.
61     Kind lookup(size_t id) {
62         if (auto k = id in kind) {
63             return *k;
64         }
65 
66         return Kind.none;
67     }
68 
69     /// Copy an AA of classes.
70     void putForLookup(ref CppClass[FullyQualifiedNameType] other) @trusted {
71         foreach (v; other.byKeyValue) {
72             classes[v.key] = v.value;
73         }
74     }
75 
76     /// Returns: a range containing the class matching fqn, if found.
77     auto lookupClass(FullyQualifiedNameType fqn) @safe {
78         import std.range : only;
79         import std.typecons : NullableRef;
80 
81         typeof(only(NullableRef!CppClass())) rval;
82         if (auto c = fqn in classes) {
83             rval = only(NullableRef!CppClass(c));
84         }
85 
86         return rval;
87     }
88 }
89 
90 struct IncludeHooks {
91     AbsolutePath preInclude;
92     AbsolutePath postInclude;
93 
94     static auto make(T)(T transf) {
95         immutable file_cpp_pre_incl = "_pre_includes";
96         immutable file_cpp_post_incl = "_post_includes";
97 
98         return IncludeHooks(transf.createHeaderFile(file_cpp_pre_incl),
99                 transf.createHeaderFile(file_cpp_post_incl));
100     }
101 }
102 
103 struct Code {
104     enum Kind {
105         hdr,
106         impl,
107     }
108 
109     CppModule cpp;
110     alias cpp this;
111 }
112 
113 struct Mock {
114     // Use to generate a unique filename.
115     CppClassName name;
116     CppNs[] nesting;
117 
118     CppModule cpp;
119     alias cpp this;
120 }
121 
122 struct GtestPrettyPrint {
123     // Use to generate a unique filename.
124     CppClassName name;
125     CppNs[] nesting;
126 
127     CppModule cpp;
128     alias cpp this;
129 }
130 
131 struct GeneratedData {
132     @disable this(this);
133 
134     /// Code kinds that can't be duplicated.
135     Code[Code.Kind] uniqueData;
136 
137     /// All gmocks to write
138     Mock[] gmocks;
139 
140     GtestPrettyPrint[] gtestPPHdr;
141     GtestPrettyPrint[] gtestPPImpl;
142 
143     IncludeHooks includeHooks;
144 
145     auto make(Code.Kind kind) {
146         if (auto c = kind in uniqueData) {
147             return *c;
148         }
149 
150         Code m;
151         m.cpp = (new CppModule).noIndent;
152 
153         uniqueData[kind] = m;
154         return m;
155     }
156 
157     auto makeMock(CppNs[] ns, CppClassName name) {
158         auto m = Mock(name, ns);
159         m.cpp = (new CppModule).noIndent;
160         gmocks ~= m;
161 
162         return m;
163     }
164 
165     auto makeGtestPrettyPrintHdr(CppNs[] ns, CppClassName name) {
166         auto m = GtestPrettyPrint(name, ns);
167         m.cpp = (new CppModule).noIndent;
168         gtestPPHdr ~= m;
169 
170         return m;
171     }
172 
173     auto makeGtestPrettyPrintImpl(CppNs[] ns, CppClassName name) {
174         auto m = GtestPrettyPrint(name, ns);
175         m.cpp = (new CppModule).noIndent;
176         gtestPPImpl ~= m;
177 
178         return m;
179     }
180 }