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