1 module contract.aggregates;
2 
3 
4 import contract;
5 
6 
7 
8 mixin Contract!(TestName("struct.onefield.int"), contract_onefield_int);
9 @ContractFunction(CodeURL("it.c.compile.struct_", "onefield.int"))
10 auto contract_onefield_int(TestMode mode, CursorType)(auto ref CursorType tu) {
11 
12     tu.kind.expect == Cursor.Kind.TranslationUnit;
13     tu.children.expectLength == 1;
14 
15     auto struct_ = tu.child(0);
16     struct_.isDefinition.expect == true;
17     struct_.expectEqual(Cursor.Kind.StructDecl, "Foo");
18     struct_.type.expectEqual(Type.Kind.Record, "struct Foo");
19 
20     printChildren(struct_);
21     struct_.children.expectLength == 1;
22 
23     auto member = struct_.child(0);
24     member.expectEqual(Cursor.Kind.FieldDecl,"i");
25     member.type.expectEqual(Type.Kind.Int, "int");
26 
27     static if(is(CursorType == MockCursor)) return tu;
28 }
29 
30 
31 
32 mixin Contract!(TestName("struct.nested.c"), contract_nested);
33 @ContractFunction(CodeURL("it.c.compile.struct_", "nested"))
34 auto contract_nested(TestMode mode, CursorType)(auto ref CursorType tu) {
35 
36     tu.kind.expect == Cursor.Kind.TranslationUnit;
37     tu.children.expectLength == 1;
38 
39     auto outer = tu.child(0);
40     outer.isDefinition.expect == true;
41     outer.kind.expect == Cursor.Kind.StructDecl;
42     outer.spelling.expect == "Outer";
43     outer.type.kind.expect == Type.Kind.Record;
44     outer.type.spelling.expect == "struct Outer";
45 
46     printChildren(outer);
47     outer.children.expectLength == 3;
48 
49 
50     auto integer = outer.child(0);
51     integer.kind.expect == Cursor.Kind.FieldDecl;
52     integer.spelling.expect == "integer";
53     integer.type.kind.expect == Type.Kind.Int;
54     integer.type.spelling.expect == "int";
55 
56 
57     auto innerStruct = outer.child(1);
58     innerStruct.kind.expect == Cursor.Kind.StructDecl;
59     innerStruct.spelling.expect == "Inner";
60     innerStruct.type.expectEqual(Type.Kind.Record, "struct Inner");
61     innerStruct.type.canonical.expectEqual(Type.Kind.Record, "struct Inner");
62 
63     printChildren(innerStruct);
64     innerStruct.children.expectLength == 1;  // the `x` field
65 
66     auto xfield = innerStruct.child(0);
67     xfield.kind.expect == Cursor.Kind.FieldDecl;
68     xfield.spelling.expect == "x";
69     xfield.type.kind.expect == Type.Kind.Int;
70 
71 
72     auto innerField = outer.child(2);
73     innerField.kind.expect == Cursor.Kind.FieldDecl;
74     innerField.spelling.expect == "inner";
75     printChildren(innerField);
76     innerField.children.expectLength == 1;  // the Inner StructDecl
77 
78     innerField.type.expectEqual(Type.Kind.Elaborated, "struct Inner");
79     innerField.type.canonical.expectEqual(Type.Kind.Record, "struct Inner");
80 
81     auto innerFieldChild = innerField.child(0);
82     innerFieldChild.expect == innerStruct;
83 
84     static if(is(CursorType == MockCursor)) return tu;
85 }
86 
87 
88 // Slightly different from the C version
89 @Tags("cpp")
90 @("struct.nested.cpp")
91 @safe unittest {
92 
93     const tu = parse(
94         Cpp(
95             q{
96                 struct Outer {
97                     int integer;
98                     struct Inner {
99                         int x;
100                     } inner;
101                 };
102             }
103         )
104     );
105 
106     const outer = tu.children[0];
107     printChildren(outer);
108     outer.children.length.should == 3;
109 
110 
111     const integer = outer.children[0];
112     integer.kind.should == Cursor.Kind.FieldDecl;
113     integer.spelling.should == "integer";
114     integer.type.kind.should == Type.Kind.Int;
115     integer.type.spelling.should == "int";
116 
117 
118     const innerStruct = outer.children[1];
119     innerStruct.kind.should == Cursor.Kind.StructDecl;
120     innerStruct.spelling.should == "Inner";
121     printChildren(innerStruct);
122     innerStruct.children.length.should == 1;  // the `x` field
123 
124     innerStruct.type.kind.should == Type.Kind.Record;
125     innerStruct.type.spelling.should == "Outer::Inner";
126     innerStruct.type.canonical.kind.should == Type.Kind.Record;
127     innerStruct.type.canonical.spelling.should == "Outer::Inner";
128 
129     const xfield = innerStruct.children[0];
130     xfield.kind.should == Cursor.Kind.FieldDecl;
131     xfield.spelling.should == "x";
132     xfield.type.kind.should == Type.Kind.Int;
133 
134 
135     const innerField = outer.children[2];
136     innerField.kind.should == Cursor.Kind.FieldDecl;
137     innerField.spelling.should == "inner";
138     printChildren(innerField);
139     innerField.children.length.should == 1;  // the Inner StructDecl
140 
141     innerField.type.kind.should == Type.Kind.Elaborated;
142     innerField.type.spelling.should == "struct Inner";
143     innerField.type.canonical.kind.should == Type.Kind.Record;
144     innerField.type.canonical.spelling.should == "Outer::Inner";
145 
146     innerField.children[0].should == innerStruct;
147 }
148 
149 
150 mixin Contract!(TestName("struct.typedef.name"), contract_typedef_name);
151 @ContractFunction(CodeURL("it.c.compile.struct_", "typedef.name"))
152 auto contract_typedef_name(TestMode mode, CursorType)(auto ref CursorType tu) {
153 
154     tu.kind.expect == Cursor.Kind.TranslationUnit;
155     tu.children.expectLength == 2;
156 
157     auto struct_ = tu.child(0);
158     struct_.isDefinition.expect == true;
159     struct_.kind.expect == Cursor.Kind.StructDecl;
160     struct_.spelling.expect == "TypeDefd_";
161     struct_.type.kind.expect == Type.Kind.Record;
162     struct_.type.spelling.expect == "struct TypeDefd_";
163 
164     auto typedef_ = tu.child(1);
165     typedef_.isDefinition.expect == true;
166     typedef_.kind.expect == Cursor.Kind.TypedefDecl;
167     typedef_.spelling.expect == "TypeDefd";
168     typedef_.type.kind.expect == Type.Kind.Typedef;
169     typedef_.type.spelling.expect == "TypeDefd";
170 
171     typedef_.underlyingType.kind.expect == Type.Kind.Elaborated;
172     typedef_.underlyingType.spelling.expect == "struct TypeDefd_";
173     typedef_.underlyingType.canonical.kind.expect == Type.Kind.Record;
174     typedef_.underlyingType.canonical.spelling.expect == "struct TypeDefd_";
175 
176     printChildren(typedef_);
177     typedef_.children.expectLength == 1;
178     typedef_.children[0].expect == struct_;
179 
180     static if(is(CursorType == MockCursor)) return tu;
181 }
182 
183 
184 mixin Contract!(TestName("struct.typedef.anon"), contract_typedef_anon);
185 @ContractFunction(CodeURL("it.c.compile.struct_", "typedef.anon"))
186 auto contract_typedef_anon(TestMode mode, CursorType)(auto ref CursorType tu) {
187 
188     tu.kind.expect == Cursor.Kind.TranslationUnit;
189     tu.children.expectLength == 4;
190 
191     {
192         auto struct1 = tu.child(0);
193         struct1.isDefinition.expect == true;
194         struct1.kind.expect == Cursor.Kind.StructDecl;
195         struct1.spelling.expect == "";
196         struct1.type.kind.expect == Type.Kind.Record;
197         // the cursor has no spelling but the type does
198         struct1.type.spelling.expect == "Nameless1";
199 
200         struct1.children.expectLength == 3;
201         struct1.child(0).kind.expect == Cursor.Kind.FieldDecl;
202         struct1.child(0).spelling.expect == "x";
203         struct1.child(0).type.kind.expect == Type.Kind.Int;
204         struct1.child(1).kind.expect == Cursor.Kind.FieldDecl;
205         struct1.child(1).spelling.expect == "y";
206         struct1.child(1).type.kind.expect == Type.Kind.Int;
207         struct1.child(2).kind.expect == Cursor.Kind.FieldDecl;
208         struct1.child(2).spelling.expect == "z";
209         struct1.child(2).type.kind.expect == Type.Kind.Int;
210 
211         auto typedef1 = tu.child(1);
212         typedef1.isDefinition.expect == true;
213         typedef1.kind.expect == Cursor.Kind.TypedefDecl;
214         typedef1.spelling.expect == "Nameless1";
215         typedef1.type.kind.expect == Type.Kind.Typedef;
216         typedef1.type.spelling.expect == "Nameless1";
217 
218         typedef1.underlyingType.kind.expect == Type.Kind.Elaborated;
219         typedef1.underlyingType.spelling.expect == "struct Nameless1";
220         typedef1.underlyingType.canonical.kind.expect == Type.Kind.Record;
221         typedef1.underlyingType.canonical.spelling.expect == "Nameless1";
222 
223         printChildren(typedef1);
224         typedef1.children.expectLength == 1;
225         typedef1.children[0].expect == struct1;
226     }
227 
228     {
229         auto struct2 = tu.child(2);
230         struct2.isDefinition.expect == true;
231         struct2.kind.expect == Cursor.Kind.StructDecl;
232         struct2.spelling.expect == "";
233         struct2.type.kind.expect == Type.Kind.Record;
234         struct2.type.spelling.expect == "Nameless2";
235 
236         struct2.children.expectLength == 1;
237         struct2.child(0).kind.expect == Cursor.Kind.FieldDecl;
238         struct2.child(0).spelling.expect == "d";
239         struct2.child(0).type.kind.expect == Type.Kind.Double;
240 
241         auto typedef2 = tu.child(3);
242         typedef2.isDefinition.expect == true;
243         typedef2.kind.expect == Cursor.Kind.TypedefDecl;
244         typedef2.spelling.expect == "Nameless2";
245         typedef2.type.kind.expect == Type.Kind.Typedef;
246         typedef2.type.spelling.expect == "Nameless2";
247 
248         typedef2.underlyingType.kind.expect == Type.Kind.Elaborated;
249         typedef2.underlyingType.spelling.expect == "struct Nameless2";
250         typedef2.underlyingType.canonical.kind.expect == Type.Kind.Record;
251         typedef2.underlyingType.canonical.spelling.expect == "Nameless2";
252 
253         printChildren(typedef2);
254         typedef2.children.expectLength == 1;
255         typedef2.children[0].expect == struct2;
256     }
257 
258     static if(is(CursorType == MockCursor)) return tu;
259 }
260 
261 
262 mixin Contract!(TestName("struct.typedef.before"), contract_typedef_before);
263 @ContractFunction(CodeURL("it.c.compile.struct_", "typedef.before"))
264 auto contract_typedef_before(TestMode mode, CursorType)(auto ref CursorType tu) {
265 
266     tu.kind.expect == Cursor.Kind.TranslationUnit;
267     tu.children.expectLength == 3;
268 
269     // first, a struct declaration with no definition
270     auto struct1 = tu.child(0);
271     struct1.isDefinition.expect == false;
272     struct1.kind.expect == Cursor.Kind.StructDecl;
273     struct1.spelling.expect == "A";
274     struct1.type.kind.expect == Type.Kind.Record;
275     struct1.type.spelling.expect == "struct A";
276 
277     // forward declaration has no children
278     struct1.children.expectLength == 0;
279 
280     auto typedef_ = tu.child(1);
281     typedef_.isDefinition.expect == true;
282     typedef_.kind.expect == Cursor.Kind.TypedefDecl;
283     typedef_.spelling.expect == "B";
284     typedef_.type.kind.expect == Type.Kind.Typedef;
285     typedef_.type.spelling.expect == "B";
286 
287     typedef_.underlyingType.kind.expect == Type.Kind.Elaborated;
288     typedef_.underlyingType.spelling.expect == "struct A";
289     typedef_.underlyingType.canonical.kind.expect == Type.Kind.Record;
290     typedef_.underlyingType.canonical.spelling.expect == "struct A";
291 
292     // then, a struct declaration that is a definition
293     auto struct2 = tu.child(2);
294     struct2.isDefinition.expect == true;
295     struct2.kind.expect == Cursor.Kind.StructDecl;
296     struct2.spelling.expect == "A";
297     struct2.type.kind.expect == Type.Kind.Record;
298     struct2.type.spelling.expect == "struct A";
299 
300     // definition has the child
301     struct2.children.expectLength == 1;
302     auto child = struct2.child(0);
303 
304     child.kind.expect == Cursor.Kind.FieldDecl;
305     child.spelling.expect == "a";
306     child.type.kind.expect == Type.Kind.Int;
307     child.type.spelling.expect == "int";
308 
309     static if(is(CursorType == MockCursor)) return tu;
310 }
311 
312 
313 // TODO: multiple declarations test