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 }