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 } 344 345 @Tags("contract") 346 @("ctor.copy.definition.only") 347 @safe unittest { 348 const tu = parse( 349 Cpp( 350 q{ 351 template<typename T> 352 struct Struct{ 353 Struct(const Struct& other) {} 354 }; 355 } 356 ) 357 ); 358 359 tu.children.length.should == 1; 360 361 const struct0 = tu.children[0]; 362 struct0.kind.should == Cursor.Kind.ClassTemplate; 363 printChildren(struct0); 364 struct0.children.length.should == 2; 365 366 const templateParam0 = struct0.children[0]; 367 printChildren(templateParam0); 368 templateParam0.kind.should == Cursor.Kind.TemplateTypeParameter; 369 // We named it so it shows up as T, not as type-parameter-0-0 370 templateParam0.type.spelling.should == "T"; 371 372 const ctor = struct0.children[1]; 373 printChildren(ctor); 374 ctor.kind.should == Cursor.Kind.Constructor; 375 376 ctor.children.length.should == 2; 377 const ctorParam = ctor.children[0]; 378 ctorParam.kind.should == Cursor.Kind.ParmDecl; 379 ctorParam.type.kind.should == Type.Kind.LValueReference; 380 // The spelling here is different from the other test below 381 ctorParam.type.spelling.should == "const Struct<T> &"; 382 } 383 384 385 @Tags("contract") 386 @("ctor.copy.definition.declaration") 387 @safe unittest { 388 const tu = parse( 389 Cpp( 390 q{ 391 template <typename> struct Struct; 392 393 template<typename T> 394 struct Struct{ 395 Struct(const Struct& other) {} 396 }; 397 } 398 ) 399 ); 400 401 tu.children.length.should == 2; 402 403 const struct0 = tu.children[0]; 404 struct0.kind.should == Cursor.Kind.ClassTemplate; 405 printChildren(struct0); 406 struct0.children.length.should == 1; 407 408 const templateParam0 = struct0.children[0]; 409 templateParam0.kind.should == Cursor.Kind.TemplateTypeParameter; 410 templateParam0.type.spelling.should == "type-parameter-0-0"; 411 412 const struct1 = tu.children[1]; 413 struct1.kind.should == Cursor.Kind.ClassTemplate; 414 printChildren(struct1); 415 struct1.children.length.should == 2; 416 417 const templateParam1 = struct1.children[0]; 418 printChildren(templateParam1); 419 templateParam1.kind.should == Cursor.Kind.TemplateTypeParameter; 420 templateParam1.type.spelling.should == "T"; 421 422 const ctor = struct1.children[1]; 423 printChildren(ctor); 424 ctor.kind.should == Cursor.Kind.Constructor; 425 ctor.templateParams.length.should == 0; // not a template function 426 ctor.semanticParent.templateParams.length.should == 1; // the `T` 427 ctor.semanticParent.templateParams[0].spelling.should == "T"; 428 429 ctor.children.length.should == 2; 430 const ctorParam = ctor.children[0]; 431 ctorParam.kind.should == Cursor.Kind.ParmDecl; 432 ctorParam.type.kind.should == Type.Kind.LValueReference; 433 434 // The spelling here is different from the other test above. 435 // The class template type paramater is spelled "T" but the _same_ 436 // generic type as a part of a function parameter list gets spelled 437 // "type-parameter-0-0" just because the original definition left out 438 // the type parameter name. 439 440 ctorParam.type.spelling.should == "const Struct<type-parameter-0-0> &"; 441 ctorParam.type.canonical.spelling.should == "const Struct<type-parameter-0-0> &"; 442 } 443 444 445 @Tags("contract") 446 @("pointer to T") 447 @safe unittest { 448 const tu = parse( 449 Cpp( 450 q{ 451 template<typename T> 452 struct Struct { 453 T* data; 454 }; 455 } 456 ) 457 ); 458 459 tu.children.length.should == 1; 460 const struct_ = tu.children[0]; 461 printChildren(struct_); 462 463 struct_.kind.should == Cursor.Kind.ClassTemplate; 464 struct_.spelling.should == "Struct"; 465 struct_.children.length.should == 2; 466 467 struct_.children[0].kind.should == Cursor.Kind.TemplateTypeParameter; 468 struct_.children[0].spelling.should == "T"; 469 470 const data = struct_.children[1]; 471 data.kind.should == Cursor.Kind.FieldDecl; 472 data.spelling.should == "data"; 473 data.type.kind.should == Type.Kind.Pointer; 474 data.type.spelling.should == "T *"; 475 data.type.pointee.kind.should == Type.Kind.Unexposed; 476 data.type.pointee.spelling.should == "T"; 477 } 478 479 @Tags("contract") 480 @("enum") 481 @safe unittest { 482 const tu = parse( 483 Cpp( 484 q{ 485 template<int I> struct Struct { enum { value = I }; }; 486 } 487 ) 488 ); 489 490 tu.children.length.should == 1; 491 const template_ = tu.children[0]; 492 printChildren(template_); 493 494 template_.kind.should == Cursor.Kind.ClassTemplate; 495 template_.children.length.should == 2; 496 template_.children[0].kind.should == Cursor.Kind.NonTypeTemplateParameter; 497 498 const enumDecl = template_.children[1]; 499 enumDecl.kind.should == Cursor.Kind.EnumDecl; 500 printChildren(enumDecl); 501 502 enumDecl.children.length.should == 1; 503 const enumConstantDecl = enumDecl.children[0]; 504 enumConstantDecl.kind.should == Cursor.Kind.EnumConstantDecl; 505 enumConstantDecl.spelling.should == "value"; 506 enumConstantDecl.enumConstantValue.should == 0; // it's a template 507 writelnUt(enumConstantDecl.tokens); 508 } 509 510 511 @Tags("contract") 512 @("value template argument specialisation") 513 @safe unittest { 514 515 import clang: Token; 516 517 const tu = parse( 518 Cpp( 519 q{ 520 template<int I> struct Struct { enum { value = I }; }; 521 template<> struct Struct<42> { using Type = void; }; 522 } 523 ) 524 ); 525 526 tu.children.length.should == 2; 527 const template_ = tu.children[0]; 528 template_.kind.should == Cursor.Kind.ClassTemplate; 529 const struct_ = tu.children[1]; 530 struct_.kind.should == Cursor.Kind.StructDecl; 531 printChildren(struct_); 532 533 struct_.children.length.should == 2; 534 const integerLiteral = struct_.children[0]; 535 integerLiteral.kind.should == Cursor.Kind.IntegerLiteral; 536 integerLiteral.spelling.should == ""; 537 538 integerLiteral.tokens.should == [Token(Token.Kind.Literal, "42")]; 539 } 540 541 542 @Tags("contract") 543 @("using.partial") 544 @safe unittest { 545 546 const tu = parse( 547 Cpp( 548 q{ 549 template<typename T> 550 struct new_allocator { 551 }; 552 553 template<typename _Tp> 554 using __allocator_base = new_allocator<_Tp>; 555 } 556 ) 557 ); 558 559 tu.children.length.should == 2; 560 561 const using = tu.child(1); 562 using.kind.should == Cursor.Kind.TypeAliasTemplateDecl; 563 using.spelling.should == "__allocator_base"; 564 using.type.kind.should == Type.Kind.Invalid; 565 using.type.spelling.should == ""; 566 567 printChildren(using); 568 using.children.length.should == 2; 569 570 const typeParam = using.child(0); 571 typeParam.kind.should == Cursor.Kind.TemplateTypeParameter; 572 typeParam.spelling.should == "_Tp"; 573 typeParam.type.kind.should == Type.Kind.Unexposed; 574 typeParam.spelling.should == "_Tp"; 575 printChildren(typeParam); 576 typeParam.children.length.should == 0; 577 578 const typeAlias = using.child(1); 579 typeAlias.kind.should == Cursor.Kind.TypeAliasDecl; 580 typeAlias.spelling.should == "__allocator_base"; 581 typeAlias.type.kind.should == Type.Kind.Typedef; 582 typeAlias.type.spelling.should == "__allocator_base"; 583 typeAlias.underlyingType.kind.should == Type.Kind.Unexposed; 584 typeAlias.underlyingType.spelling.should == "new_allocator<_Tp>"; 585 typeAlias.underlyingType.canonical.kind.should == Type.Kind.Unexposed; 586 typeAlias.underlyingType.canonical.spelling.should == "new_allocator<type-parameter-0-0>"; 587 printChildren(typeAlias); 588 typeAlias.children.length.should == 2; 589 590 const templateRef = typeAlias.child(0); 591 templateRef.kind.should == Cursor.Kind.TemplateRef; 592 templateRef.spelling.should == "new_allocator"; 593 templateRef.type.kind.should == Type.Kind.Invalid; 594 templateRef.type.spelling.should == ""; 595 printChildren(templateRef); 596 templateRef.children.length.should == 0; 597 598 const typeRef = typeAlias.child(1); 599 typeRef.kind.should == Cursor.Kind.TypeRef; 600 typeRef.spelling.should == "_Tp"; 601 typeRef.type.kind.should == Type.Kind.Unexposed; 602 typeRef.type.spelling.should == "_Tp"; 603 printChildren(typeRef); 604 typeRef.children.length.should == 0; 605 } 606 607 608 @Tags("contract") 609 @("using.complete") 610 @safe unittest { 611 612 const tu = parse( 613 Cpp( 614 q{ 615 template<typename...> using __void_t = void; 616 } 617 ) 618 ); 619 620 tu.children.length.should == 1; 621 622 const using = tu.child(0); 623 using.kind.should == Cursor.Kind.TypeAliasTemplateDecl; 624 using.spelling.should == "__void_t"; 625 using.type.kind.should == Type.Kind.Invalid; 626 using.type.spelling.should == ""; 627 using.underlyingType.kind.should == Type.Kind.Invalid; 628 printChildren(using); 629 using.children.length.should == 2; 630 631 const templateTypeParam = using.child(0); 632 templateTypeParam.kind.should == Cursor.Kind.TemplateTypeParameter; 633 templateTypeParam.spelling.should == ""; 634 templateTypeParam.type.kind.should == Type.Kind.Unexposed; 635 templateTypeParam.type.spelling.should == "type-parameter-0-0"; 636 637 const typeAlias = using.child(1); 638 typeAlias.kind.should == Cursor.Kind.TypeAliasDecl; 639 typeAlias.spelling.should == "__void_t"; 640 typeAlias.type.kind.should == Type.Kind.Typedef; 641 typeAlias.type.spelling.should == "__void_t"; 642 typeAlias.underlyingType.kind.should == Type.Kind.Void; 643 typeAlias.underlyingType.spelling.should == "void"; 644 } 645 646 647 @Tags("contract") 648 @("function.equals") 649 @safe unittest { 650 651 const tu = parse( 652 Cpp( 653 q{ 654 struct Foo { 655 template<typename T0, typename T1> 656 bool equals(T0 lhs, T1 rhs); 657 }; 658 } 659 ) 660 ); 661 662 tu.children.length.should == 1; 663 const struct_ = tu.child(0); 664 665 struct_.shouldMatch(Cursor.Kind.StructDecl, "Foo"); 666 printChildren(struct_); 667 struct_.children.length.should == 1; 668 669 const func = struct_.child(0); 670 func.shouldMatch(Cursor.Kind.FunctionTemplate, "equals"); 671 func.type.shouldMatch(Type.Kind.FunctionProto, "bool (T0, T1)"); 672 printChildren(func); 673 func.children.length.should == 4; 674 675 const t0 = func.child(0); 676 t0.shouldMatch(Cursor.Kind.TemplateTypeParameter, "T0"); 677 t0.type.shouldMatch(Type.Kind.Unexposed, "T0"); 678 t0.children.length.should == 0; 679 680 const t1 = func.child(1); 681 t1.shouldMatch(Cursor.Kind.TemplateTypeParameter, "T1"); 682 t1.type.shouldMatch(Type.Kind.Unexposed, "T1"); 683 t1.children.length.should == 0; 684 685 const lhs = func.child(2); 686 lhs.shouldMatch(Cursor.Kind.ParmDecl, "lhs"); 687 lhs.type.shouldMatch(Type.Kind.Unexposed, "T0"); 688 printChildren(lhs); 689 lhs.children.length.should == 1; 690 const typeRef0 = lhs.child(0); 691 typeRef0.shouldMatch(Cursor.Kind.TypeRef, "T0"); 692 typeRef0.type.shouldMatch(Type.Kind.Unexposed,"T0"); 693 694 const rhs = func.child(3); 695 rhs.shouldMatch(Cursor.Kind.ParmDecl, "rhs"); 696 rhs.type.shouldMatch(Type.Kind.Unexposed, "T1"); 697 printChildren(rhs); 698 rhs.children.length.should == 1; 699 const typeRef1 = rhs.child(0); 700 typeRef1.shouldMatch(Cursor.Kind.TypeRef, "T1"); 701 typeRef1.type.shouldMatch(Type.Kind.Unexposed,"T1"); 702 } 703 704 705 @Tags("contract") 706 @("function.ctor") 707 @safe unittest { 708 709 const tu = parse( 710 Cpp( 711 q{ 712 template<typename T> 713 struct Foo { 714 template<typename U> 715 Foo(const Foo<U>& other); 716 }; 717 } 718 ) 719 ); 720 721 tu.children.length.should == 1; 722 const struct_ = tu.child(0); 723 724 struct_.shouldMatch(Cursor.Kind.ClassTemplate, "Foo"); 725 printChildren(struct_); 726 struct_.children.length.should == 2; 727 728 const T = struct_.child(0); 729 T.shouldMatch(Cursor.Kind.TemplateTypeParameter, "T"); 730 printChildren(T); 731 T.children.length.should == 0; 732 733 const ctor = struct_.child(1); 734 // being a template makes it not be a Cursor.Kind.Constructor 735 ctor.shouldMatch(Cursor.Kind.FunctionTemplate, "Foo<T>"); 736 ctor.type.shouldMatch(Type.Kind.FunctionProto, "void (const Foo<U> &)"); 737 printChildren(ctor); 738 ctor.children.length.should == 2; 739 740 const U = ctor.child(0); 741 U.shouldMatch(Cursor.Kind.TemplateTypeParameter, "U"); 742 U.type.shouldMatch(Type.Kind.Unexposed, "U"); 743 printChildren(U); 744 U.children.length.should == 0; 745 746 const other = ctor.child(1); 747 other.shouldMatch(Cursor.Kind.ParmDecl, "other"); 748 other.type.shouldMatch(Type.Kind.LValueReference, "const Foo<U> &"); 749 other.type.isConstQualified.should == false; 750 other.type.pointee.shouldMatch(Type.Kind.Unexposed, "const Foo<U>"); 751 other.type.pointee.isConstQualified.should == true; 752 } 753 754 755 @Tags("contract") 756 @("functionproto") 757 @safe unittest { 758 import std.array: array; 759 760 const tu = parse( 761 Cpp( 762 q{ 763 template<typename T> 764 struct Template {}; 765 766 void foo(const Template<double(int)>& arg0); 767 } 768 ) 769 ); 770 771 tu.children.length.should == 2; 772 773 const foo = tu.child(1); 774 foo.shouldMatch(Cursor.Kind.FunctionDecl, "foo"); 775 foo.type.shouldMatch(Type.Kind.FunctionProto, "void (const Template<double (int)> &)"); 776 777 const fooParams = foo.type.paramTypes.array; 778 fooParams.length.should == 1; 779 780 const arg0 = fooParams[0]; 781 writelnUt("arg0: ", arg0); 782 arg0.shouldMatch(Type.Kind.LValueReference, "const Template<double (int)> &"); 783 784 const unexposed = arg0.pointee; 785 writelnUt("unexposed: ", unexposed); 786 unexposed.shouldMatch(Type.Kind.Unexposed, "const Template<double (int)>"); 787 788 const record = unexposed.canonical; 789 writelnUt("record: ", record); 790 record.shouldMatch(Type.Kind.Record, "const Template<double (int)>"); 791 record.numTemplateArguments.should == 1; 792 793 const functionProto = record.typeTemplateArgument(0); 794 writelnUt("function proto: ", functionProto); 795 functionProto.shouldMatch(Type.Kind.FunctionProto, "double (int)"); 796 797 const functionProtoParams = functionProto.paramTypes.array; 798 writelnUt("functionProtoParams: ", functionProtoParams); 799 functionProtoParams.length.should == 1; 800 const int_ = functionProtoParams[0]; 801 int_.shouldMatch(Type.Kind.Int, "int"); 802 803 const functionProtoReturn = functionProto.returnType; 804 writelnUt("functionProtoReturn: ", functionProtoReturn); 805 functionProtoReturn.shouldMatch(Type.Kind.Double, "double"); 806 807 writelnUt("functionProto pointee: ", functionProto.pointee); 808 }