1 module contract.inheritance;
2 
3 
4 import contract;
5 
6 
7 @Tags("contract")
8 @("single.normal")
9 @safe unittest {
10     const tu = parse(
11         Cpp(
12             q{
13                 struct Base {
14                     int i;
15                 };
16 
17                 struct Derived: public Base {
18                     double d;
19                 };
20             }
21         )
22     );
23 
24     tu.children.length.should == 2;
25 
26     const base = tu.child(0);
27     base.kind.should == Cursor.Kind.StructDecl;
28     base.spelling.should == "Base";
29     base.type.kind.should == Type.Kind.Record;
30     base.type.spelling.should == "Base";
31 
32     printChildren(base);
33     base.children.length.should == 1;
34 
35     const derived = tu.child(1);
36     derived.kind.should == Cursor.Kind.StructDecl;
37     derived.spelling.should == "Derived";
38     derived.type.kind.should == Type.Kind.Record;
39     derived.type.spelling.should == "Derived";
40 
41     printChildren(derived);
42     derived.children.length.should == 2;
43 
44     const j = derived.child(1);
45     j.kind.should == Cursor.Kind.FieldDecl;
46 
47     const baseSpec = derived.child(0);
48     baseSpec.kind.should == Cursor.Kind.CXXBaseSpecifier;
49     baseSpec.spelling.should == "struct Base";
50     baseSpec.type.kind.should == Type.Kind.Record;
51     baseSpec.type.spelling.should == "Base";
52 
53     printChildren(baseSpec);
54     baseSpec.children.length.should == 1;
55 
56     const typeRef = baseSpec.child(0);
57     typeRef.kind.should == Cursor.Kind.TypeRef;
58     typeRef.spelling.should == "struct Base";
59     typeRef.type.kind.should == Type.Kind.Record;
60     typeRef.type.spelling.should == "Base";
61     typeRef.referencedCursor.should == base;
62 
63     printChildren(typeRef);
64     typeRef.children.length.should == 0;
65 }
66 
67 
68 @Tags("contract")
69 @("single.template")
70 @safe unittest {
71     const tu = parse(
72         Cpp(
73             q{
74                 template <typename T>
75                 struct Base {
76                     int i;
77                 };
78 
79                 struct Derived: public Base<int> {
80                     double d;
81                 };
82             }
83         )
84     );
85 
86     tu.children.length.should == 2;
87 
88     const base = tu.child(0);
89     base.kind.should == Cursor.Kind.ClassTemplate;
90     base.spelling.should == "Base";
91     base.type.kind.should == Type.Kind.Invalid;
92     base.type.spelling.should == "";
93 
94     printChildren(base);
95     base.children.length.should == 2; // template type param, field
96 
97     const derived = tu.child(1);
98     derived.kind.should == Cursor.Kind.StructDecl;
99     derived.spelling.should == "Derived";
100     derived.type.kind.should == Type.Kind.Record;
101     derived.type.spelling.should == "Derived";
102 
103     printChildren(derived);
104     derived.children.length.should == 2;
105 
106     const j = derived.child(1);
107     j.kind.should == Cursor.Kind.FieldDecl;
108 
109     const baseSpec = derived.child(0);
110     baseSpec.kind.should == Cursor.Kind.CXXBaseSpecifier;
111     baseSpec.spelling.should == "Base<int>";
112     baseSpec.type.kind.should == Type.Kind.Unexposed; // because it's a template
113     baseSpec.type.spelling.should == "Base<int>";
114     // Here's where the weirdness starts. We try and get back to the original
115     // ClassTemplate cursor here via the baseSpec type, but instead we get a
116     // StructDecl. We need to use the TemplateRef instead.
117     baseSpec.type.declaration.kind.should == Cursor.Kind.StructDecl;
118     baseSpec.type.declaration.spelling.should == "Base";
119     baseSpec.type.declaration.children.length.should == 0;
120 
121     printChildren(baseSpec);
122     baseSpec.children.length.should == 1;
123 
124     import clang.c.index;
125     const templateRef = baseSpec.child(0);
126     templateRef.kind.should == Cursor.Kind.TemplateRef;
127     templateRef.spelling.should == "Base";
128     templateRef.type.kind.should == Type.Kind.Invalid;
129     templateRef.type.spelling.should == "";
130 
131     templateRef.referencedCursor.should == base;
132 
133     printChildren(templateRef);
134     templateRef.children.length.should == 0;
135 }
136 
137 @Tags("contract")
138 @("multiple")
139 @safe unittest {
140     const tu = parse(
141         Cpp(
142             q{
143                 struct Base0 {
144                     int i;
145                 };
146 
147                 struct Base1 {
148                     int j;
149                 };
150 
151                 struct Derived: public Base0, Base1 {
152                     double d;
153                 };
154             }
155         )
156     );
157 
158     tu.children.length.should == 3;
159 
160     const derived = tu.child(2);
161     derived.shouldMatch(Cursor.Kind.StructDecl, "Derived");
162     derived.type.shouldMatch(Type.Kind.Record, "Derived");
163 
164     printChildren(derived);
165     derived.children.length.should == 3;
166 
167     const baseSpec0 = derived.child(0);
168     baseSpec0.shouldMatch(Cursor.Kind.CXXBaseSpecifier, "struct Base0");
169     baseSpec0.type.shouldMatch(Type.Kind.Record, "Base0");
170     printChildren(baseSpec0);
171     baseSpec0.children.length.should == 1;
172 
173     const typeRef0 = baseSpec0.child(0);
174     typeRef0.shouldMatch(Cursor.Kind.TypeRef, "struct Base0");
175     typeRef0.type.shouldMatch(Type.Kind.Record, "Base0");
176     typeRef0.children.length.should == 0;
177 
178     const baseSpec1 = derived.child(1);
179     baseSpec1.shouldMatch(Cursor.Kind.CXXBaseSpecifier, "struct Base1");
180     baseSpec1.type.shouldMatch(Type.Kind.Record, "Base1");
181     printChildren(baseSpec1);
182     baseSpec1.children.length.should == 1;
183 
184     const typeRef1 = baseSpec1.child(0);
185     typeRef1.shouldMatch(Cursor.Kind.TypeRef, "struct Base1");
186     typeRef1.type.shouldMatch(Type.Kind.Record, "Base1");
187     typeRef1.children.length.should == 0;
188 }
189 
190 
191 @Tags("contract")
192 @("using")
193 @safe unittest {
194     const tu = parse(
195         Cpp(
196             q{
197                 struct Base {
198                     Base(int i);
199                 };
200 
201                 struct Derived: Base {
202                     using Base::Base;
203                 };
204             }
205         )
206     );
207 
208     tu.children.length.should == 2;
209 
210     const derived = tu.child(1);
211     derived.shouldMatch(Cursor.Kind.StructDecl, "Derived");
212     derived.type.shouldMatch(Type.Kind.Record, "Derived");
213 
214     printChildren(derived);
215     derived.children.length.should == 2;
216 
217     const using = derived.child(1);
218     using.shouldMatch(Cursor.Kind.UsingDeclaration, "Derived");
219     using.type.shouldMatch(Type.Kind.Invalid, "");
220 
221     printChildren(using);
222     using.children.length.should == 3;
223 
224     const typeRef0 = using.child(0);
225     typeRef0.shouldMatch(Cursor.Kind.TypeRef, "struct Base");
226     typeRef0.type.shouldMatch(Type.Kind.Record, "Base");
227     printChildren(typeRef0);
228     typeRef0.children.length.should == 0;
229 
230     const overloadedDeclRef = using.child(1);
231     overloadedDeclRef.shouldMatch(Cursor.Kind.OverloadedDeclRef, "Derived");
232     overloadedDeclRef.type.shouldMatch(Type.Kind.Invalid, "");
233     overloadedDeclRef.isDefinition.should == false;
234 
235     printChildren(overloadedDeclRef);
236     overloadedDeclRef.children.length.should == 0;
237     overloadedDeclRef.numOverloadedDecls.should == 3;
238 
239     // all of the overloads are constructors. The first two are compiler-generated
240     const moveCtor = overloadedDeclRef.overloadedDecl(0);
241     moveCtor.shouldMatch(Cursor.Kind.Constructor, "Base");
242     moveCtor.type.shouldMatch(Type.Kind.FunctionProto, "void (Base &&)");
243 
244     const copyCtor = overloadedDeclRef.overloadedDecl(1);
245     copyCtor.shouldMatch(Cursor.Kind.Constructor, "Base");
246     copyCtor.type.shouldMatch(Type.Kind.FunctionProto, "void (const Base &)");
247 
248     const userCtor = overloadedDeclRef.overloadedDecl(2);
249     userCtor.shouldMatch(Cursor.Kind.Constructor, "Base");
250     userCtor.type.shouldMatch(Type.Kind.FunctionProto, "void (int)");
251 
252 
253     const typeRef1 = using.child(2);
254     typeRef1.shouldMatch(Cursor.Kind.TypeRef, "struct Base");
255     typeRef1.type.shouldMatch(Type.Kind.Record, "Base");
256     printChildren(typeRef1);
257     typeRef1.children.length.should == 0;
258 }