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