1 module contract.templates; 2 3 4 import contract; 5 6 7 @Tags("contract") 8 @("Partial and full template specialisation") 9 @safe unittest { 10 const tu = parse( 11 Cpp( 12 q{ 13 struct Foo; struct Bar; struct Baz; struct Quux; 14 15 template<typename, typename, bool, typename, int, typename> 16 struct Template { using Type = bool; }; 17 18 template<typename T, bool V0, typename T3, typename T4> 19 struct Template<Quux, T, V0, T3, 42, T4> { using Type = short; }; 20 21 template<typename T, bool V0, typename T3, typename T4> 22 struct Template<T, Quux, V0, T3, 42, T4> { using Type = double; }; 23 24 template<> 25 struct Template<Quux, Baz, true, Bar, 33, Foo> { using Type = float; }; 26 } 27 ) 28 ); 29 30 tu.children.length.shouldEqual(8); 31 32 auto structs = tu.children[0 .. 4]; // Foo, Bar, Baz, Quux 33 auto template_ = tu.children[4]; // The full or pure template 34 auto partials = tu.children[5 .. 7]; // The partial template specialisations 35 auto full = tu.children[7]; // The last Template declaration 36 37 foreach(struct_; structs) { 38 struct_.kind.should == Cursor.Kind.StructDecl; 39 struct_.type.numTemplateArguments.should == -1; 40 } 41 42 template_.kind.should == Cursor.Kind.ClassTemplate; 43 // The actual template, according to clang, has no template arguments 44 template_.type.numTemplateArguments.should == -1; 45 // To get the template parameters, one must look at the ClassTemplate's children 46 template_.children.length.should == 7; 47 printChildren(template_); 48 49 const typeAliasDecl = template_.children[$ - 1]; 50 typeAliasDecl.kind.should == Cursor.Kind.TypeAliasDecl; 51 52 const templateParameters = template_.children[0 .. $ - 1]; 53 templateParameters[0].kind.should == Cursor.Kind.TemplateTypeParameter; 54 templateParameters[1].kind.should == Cursor.Kind.TemplateTypeParameter; 55 templateParameters[2].kind.should == Cursor.Kind.NonTypeTemplateParameter; 56 templateParameters[3].kind.should == Cursor.Kind.TemplateTypeParameter; // bool 57 templateParameters[4].kind.should == Cursor.Kind.NonTypeTemplateParameter; 58 templateParameters[5].kind.should == Cursor.Kind.TemplateTypeParameter; // int 59 60 foreach(partial; partials) { 61 partial.kind.should == Cursor.Kind.ClassTemplatePartialSpecialization; 62 partial.type.numTemplateArguments.should == 6; 63 partial.specializedCursorTemplate.should == template_; 64 } 65 66 full.kind.should == Cursor.Kind.StructDecl; 67 full.type.numTemplateArguments.should == 6; 68 } 69 70 71 72 @Tags("contract") 73 @("variadic.only.types") 74 @safe unittest { 75 import clang: Token; 76 77 const tu = parse( 78 Cpp( 79 q{ 80 template<typename...> 81 struct Variadic {}; 82 } 83 ) 84 ); 85 86 tu.children.length.shouldEqual(1); 87 88 const variadic = tu.children[0]; 89 printChildren(variadic); 90 91 variadic.kind.should == Cursor.Kind.ClassTemplate; 92 variadic.type.numTemplateArguments.should == -1; 93 94 // variadic templates can't use the children to figure out how many template 95 // arguments there are, since there's only one "typename" and the length 96 // can be any number. 97 variadic.children.length.should == 1; 98 const templateParameter = variadic.children[0]; 99 100 templateParameter.kind.should == Cursor.Kind.TemplateTypeParameter; 101 templateParameter.type.kind.should == Type.Kind.Unexposed; 102 templateParameter.type.canonical.kind.should == Type.Kind.Unexposed; 103 templateParameter.type.spelling.should == "type-parameter-0-0"; 104 105 Token(Token.Kind.Punctuation, "...").should.be in variadic.tokens; 106 } 107 108 @Tags("contract") 109 @("variadic.only.values") 110 @safe unittest { 111 import clang: Token; 112 113 const tu = parse( 114 Cpp( 115 q{ 116 template<int...> 117 struct Variadic {}; 118 } 119 ) 120 ); 121 122 tu.children.length.shouldEqual(1); 123 124 const variadic = tu.children[0]; 125 printChildren(variadic); 126 127 variadic.kind.should == Cursor.Kind.ClassTemplate; 128 variadic.type.numTemplateArguments.should == -1; 129 130 // variadic templates can't use the children to figure out how many template 131 // arguments there are, since there's only one "typename" and the length 132 // can be any number. 133 variadic.children.length.should == 1; 134 const templateParameter = variadic.children[0]; 135 136 templateParameter.kind.should == Cursor.Kind.NonTypeTemplateParameter; 137 templateParameter.type.kind.should == Type.Kind.Int; 138 templateParameter.type.canonical.kind.should == Type.Kind.Int; 139 templateParameter.type.spelling.should == "int"; 140 141 Token(Token.Kind.Punctuation, "...").should.be in variadic.tokens; 142 } 143 144 @Tags("contract") 145 @("variadic.also.types") 146 @safe unittest { 147 import clang: Token; 148 149 const tu = parse( 150 Cpp( 151 q{ 152 template<int, typename, bool, typename...> 153 struct Variadic {}; 154 } 155 ) 156 ); 157 158 tu.children.length.shouldEqual(1); 159 160 const variadic = tu.children[0]; 161 printChildren(variadic); 162 163 variadic.kind.should == Cursor.Kind.ClassTemplate; 164 variadic.type.numTemplateArguments.should == -1; 165 166 // variadic templates can't use the children to figure out how many template 167 // arguments there are, since there's only one "typename" and the length 168 // can be any number. 169 variadic.children.length.should == 4; 170 const intParam = variadic.children[0]; 171 const typeParam = variadic.children[1]; 172 const boolParam = variadic.children[2]; 173 const restParam = variadic.children[3]; 174 175 intParam.kind.should == Cursor.Kind.NonTypeTemplateParameter; 176 intParam.type.kind.should == Type.Kind.Int; 177 178 typeParam.kind.should == Cursor.Kind.TemplateTypeParameter; 179 typeParam.type.kind.should == Type.Kind.Unexposed; 180 typeParam.spelling.should == ""; 181 182 boolParam.kind.should == Cursor.Kind.NonTypeTemplateParameter; 183 boolParam.type.kind.should == Type.Kind.Bool; 184 185 restParam.kind.should == Cursor.Kind.TemplateTypeParameter; 186 restParam.type.kind.should == Type.Kind.Unexposed; 187 restParam.type.spelling.should == "type-parameter-0-3"; 188 189 Token(Token.Kind.Punctuation, "...").should.be in variadic.tokens; 190 } 191 192 @Tags("contract") 193 @("variadic.also.values") 194 @safe unittest { 195 import clang: Token; 196 197 const tu = parse( 198 Cpp( 199 q{ 200 template<int, typename, bool, short...> 201 struct Variadic {}; 202 } 203 ) 204 ); 205 206 tu.children.length.shouldEqual(1); 207 208 const variadic = tu.children[0]; 209 printChildren(variadic); 210 211 variadic.kind.should == Cursor.Kind.ClassTemplate; 212 variadic.type.numTemplateArguments.should == -1; 213 214 // variadic templates can't use the children to figure out how many template 215 // arguments there are, since there's only one "typename" and the length 216 // can be any number. 217 variadic.children.length.should == 4; 218 const intParam = variadic.children[0]; 219 const typeParam = variadic.children[1]; 220 const boolParam = variadic.children[2]; 221 const restParam = variadic.children[3]; 222 223 intParam.kind.should == Cursor.Kind.NonTypeTemplateParameter; 224 intParam.type.kind.should == Type.Kind.Int; 225 226 typeParam.kind.should == Cursor.Kind.TemplateTypeParameter; 227 typeParam.type.kind.should == Type.Kind.Unexposed; 228 typeParam.spelling.should == ""; 229 230 boolParam.kind.should == Cursor.Kind.NonTypeTemplateParameter; 231 boolParam.type.kind.should == Type.Kind.Bool; 232 233 restParam.kind.should == Cursor.Kind.NonTypeTemplateParameter; 234 restParam.type.kind.should == Type.Kind.Short; 235 restParam.type.spelling.should == "short"; 236 237 Token(Token.Kind.Punctuation, "...").should.be in variadic.tokens; 238 } 239 240 241 242 @Tags("contract") 243 @("variadic.specialization") 244 @safe unittest { 245 import clang: Token; 246 247 const tu = parse( 248 Cpp( 249 q{ 250 template<typename...> 251 struct Variadic {}; 252 253 template<typename T0, typename T1> 254 struct Variadic<T0, T1> { }; 255 } 256 ) 257 ); 258 259 tu.children.length.shouldEqual(2); 260 261 const template_ = tu.children[0]; 262 printChildren(template_); 263 264 const special = tu.children[1]; 265 printChildren(special); 266 267 special.kind.should == Cursor.Kind.ClassTemplatePartialSpecialization; 268 special.type.numTemplateArguments.should == 2; 269 // unexposed - non-specialised type 270 special.type.typeTemplateArgument(0).kind.should == Type.Kind.Unexposed; 271 special.type.typeTemplateArgument(1).kind.should == Type.Kind.Unexposed; 272 } 273 274 275 @Tags("contract") 276 @("lref") 277 @safe unittest { 278 const tu = parse( 279 Cpp( 280 q{ 281 template<typename> 282 struct Struct{}; 283 284 template<typename T> 285 struct Struct<T&> { 286 using Type = T; 287 }; 288 } 289 ) 290 ); 291 292 tu.children.length.shouldEqual(2); 293 294 const general = tu.children[0]; 295 const special = tu.children[1]; 296 297 general.kind.should == Cursor.Kind.ClassTemplate; 298 special.kind.should == Cursor.Kind.ClassTemplatePartialSpecialization; 299 300 special.type.kind.should == Type.Kind.Unexposed; 301 special.type.numTemplateArguments.should == 1; 302 const templateType = special.type.typeTemplateArgument(0); 303 304 templateType.spelling.should == "type-parameter-0-0 &"; 305 } 306 307 308 @Tags("contract") 309 @("ParmDecl") 310 @safe unittest { 311 const tu = parse( 312 Cpp( 313 q{ 314 template<typename> struct Struct{}; 315 template<typename R, typename... A> 316 struct Struct<R(A...)> {}; 317 } 318 ) 319 ); 320 321 tu.children.length.should == 2; 322 const partial = tu.children[1]; 323 324 partial.kind.should == Cursor.Kind.ClassTemplatePartialSpecialization; 325 printChildren(partial); 326 partial.children.length.should == 4; 327 328 partial.children[0].kind.should == Cursor.Kind.TemplateTypeParameter; 329 partial.children[0].spelling.should == "R"; 330 331 partial.children[1].kind.should == Cursor.Kind.TemplateTypeParameter; 332 partial.children[1].spelling.should == "A"; 333 334 partial.children[2].kind.should == Cursor.Kind.TypeRef; 335 partial.children[2].spelling.should == "R"; 336 337 partial.children[3].kind.should == Cursor.Kind.ParmDecl; 338 partial.children[3].spelling.should == ""; 339 340 const parmDecl = partial.children[3]; 341 parmDecl.type.kind.should == Type.Kind.Unexposed; 342 parmDecl.type.spelling.should == "A..."; 343 }