1 /** 2 Date: 2015-2016, Joakim Brännström 3 License: MPL-2, Mozilla Public License 2.0 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 Version: Initial created: Jan 30, 2012 7 Copyright (c) 2012 Jacob Carlborg. All rights reserved. 8 9 # Interaction flow 10 Pass1, implicit anonymous struct and unions. 11 Pass2, struct or union decl who has no name. 12 Pass3, anonymous instantiated types. 13 Pass4, generic, last decision point for deriving data from the cursor. 14 PassType, derive type from the cursors type. 15 16 # Location information 17 The "source" location is only, always the definition. 18 Declarations are "using" locations. 19 20 ## CS101 refresher. 21 A definition is the information needed to create an instance of the type. 22 23 A declaration is a subset of the information that makes it possible to use in most scenarios. 24 The most telling example of an useful declaration is a function declaration, "void foo();". 25 Useful most everywhere. 26 But during linking it must be defined _somewhere_ or a linker error will ensue. 27 28 # Future optimization 29 - Skip the primitive types by having them prepoulated in the Container. 30 - Minimize the amoung of data that is propagated by changing TypeResults to 31 ensure only unique USR's exist in it. 32 - Skip pass4+ if the USR already exist in the container. 33 */ 34 module cpptooling.analyzer.clang.type; 35 36 import std.algorithm : among; 37 import std.conv : to; 38 import std.range : only; 39 import std.string : format; 40 import std.traits; 41 import std.typecons : Flag, Yes, No, Tuple, Nullable; 42 import logger = std.experimental.logger; 43 44 import clang.c.Index : CXTypeKind, CXCursorKind; 45 import clang.Cursor : Cursor; 46 import clang.Type : Type; 47 48 import my.sumtype; 49 import my.optional; 50 51 import libclang_ast.cursor_logger : logNode; 52 53 public import cpptooling.data.kind_type; 54 import cpptooling.analyzer.clang.type_logger : logType; 55 import cpptooling.data : SimpleFmt, TypeId, TypeIdLR; 56 import cpptooling.data : Location, LocationTag; 57 import cpptooling.data.symbol : Container, USRType; 58 59 private string nextSequence() @safe { 60 import std.conv : text; 61 import cpptooling.utility.global_unique : nextNumber; 62 63 return text(nextNumber); 64 } 65 66 /// Returns: Filter node to only return those that are a typeref. 67 private auto filterByTypeRef(T)(auto ref T in_) { 68 import std.algorithm : filter; 69 70 return in_.filter!(a => a.isTypeRef); 71 } 72 73 /// 74 private bool isTypeRef(Cursor c) { 75 // CXCursorKind.CXCursor_TypeRef is the first node, thus >=... 76 // it is not in any other way "special". 77 78 return c.kind >= CXCursorKind.typeRef && c.kind <= CXCursorKind.lastRef; 79 } 80 81 /** Iteratively try to construct a USR that is reproducable from the cursor. 82 * 83 * Only use when c.usr may return the empty string. 84 * 85 * Fallback case, using location to make it unique. 86 * 87 * strategy 1 88 * try and derive a location from the lexical parent. 89 * strategy 2 90 * handled by putBacktrackLocation when loc_.kind is null_. 91 * putBacktrackLocation will then use nextSequence to generate a _for sure_ 92 * unique ID. 93 */ 94 private void makeFallbackUSR(Writer)(scope Writer w, scope const Cursor c, in uint this_indent) @safe { 95 // strategy 1 96 auto loc_ = backtrackLocation(c); 97 98 // strategy 2 99 putBacktrackLocation(w, c, loc_); 100 } 101 102 /// ditto 103 /// Returns: fallback USR from the cursor. 104 private USRType makeFallbackUSR(const Cursor c, in uint this_indent) @safe 105 out (result) { 106 logger.trace(result, this_indent); 107 assert(result.length > 0); 108 } 109 do { 110 import std.array : appender; 111 112 auto app = appender!string(); 113 makeFallbackUSR((const(char)[] s) { app.put(s); }, c, this_indent); 114 115 return USRType(app.data); 116 } 117 118 /// Make a USR, never failing. 119 USRType makeEnsuredUSR(scope const Cursor c, in uint this_indent) @safe 120 out (result) { 121 logger.trace(result, this_indent); 122 assert(result.length > 0); 123 } 124 do { 125 import std.array : appender; 126 127 auto usr = USRType(c.usr); 128 if (usr.length > 0) { 129 return usr; 130 } 131 132 auto app = appender!string(); 133 makeFallbackUSR((const(char)[] s) { app.put(s); }, c, this_indent); 134 app.put("§"); 135 app.put(nextSequence); 136 137 return USRType(app.data); 138 } 139 140 private void assertTypeResult(const ref TypeResults results) @trusted { 141 void assert_(const TypeResult result) { 142 assert(result.type.toStringDecl("x").length > 0); 143 assert(result.type.kind.usr.length > 0); 144 145 result.type.kind.info.match!(ignore!(TypeKind.PrimitiveInfo), (_) { 146 if (result.location.kind != LocationTag.Kind.noloc) { 147 assert(result.location.file.length > 0); 148 } 149 }); 150 } 151 152 assert_(results.primary); 153 154 foreach (ref result; results.extra) { 155 assert_(result); 156 } 157 } 158 159 struct BacktrackLocation { 160 static import clang.SourceLocation; 161 import my.optional; 162 static import cpptooling.data.type; 163 164 alias Tag = Optional!(cpptooling.data.type.Location); 165 166 Tag tag; 167 168 /// Number of nodes backtracked through until a valid was found 169 int backtracked; 170 } 171 172 /** Lexical backtrack from the argument cursor to first cursor with a valid 173 * location. 174 * 175 * using a for loop to ensure it is NOT an infinite loop. 176 * hoping 100 is enough for all type of nesting to reach at least translation 177 * unit. 178 * 179 * Return: Location and nr of backtracks needed. 180 */ 181 private BacktrackLocation backtrackLocation(scope const Cursor c) @trusted { 182 import cpptooling.data.type : Location; 183 184 BacktrackLocation rval; 185 186 Cursor parent = c; 187 for (rval.backtracked = 0; !rval.tag.hasValue && rval.backtracked < 100; ++rval.backtracked) { 188 auto loc = parent.location; 189 auto spell = loc.spelling; 190 if (spell.file is null) { 191 // do nothing 192 } else if (spell.file.name.length != 0) { 193 rval.tag = some(Location(spell.file.name, spell.line, spell.column)); 194 } else if (parent.isTranslationUnit) { 195 rval.tag = some(Location(spell.file.name, spell.line, spell.column)); 196 break; 197 } 198 199 parent = () @trusted { return parent.lexicalParent; }(); 200 } 201 202 return rval; 203 } 204 205 /// TODO consider if .offset should be used too. But may make it harder to 206 /// reverse engineer a location. 207 private void putBacktrackLocation(Writer)(scope Writer app, scope const Cursor c, 208 BacktrackLocation back_loc) @safe { 209 import std.range.primitives : put; 210 211 static import cpptooling.data.type; 212 213 // using a suffix that do NOT exist in the clang USR standard. 214 // TODO lookup the algorithm for clang USR to see if $ is valid. 215 enum marker = '§'; 216 217 app.put(back_loc.tag.orElse(Location(nextSequence)).toString); 218 219 put(app, marker); 220 put(app, back_loc.backtracked.to!string); 221 if (c.isValid) { 222 put(app, () @trusted { return c.spelling; }()); 223 } 224 } 225 226 LocationTag makeLocation(const Cursor c) @safe 227 out (result) { 228 import std.utf : validate; 229 230 validate(result.file); 231 } 232 do { 233 import std.array : appender; 234 235 auto loc = c.location.spelling; 236 auto rval = Location(loc.file.name, loc.line, loc.column); 237 238 if (rval.file.length > 0) { 239 return LocationTag(rval); 240 } 241 242 auto loc_ = backtrackLocation(c); 243 244 if (!loc_.tag.hasValue) { 245 return LocationTag(null); 246 } 247 248 auto app = appender!string(); 249 putBacktrackLocation((const(char)[] s) { app.put(s); }, c, loc_); 250 251 rval = Location(app.data, loc.line, loc.column); 252 253 return LocationTag(rval); 254 } 255 256 TypeAttr makeTypeAttr(ref Type type, const Cursor c) { 257 TypeAttr attr; 258 259 attr.isConst = cast(Flag!"isConst") type.isConst; 260 attr.isRef = cast(Flag!"isRef")(type.kind == CXTypeKind.lValueReference); 261 attr.isPtr = cast(Flag!"isPtr")(type.kind == CXTypeKind.pointer); 262 attr.isArray = cast(Flag!"isArray") type.isArray; 263 attr.isDefinition = cast(Flag!"isDefinition") c.isDefinition; 264 265 return attr; 266 } 267 268 TypeKindAttr makeTypeKindAttr(ref Type type, const Cursor c) { 269 TypeKindAttr tka; 270 tka.attr = makeTypeAttr(type, c); 271 272 return tka; 273 } 274 275 TypeKindAttr makeTypeKindAttr(ref Type type, ref TypeKind tk, const Cursor c) { 276 auto tka = makeTypeKindAttr(type, c); 277 tka.kind = tk; 278 279 return tka; 280 } 281 282 /** Deduct the type the node represents. 283 * 284 * pass 1, implicit anonymous structs and unions. 285 * pass 2, implicit types aka no spelling exist for them. 286 * pass 3, instansiated anonymous types and typedef of anonymous. 287 * pass 4, normal nodes, typedefs and references. 288 * passType, collect type information. The final result in most cases. 289 * 290 * TODO add "in" to parameter c. 291 * 292 * Params: 293 * c = cursor to retrieve from. 294 * container = container holding type symbols. 295 * indent = ? 296 */ 297 Nullable!TypeResults retrieveType(scope const Cursor c, ref Container container, in uint indent = 0) 298 in { 299 logNode(c, indent); 300 301 // unable to derive anything useful from a typeref when based on nothing else. 302 // __va_list is an examle (found in stdarg.h). 303 if (indent == 0 && isRefNode(c.kind)) { 304 assert(false); 305 } 306 } 307 out (result) { 308 logTypeResult(result, indent); 309 310 // ensure no invalid data is returned 311 if (!result.isNull && indent == 0) { 312 assertTypeResult(result.get); 313 } 314 } 315 do { 316 Nullable!TypeResults rval; 317 318 // bail early 319 if (c.kind.among(CXCursorKind.macroDefinition)) { 320 return rval; 321 } 322 323 foreach (pass; only(&pass1, &pass2, &pass3)) { 324 auto r = pass(c, indent + 1); 325 if (!r.isNull) { 326 rval = typeof(return)(TypeResults(r.get, null)); 327 return rval; 328 } 329 } 330 331 rval = pass4(c, container, indent + 1); 332 return rval; 333 } 334 335 /** Pass 1, implicit anonymous types for struct and union. 336 * 337 * TODO merge with pass2. Code duplication 338 */ 339 private Nullable!TypeResult pass1(scope const Cursor c, uint indent) 340 in { 341 logNode(c, indent); 342 } 343 do { 344 Nullable!TypeResult rval; 345 346 if (!c.isAnonymous) { 347 return rval; 348 } 349 350 switch (c.kind) with (CXCursorKind) { 351 case structDecl: 352 goto case; 353 case unionDecl: 354 auto type = c.type; 355 rval = TypeResult(); 356 rval.get.type = makeTypeKindAttr(type, c); 357 358 string spell = type.spelling; 359 rval.get.type.kind.info = TypeKind.RecordInfo(SimpleFmt(TypeId(spell))); 360 rval.get.type.kind.usr = USRType(c.usr); 361 rval.get.location = makeLocation(c); 362 break; 363 default: 364 } 365 366 return rval; 367 } 368 369 /** Pass 2, detect anonymous types who has "no name". 370 * 371 * Only struct, enum, union can possibly have this attribute. 372 * The types name. 373 * 374 * TODO consider using the identifier as the spelling. 375 * 376 * Example: 377 * --- 378 * struct (implicit name) { <-- and spelling is "" 379 * } Struct; 380 * 381 * union (implicit name) { <-- and spelling is "" 382 * } Union; 383 * 384 * typedef enum { 385 * X <--- this one 386 * } Enum; <--- not this one, covered by "other" pass 387 * --- 388 */ 389 private Nullable!TypeResult pass2(scope const Cursor c, uint indent) 390 in { 391 logNode(c, indent); 392 } 393 do { 394 Nullable!TypeResult rval; 395 396 if (c.spelling.length != 0) { 397 return rval; 398 } 399 400 switch (c.kind) with (CXCursorKind) { 401 case structDecl: 402 goto case; 403 case unionDecl: 404 auto type = c.type; 405 rval = TypeResult(makeTypeKindAttr(type, c), LocationTag.init); 406 rval.get.type.kind.info = TypeKind.RecordInfo(SimpleFmt(TypeId(nextSequence))); 407 rval.get.type.kind.usr = USRType(c.usr); 408 rval.get.location = makeLocation(c); 409 break; 410 case enumDecl: 411 auto type = c.type; 412 rval = TypeResult(makeTypeKindAttr(type, c), LocationTag.init); 413 rval.get.type.kind.info = TypeKind.SimpleInfo(SimpleFmt(TypeId(nextSequence))); 414 rval.get.type.kind.usr = USRType(c.usr); 415 rval.get.location = makeLocation(c); 416 break; 417 default: 418 } 419 420 return rval; 421 } 422 423 /** Detect anonymous types that have an instansiation. 424 * 425 * Continuation of Pass 2. 426 * Kept separate from Pass 3 to keep the passes logically "small". 427 * Less cognitive load to understand what the passes do. 428 * 429 * Examle: 430 * --- 431 * struct { 432 * } Struct; 433 * --- 434 */ 435 private Nullable!TypeResult pass3(scope const Cursor c, uint indent) 436 in { 437 logNode(c, indent); 438 } 439 do { 440 Nullable!TypeResult rval; 441 442 switch (c.kind) with (CXCursorKind) { 443 case fieldDecl: 444 goto case; 445 case varDecl: 446 import std.range : takeOne; 447 448 foreach (child; c.children.takeOne) { 449 rval = pass2(child, indent + 1); 450 } 451 break; 452 default: 453 } 454 455 return rval; 456 } 457 458 /** 459 */ 460 private Nullable!TypeResults pass4(scope const Cursor c, ref Container container, in uint this_indent) 461 in { 462 logNode(c, this_indent); 463 } 464 out (result) { 465 logTypeResult(result, this_indent); 466 } 467 do { 468 auto indent = this_indent + 1; 469 Nullable!TypeResults rval; 470 471 switch (c.kind) with (CXCursorKind) { 472 case typedefDecl: 473 rval = retrieveTypeDef(c, container, indent); 474 break; 475 476 case typeAliasTemplateDecl: 477 case typeAliasDecl: 478 rval = retrieveTypeAlias(c, container, indent); 479 break; 480 481 case fieldDecl: 482 case varDecl: 483 rval = retrieveInstanceDecl(c, container, indent); 484 break; 485 486 case parmDecl: 487 rval = retrieveParam(c, container, indent); 488 break; 489 490 case templateTypeParameter: 491 rval = retrieveTemplateParam(c, container, indent); 492 break; 493 494 case classTemplatePartialSpecialization: 495 case classTemplate: 496 rval = retrieveClassTemplate(c, container, indent); 497 break; 498 499 case structDecl: 500 case unionDecl: 501 case classDecl: 502 case enumDecl: 503 auto type = c.type; 504 rval = passType(c, type, container, indent); 505 break; 506 507 case cxxMethod: 508 case functionDecl: 509 rval = retrieveFunc(c, container, indent); 510 break; 511 512 case constructor: 513 auto type = c.type; 514 rval = typeToCtor(c, type, container, indent); 515 break; 516 517 case destructor: 518 auto type = c.type; 519 rval = typeToDtor(c, type, indent); 520 break; 521 522 case integerLiteral: 523 auto type = c.type; 524 rval = passType(c, type, container, indent); 525 break; 526 527 case cxxBaseSpecifier: 528 rval = retrieveClassBaseSpecifier(c, container, indent); 529 break; 530 531 case declRefExpr: 532 case typeRef: 533 case templateRef: 534 case namespaceRef: 535 case memberRef: 536 case labelRef: 537 auto refc = c.referenced; 538 rval = retrieveType(refc, container, indent); 539 break; 540 541 case noDeclFound: 542 // nothing to do 543 break; 544 545 case nonTypeTemplateParameter: 546 auto type = c.type; 547 rval = typeToSimple(c, type, indent); 548 break; 549 550 case unexposedDecl: 551 rval = retrieveUnexposed(c, container, indent); 552 if (rval.isNull) { 553 logger.trace("Not implemented type retrieval for node ", c.usr); 554 } 555 break; 556 557 default: 558 // skip for now, may implement in the future 559 logger.trace("Not implemented type retrieval for node ", c.usr); 560 } 561 562 return rval; 563 } 564 565 //TODO add comment, I don't understand what the function is intended to do from 566 // the function name. 567 private bool isUnexposedDeclWithUSR(CXCursorKind kind) { 568 switch (kind) with (CXCursorKind) { 569 case typedefDecl: 570 case templateTypeParameter: 571 case classTemplate: 572 case structDecl: 573 case unionDecl: 574 case classDecl: 575 case enumDecl: 576 return true; 577 default: 578 return false; 579 } 580 } 581 582 private bool canConvertNodeDeclToType(CXCursorKind kind) { 583 switch (kind) with (CXCursorKind) { 584 case typedefDecl: 585 case templateTypeParameter: 586 case classTemplate: 587 case structDecl: 588 case unionDecl: 589 case classDecl: 590 case enumDecl: 591 case cxxMethod: 592 case functionDecl: 593 case constructor: 594 case destructor: 595 case integerLiteral: 596 return true; 597 default: 598 return false; 599 } 600 } 601 602 private bool isRefNode(CXCursorKind kind) { 603 switch (kind) with (CXCursorKind) { 604 case typeRef: 605 case cxxBaseSpecifier: 606 case templateRef: 607 case namespaceRef: 608 case memberRef: 609 case labelRef: 610 return true; 611 default: 612 return false; 613 } 614 } 615 616 private Nullable!TypeResults retrieveUnexposed(const Cursor c, 617 ref Container container, in uint this_indent) 618 in { 619 logNode(c, this_indent); 620 assert(c.kind.among(CXCursorKind.unexposedDecl, CXCursorKind.nonTypeTemplateParameter)); 621 } 622 out (result) { 623 logTypeResult(result, this_indent); 624 } 625 do { 626 import std.range : takeOne; 627 628 auto indent = this_indent + 1; 629 Nullable!TypeResults rval; 630 631 foreach (child; c.children.takeOne) { 632 switch (child.kind) with (CXCursorKind) { 633 case cxxMethod: 634 case functionDecl: 635 rval = pass4(child, container, indent); 636 if (!rval.isNull) { 637 // cases like typeof(x) y; 638 // fix in the future 639 rval.get.primary.type.kind.info.match!(ignore!(TypeKind.FuncInfo), 640 _ => rval.nullify); 641 } 642 break; 643 644 default: 645 } 646 } 647 648 return rval; 649 } 650 651 private Nullable!TypeResults passType(const Cursor c, ref Type type, 652 ref Container container, in uint this_indent) 653 in { 654 logNode(c, this_indent); 655 logType(type, this_indent); 656 657 //TODO investigate if the below assumption is as it should be. 658 // Not suposed to be handled here. 659 // A typedef cursor shall have been detected and then handled by inspecting the child. 660 // MAYBE move primitive type detection here. 661 //assert(type.kind != CXTypeKind.CXType_Typedef); 662 } 663 out (result) { 664 logTypeResult(result, this_indent); 665 } 666 do { 667 import std.range : takeOne; 668 669 auto indent = 1 + this_indent; 670 Nullable!TypeResults rval; 671 672 switch (type.kind) with (CXTypeKind) { 673 case functionNoProto: 674 case functionProto: 675 rval = typeToFuncProto(c, type, container, indent); 676 break; 677 678 case blockPointer: 679 rval = typeToFuncPtr(c, type, container, indent); 680 break; 681 682 // handle ref and ptr the same way 683 case lValueReference: 684 case pointer: 685 //TODO fix architecture so this check isn't needed. 686 //Should be possible to merge typeToFunPtr and typeToPointer 687 if (type.isFunctionPointerType) { 688 rval = typeToFuncPtr(c, type, container, indent); 689 } else { 690 rval = typeToPointer(c, type, container, indent); 691 } 692 break; 693 694 case constantArray: 695 case incompleteArray: 696 rval = typeToArray(c, type, container, indent); 697 break; 698 699 case record: 700 rval = typeToRecord(c, type, indent); 701 break; 702 703 case typedef_: 704 // unable to represent a typedef as a typedef. 705 // Falling back on representing as a Simple. 706 // Note: the usr from the cursor is null. 707 rval = typeToFallBackTypeDef(c, type, indent); 708 break; 709 710 case unexposed: 711 debug { 712 logger.trace("Unexposed, investigate if any other action should be taken"); 713 } 714 if (!c.kind.among(CXCursorKind.functionDecl, CXCursorKind.cxxMethod)) { 715 // see retrieveUnexposed for why 716 rval = typeToSimple(c, type, indent); 717 } else if (type.isFunctionType) { 718 rval = typeToFuncProto(c, type, container, indent); 719 } 720 break; 721 722 default: 723 rval = typeToSimple(c, type, indent); 724 } 725 726 return rval; 727 } 728 729 /** Create a representation of a typeRef for the cursor. 730 */ 731 private TypeResults typeToTypeRef(const Cursor c, ref Type type, USRType type_ref, 732 USRType canonical_ref, in uint this_indent) 733 in { 734 logNode(c, this_indent); 735 logType(type, this_indent); 736 } 737 out (result) { 738 logTypeResult(result, this_indent); 739 } 740 do { 741 const uint indent = this_indent + 1; 742 string spell = type.spelling; 743 744 // ugly hack 745 if (type.isConst && spell.length > 6 && spell[0 .. 6] == "const ") { 746 spell = spell[6 .. $]; 747 } 748 749 TypeKind.TypeRefInfo info; 750 info.fmt = SimpleFmt(TypeId(spell)); 751 info.typeRef = type_ref; 752 info.canonicalRef = canonical_ref; 753 754 TypeResults rval; 755 rval.primary.type.attr = makeTypeAttr(type, c); 756 rval.primary.type.kind.info = info; 757 758 // a typedef like __va_list has a null usr 759 if (c.usr.length == 0) { 760 rval.primary.type.kind.usr = makeFallbackUSR(c, indent); 761 } else { 762 rval.primary.type.kind.usr = c.usr; 763 } 764 765 rval.primary.location = makeLocation(c); 766 767 return rval; 768 } 769 770 /** Use fallback strategy for typedef's via Simple. 771 * 772 * A typedef referencing a type that it isn't possible to derive information 773 * from to correctly represent (pointer, record, primitive etc). 774 * 775 * The fall back strategy is in that case to represent the type textually as a Simple. 776 * The TypeKind->typeRef then references this simple type. 777 */ 778 private Nullable!TypeResults typeToFallBackTypeDef(const Cursor c, ref Type type, in uint this_indent) 779 in { 780 logNode(c, this_indent); 781 logType(type, this_indent); 782 } 783 out (result) { 784 logTypeResult(result, this_indent); 785 } 786 do { 787 string spell = type.spelling; 788 789 // ugly hack to remove const 790 if (type.isConst && spell.length > 6 && spell[0 .. 6] == "const ") { 791 spell = spell[6 .. $]; 792 } 793 794 auto rval = makeTypeKindAttr(type, c); 795 796 auto info = TypeKind.SimpleInfo(SimpleFmt(TypeId(spell))); 797 rval.kind.info = info; 798 799 // a typedef like __va_list has a null usr 800 if (c.usr.length == 0) { 801 rval.kind.usr = makeFallbackUSR(c, this_indent + 1); 802 } else { 803 rval.kind.usr = c.usr; 804 } 805 806 auto loc = makeLocation(c); 807 808 return typeof(return)(TypeResults(TypeResult(rval, loc), null)); 809 } 810 811 private Nullable!TypeResults typeToSimple(const Cursor c, ref Type type, in uint this_indent) 812 in { 813 logNode(c, this_indent); 814 logType(type, this_indent); 815 } 816 out (result) { 817 logTypeResult(result, this_indent); 818 } 819 do { 820 auto rval = makeTypeKindAttr(type, c); 821 LocationTag loc; 822 823 auto maybe_primitive = translateCursorType(type.kind); 824 825 if (maybe_primitive.isNull) { 826 string spell = type.spelling; 827 rval.kind.info = TypeKind.SimpleInfo(SimpleFmt(TypeId(spell))); 828 829 rval.kind.usr = c.usr; 830 if (rval.kind.usr.length == 0) { 831 rval.kind.usr = makeFallbackUSR(c, this_indent + 1); 832 } 833 loc = makeLocation(c); 834 } else { 835 string spell = maybe_primitive.get; 836 rval.kind.info = TypeKind.PrimitiveInfo(SimpleFmt(TypeId(spell))); 837 838 rval.kind.usr = USRType(maybe_primitive.get); 839 loc = LocationTag(null); 840 } 841 842 return typeof(return)(TypeResults(TypeResult(rval, loc), null)); 843 } 844 845 /// A function proto signature? 846 /// Workaround by checking if the return type is valid. 847 private bool isFuncProtoTypedef(const Cursor c) { 848 auto result_t = c.type.func.resultType; 849 return result_t.isValid; 850 } 851 852 private Nullable!TypeResults typeToTypedef(const Cursor c, ref Type type, 853 USRType typeRef, USRType canonicalRef, ref Container container, in uint this_indent) 854 in { 855 logNode(c, this_indent); 856 logType(type, this_indent); 857 assert(type.kind.among(CXTypeKind.typedef_) || c.kind == CXCursorKind.typeAliasTemplateDecl); 858 } 859 out (result) { 860 logTypeResult(result, this_indent); 861 } 862 do { 863 /// Make a string that represent the type. 864 static string makeSpelling(const Cursor c, ref Type type) { 865 import std.array : array; 866 import std.algorithm : canFind, map, joiner; 867 import std.range : retro, chain, only; 868 import std.utf : byChar; 869 870 string spell = type.spelling; 871 872 if (type.isConst && spell.length > 6 && spell[0 .. 6] == "const ") { 873 spell = spell[6 .. $]; 874 } 875 876 if (!spell.canFind("::")) { 877 // if it isn't contained in a namespace then perform a backtracking of 878 // the scope to ensure it isn't needed. Implicit struct or enums need 879 // this check. 880 // Example: typedef struct {} Struct; 881 882 import cpptooling.analyzer.clang.cursor_backtrack : backtrackScopeRange; 883 884 // dfmt off 885 spell = cast(string) chain(only(spell), backtrackScopeRange(c).map!(a => a.spelling)) 886 .array 887 .retro 888 .joiner("::") 889 .byChar 890 .array; 891 // dfmt on 892 } 893 894 return spell; 895 } 896 897 auto spell = makeSpelling(c, type); 898 899 TypeKind.TypeRefInfo info; 900 info.fmt = SimpleFmt(TypeId(spell)); 901 info.typeRef = typeRef; 902 info.canonicalRef = canonicalRef; 903 904 TypeResults rval; 905 rval.primary.type.attr = makeTypeAttr(type, c); 906 rval.primary.type.kind.info = info; 907 908 // a typedef like __va_list has a null usr 909 if (c.usr.length == 0) { 910 rval.primary.type.kind.usr = makeFallbackUSR(c, this_indent + 1); 911 } else { 912 rval.primary.type.kind.usr = c.usr; 913 } 914 915 rval.primary.location = makeLocation(c); 916 917 return typeof(return)(rval); 918 } 919 920 /** Make a Record from a declaration or definition. 921 */ 922 private Nullable!TypeResults typeToRecord(const Cursor c, ref Type type, in uint indent) 923 in { 924 logNode(c, indent); 925 logType(type, indent); 926 assert(type.kind == CXTypeKind.record); 927 } 928 out (result) { 929 logTypeResult(result, indent); 930 } 931 do { 932 string spell = type.spelling; 933 934 // ugly hack needed when canonicalType has been used to get the type of a 935 // cursor 936 if (type.isConst && spell.length > 6 && spell[0 .. 6] == "const ") { 937 spell = spell[6 .. $]; 938 } 939 940 TypeKind.RecordInfo info; 941 info.fmt = SimpleFmt(TypeId(spell)); 942 943 auto rval = makeTypeKindAttr(type, c); 944 rval.kind.info = info; 945 rval.kind.usr = c.usr; 946 auto loc = makeLocation(c); 947 948 if (rval.kind.usr.length == 0) { 949 rval.kind.usr = makeFallbackUSR(c, indent + 1); 950 } 951 952 return typeof(return)(TypeResults(TypeResult(rval, loc), null)); 953 } 954 955 /** Represent a pointer type hierarchy. 956 * 957 * Returns: TypeResults.primary.attr is the pointed at attribute. 958 */ 959 private Nullable!TypeResults typeToPointer(const Cursor c, ref Type type, 960 ref Container container, const uint this_indent) 961 in { 962 logNode(c, this_indent); 963 logType(type, this_indent); 964 assert(type.kind.among(CXTypeKind.pointer, CXTypeKind.lValueReference)); 965 } 966 out (result) { 967 logTypeResult(result.get, this_indent); 968 result.get.primary.type.kind.info.match!(ignore!(const TypeKind.FuncPtrInfo), 969 ignore!(const TypeKind.PointerInfo), (_) { assert(0, "wrong type"); }); 970 } 971 do { 972 import cpptooling.data : PtrFmt, Left, Right; 973 974 immutable indent = this_indent + 1; 975 976 static auto getPointee(const Cursor c, ref Type type, ref Container container, in uint indent) { 977 auto pointee = type.pointeeType; 978 auto c_pointee = pointee.declaration; 979 980 debug { 981 logNode(c_pointee, indent); 982 logType(pointee, indent); 983 } 984 985 TypeResults rval; 986 987 // find the underlying type information 988 if (c_pointee.kind == CXCursorKind.typedefDecl) { 989 rval = retrieveType(c_pointee, container, indent).get; 990 } else if (pointee.kind == CXTypeKind.unexposed) { 991 pointee = type.canonicalType; 992 while (pointee.kind.among(CXTypeKind.pointer, CXTypeKind.lValueReference)) { 993 pointee = pointee.pointeeType; 994 } 995 rval = passType(c, pointee, container, indent).get; 996 997 if (c_pointee.kind.isUnexposedDeclWithUSR) { 998 rval.primary.type.kind.info.match!((TypeKind.RecordInfo t) { 999 // if the current pointers type is for a declaration use this 1000 // usr instead of the one from pointee. 1001 // Solves the case of a forward declared class in a namespace. 1002 // The retrieved data is only correct if it is from the 1003 // canonical type but the USR is wrong. 1004 string usr = c_pointee.usr; 1005 rval.primary.type.kind.usr = usr; 1006 1007 // TODO investigate if a usr null checking is needed. 1008 // I think it is unnecessary but unsure at this point. 1009 // It is possible to run a full scan of google mock and all 1010 // internal tests without this check. 1011 // If this hasn't been changed for 6 month remove this comment. 1012 // Written at 2016-07-01, remove by 2017-02-01. 1013 }, (_) {}); 1014 } 1015 } else if (c_pointee.kind == CXCursorKind.noDeclFound) { 1016 while (pointee.kind.among(CXTypeKind.pointer, CXTypeKind.lValueReference)) { 1017 pointee = pointee.pointeeType; 1018 } 1019 1020 auto c_decl = pointee.declaration; 1021 1022 if (c_decl.kind == CXCursorKind.noDeclFound) { 1023 // primitive types do not have a declaration cursor. 1024 // find the underlying primitive type. 1025 rval = passType(c, pointee, container, indent).get; 1026 } else { 1027 rval = retrieveType(c_decl, container, indent).get; 1028 } 1029 } else { 1030 rval = retrieveType(c_pointee, container, indent).get; 1031 } 1032 1033 return rval; 1034 } 1035 1036 auto pointee = getPointee(c, type, container, indent); 1037 1038 auto attrs = retrievePointeeAttr(type, indent); 1039 1040 TypeKind.PointerInfo info; 1041 info.pointee = pointee.primary.type.kind.usr; 1042 info.attrs = attrs.ptrs; 1043 1044 pointee.primary.type.kind.info.match!((TypeKind.ArrayInfo t) { 1045 auto type_id = pointee.primary.type.kind.splitTypeId(indent); 1046 info.fmt = PtrFmt(TypeIdLR(Left(type_id.left ~ "("), Right(")" ~ type_id.right))); 1047 }, (_) { info.fmt = PtrFmt(pointee.primary.type.kind.splitTypeId(indent)); }); 1048 1049 TypeResults rval; 1050 rval.primary.type.kind.info = info; 1051 // somehow pointee.primary.attr is wrong, somehow. Don't undestand why. 1052 // TODO remove this hack 1053 rval.primary.type.attr = attrs.base; 1054 // a pointer is always itselfs definition because they are always unique 1055 rval.primary.type.attr.isDefinition = Yes.isDefinition; 1056 1057 // must be unique even when analyzing many translation units. 1058 // Could maybe work if static/anonymous namespace influenced the USR. 1059 rval.primary.type.kind.usr = makeFallbackUSR(c, indent); 1060 rval.primary.location = makeLocation(c); 1061 1062 rval.extra = [pointee.primary] ~ pointee.extra; 1063 1064 return typeof(return)(rval); 1065 } 1066 1067 /** Represent a function pointer type. 1068 * 1069 * Return: correct formatting and attributes for a function pointer. 1070 */ 1071 private Nullable!TypeResults typeToFuncPtr(const Cursor c, ref Type type, 1072 ref Container container, const uint this_indent) 1073 in { 1074 logNode(c, this_indent); 1075 logType(type, this_indent); 1076 assert(type.kind.among(CXTypeKind.pointer, CXTypeKind.lValueReference)); 1077 assert(type.isFunctionPointerType); 1078 } 1079 out (result) { 1080 logTypeResult(result, this_indent); 1081 result.get.primary.type.kind.info.match!(restrictTo!(const TypeKind.CtorInfo, 1082 const TypeKind.DtorInfo, const TypeKind.RecordInfo, 1083 const TypeKind.SimpleInfo, const TypeKind.ArrayInfo, (val) { 1084 assert(0, "wrong type " ~ typeof(val).stringof); 1085 }), (_) {}); 1086 } 1087 do { 1088 import cpptooling.data : FuncPtrFmt, Left, Right; 1089 1090 immutable indent = this_indent + 1; 1091 1092 // find the underlying function prototype 1093 auto pointee_type = type; 1094 while (pointee_type.kind.among(CXTypeKind.pointer, CXTypeKind.lValueReference)) { 1095 pointee_type = pointee_type.pointeeType; 1096 } 1097 debug { 1098 logType(pointee_type, indent); 1099 } 1100 1101 auto attrs = retrievePointeeAttr(type, indent); 1102 auto pointee = typeToFuncProto(c, pointee_type, container, indent + 1); 1103 1104 TypeKind.FuncPtrInfo info; 1105 info.pointee = pointee.get.primary.type.kind.usr; 1106 info.attrs = attrs.ptrs; 1107 info.fmt = () { 1108 auto tid = pointee.get.primary.type.kind.splitTypeId(indent); 1109 return FuncPtrFmt(TypeIdLR(Left(tid.left ~ "("), Right(")" ~ tid.right))); 1110 }(); 1111 1112 TypeResults rval; 1113 rval.primary.type.kind.info = info; 1114 rval.primary.type.kind.usr = makeFallbackUSR(c, indent); 1115 rval.primary.location = makeLocation(c); 1116 // somehow pointee.primary.attr is wrong, somehow. Don't undestand why. 1117 // TODO remove this hack 1118 rval.primary.type.attr = attrs.base; 1119 1120 rval.extra = [pointee.get.primary] ~ pointee.get.extra; 1121 1122 return typeof(return)(rval); 1123 } 1124 1125 private Nullable!TypeResults typeToFuncProto(InfoT = TypeKind.FuncInfo)( 1126 const Cursor c, ref Type type, ref Container container, in uint this_indent) 1127 if (is(InfoT == TypeKind.FuncInfo) || is(InfoT == TypeKind.FuncSignatureInfo)) 1128 in { 1129 logNode(c, this_indent); 1130 logType(type, this_indent); 1131 assert(type.isFunctionType || type.isTypedef || type.kind == CXTypeKind.functionNoProto); 1132 } 1133 out (result) { 1134 logTypeResult(result, this_indent); 1135 } 1136 do { 1137 import std.array : array; 1138 import std.algorithm : map; 1139 import std.string : strip; 1140 import cpptooling.data : FuncFmt, Left, Right, FuncSignatureFmt; 1141 1142 const auto indent = this_indent + 1; 1143 1144 // TODO redesign. This is brittle and ugly. 1145 // return by value instead of splitting two ways like this. 1146 TypeKindAttr retrieveReturn(ref TypeResults rval) { 1147 auto result_type = type.func.resultType; 1148 auto result_decl = result_type.declaration; 1149 debug { 1150 logNode(result_decl, indent); 1151 logType(result_type, indent); 1152 } 1153 1154 auto this_node = passType(result_decl, result_type, container, indent + 1).get; 1155 1156 if (result_decl.kind == CXCursorKind.noDeclFound) { 1157 rval = this_node; 1158 } else { 1159 rval = retrieveType(result_decl, container, indent + 1).get; 1160 1161 // use the attributes derived from this node because it is not 1162 // preserved in the result_decl. This is a problem when the return 1163 // type is a typedef. The const attribute isn't preserved. 1164 rval.primary.type.attr = this_node.primary.type.attr; 1165 1166 rval.extra ~= this_node.primary; 1167 rval.extra ~= this_node.extra; 1168 } 1169 1170 return rval.primary.type; 1171 } 1172 1173 TypeResults rval; 1174 TypeResults return_rval; 1175 1176 auto return_t = retrieveReturn(return_rval); 1177 auto params = extractParams(c, type, container, indent); 1178 TypeResult primary; 1179 primary.type = makeTypeKindAttr(type, c); 1180 1181 // a C++ member function must be queried for constness via a different API 1182 primary.type.attr.isConst = cast(Flag!"isConst") c.func.isConst; 1183 1184 InfoT info; 1185 static if (is(InfoT == TypeKind.FuncInfo)) { 1186 info.fmt = FuncFmt(TypeIdLR(Left(return_t.toStringDecl.strip), 1187 Right("(" ~ params.params.joinParamId ~ ")"))); 1188 } else { 1189 info.fmt = FuncSignatureFmt(TypeIdLR(Left(return_t.toStringDecl.strip), 1190 Right("(" ~ params.params.joinParamId ~ ")"))); 1191 } 1192 info.return_ = return_t.kind.usr; 1193 info.returnAttr = return_t.attr; 1194 info.params = params.params.map!(a => FuncInfoParam(a.result.type.kind.usr, 1195 a.result.type.attr, a.id, a.isVariadic)).array(); 1196 1197 primary.type.kind.info = info; 1198 primary.location = makeLocation(c); 1199 1200 primary.type.kind.usr = c.usr; 1201 if (primary.type.kind.usr.length == 0) { 1202 primary.type.kind.usr = makeFallbackUSR(c, indent); 1203 } else if (c.kind.among(CXCursorKind.varDecl, CXCursorKind.fieldDecl, 1204 CXCursorKind.templateTypeParameter, CXCursorKind.parmDecl)) { 1205 // TODO consider how the knowledge of the field could be "moved" out of 1206 // this function. 1207 // Instances must result in a unique USR. Otherwise it is impossible to 1208 // differentiate between the type and field. 1209 primary.type.kind.usr = makeFallbackUSR(c, indent); 1210 } 1211 1212 rval.primary = primary; 1213 rval.extra ~= params.params.map!(a => a.result).array() ~ params.extra; 1214 rval.extra ~= return_rval.primary; 1215 rval.extra ~= return_rval.extra; 1216 1217 return typeof(return)(rval); 1218 } 1219 1220 private Nullable!TypeResults typeToCtor(const Cursor c, ref Type type, 1221 ref Container container, in uint indent) 1222 in { 1223 logNode(c, indent); 1224 logType(type, indent); 1225 assert(c.kind == CXCursorKind.constructor); 1226 } 1227 out (result) { 1228 logTypeResult(result, indent); 1229 } 1230 do { 1231 import std.algorithm : map; 1232 import std.array : array; 1233 import cpptooling.data : CtorFmt; 1234 1235 TypeResults rval; 1236 auto params = extractParams(c, type, container, indent); 1237 TypeResult primary; 1238 primary.type = makeTypeKindAttr(type, c); 1239 1240 TypeKind.CtorInfo info; 1241 info.fmt = CtorFmt(TypeId(format("(%s)", params.params.joinParamId()))); 1242 info.params = params.params.map!(a => FuncInfoParam(a.result.type.kind.usr, 1243 a.result.type.attr, a.id, a.isVariadic)).array(); 1244 info.id = c.spelling; 1245 1246 primary.type.kind.info = info; 1247 primary.type.kind.usr = c.usr; 1248 primary.location = makeLocation(c); 1249 1250 rval.primary = primary; 1251 rval.extra ~= params.params.map!(a => a.result).array() ~ params.extra; 1252 1253 return typeof(return)(rval); 1254 } 1255 1256 private Nullable!TypeResults typeToDtor(const Cursor c, ref Type type, in uint indent) 1257 in { 1258 logNode(c, indent); 1259 logType(type, indent); 1260 assert(c.kind == CXCursorKind.destructor); 1261 } 1262 out (result) { 1263 logTypeResult(result, indent); 1264 } 1265 do { 1266 TypeResults rval; 1267 auto primary = makeTypeKindAttr(type, c); 1268 1269 TypeKind.DtorInfo info; 1270 info.id = c.spelling[1 .. $]; // remove the leading ~ 1271 1272 primary.kind.info = info; 1273 primary.kind.usr = c.usr; 1274 1275 rval.primary.location = makeLocation(c); 1276 rval.primary.type = primary; 1277 1278 return typeof(return)(rval); 1279 } 1280 1281 //TODO change the array to an appender, less GC pressure 1282 private alias PointerTypeAttr = Tuple!(TypeAttr[], "ptrs", TypeAttr, "base"); 1283 1284 /** Retrieve the attributes of the pointers until base condition. 1285 * 1286 * [$] is the value pointed at. 1287 * 1288 * Params: 1289 * underlying = the value type, injected at correct position. 1290 * type = a pointer or reference type. 1291 * indent = indent for the log strings. 1292 * Return: An array of attributes for the pointers. 1293 */ 1294 private PointerTypeAttr retrievePointeeAttr(ref Type type, in uint this_indent) 1295 in { 1296 logType(type, this_indent); 1297 } 1298 out (result) { 1299 import std.range : chain, only; 1300 1301 foreach (r; chain(only(result.base), result.ptrs)) { 1302 logTypeAttr(r, this_indent); 1303 } 1304 } 1305 do { 1306 auto indent = this_indent + 1; 1307 PointerTypeAttr rval; 1308 auto decl_c = type.declaration; 1309 1310 if (type.kind.among(CXTypeKind.pointer, CXTypeKind.lValueReference)) { 1311 // recursive 1312 auto pointee = type.pointeeType; 1313 rval = retrievePointeeAttr(pointee, indent); 1314 // current appended so right most ptr is at position 0. 1315 rval.ptrs ~= makeTypeAttr(type, decl_c); 1316 } else { 1317 // Base condition. 1318 rval.base = makeTypeAttr(type, decl_c); 1319 } 1320 1321 return rval; 1322 } 1323 1324 /// TODO this function is horrible. Refactor 1325 private Nullable!TypeResults typeToArray(const Cursor c, ref Type type, 1326 ref Container container, const uint this_indent) 1327 in { 1328 logNode(c, this_indent); 1329 logType(type, this_indent); 1330 } 1331 out (result) { 1332 logTypeResult(result.get, this_indent); 1333 result.get.primary.type.kind.info.match!(ignore!(const TypeKind.ArrayInfo), (_) { 1334 assert(0, "wrong type"); 1335 }); 1336 } 1337 do { 1338 import std.format : format; 1339 import cpptooling.data : ArrayFmt, LocationTag, Location; 1340 1341 immutable indent = this_indent + 1; 1342 1343 static void gatherIndexesToElement(Type start, ref ArrayInfoIndex[] indexes, ref Type element) { 1344 Type curr = start; 1345 1346 while (curr.kind.among(CXTypeKind.constantArray, CXTypeKind.incompleteArray)) { 1347 auto arr = curr.array; 1348 1349 switch (curr.kind) with (CXTypeKind) { 1350 case constantArray: 1351 indexes ~= ArrayInfoIndex(arr.size); 1352 break; 1353 case incompleteArray: 1354 indexes ~= ArrayInfoIndex(); 1355 break; 1356 default: 1357 break; 1358 } 1359 1360 curr = arr.elementType; 1361 } 1362 1363 element = curr; 1364 } 1365 1366 static void determineElement(Type ele_type, ref ArrayInfoIndex[] indexes, const Cursor c, ref Container container, 1367 ref USRType primary_usr, ref LocationTag primary_loc, 1368 ref TypeResults element, const uint indent) { 1369 auto index_decl = ele_type.declaration; 1370 1371 if (index_decl.kind == CXCursorKind.noDeclFound) { 1372 // on purpuse not checking if it is null before using 1373 element = passType(c, ele_type, container, indent).get; 1374 1375 if (element.primary.type.kind.usr.length != 0) { 1376 primary_usr = element.primary.type.kind.usr; 1377 } else { 1378 primary_usr = makeFallbackUSR(c, indent); 1379 } 1380 primary_loc = element.primary.location; 1381 } else { 1382 // on purpuse not checking if it is null before using 1383 element = retrieveType(index_decl, container, indent).get; 1384 1385 primary_usr = element.primary.type.kind.usr; 1386 primary_loc = element.primary.location; 1387 } 1388 // let the indexing affect the USR as to not collide with none-arrays of 1389 // the same type. 1390 primary_usr = primary_usr ~ indexes.toRepr; 1391 1392 switch (primary_loc.kind) { 1393 case LocationTag.Kind.noloc: 1394 // TODO this is stupid ... fix it. Shouldn't be needed but happens 1395 // when it is an array of primary types. 1396 // Probably the correct fix is the contract in retrieveType to check 1397 // that if it is an array at primary types it do NOT check for length. 1398 primary_loc = makeLocation(c); 1399 break; 1400 default: 1401 } 1402 } 1403 1404 // step 1, find indexing and element type 1405 ArrayInfoIndex[] index_nr; 1406 Type element_type = type; 1407 1408 gatherIndexesToElement(type, index_nr, element_type); 1409 1410 // step 2, determine element 1411 TypeResults element; 1412 USRType primary_usr; 1413 LocationTag primary_loc; 1414 1415 determineElement(element_type, index_nr, c, container, primary_usr, 1416 primary_loc, element, indent); 1417 1418 // step 3, put together the result 1419 1420 TypeKind.ArrayInfo info; 1421 info.element = element.primary.type.kind.usr; 1422 info.indexes = index_nr; 1423 info.fmt = ArrayFmt(element.primary.type.kind.splitTypeId(indent)); 1424 1425 TypeResults rval; 1426 1427 if (element.primary.type.kind.info.match!(restrictTo!(TypeKind.PointerInfo, 1428 TypeKind.FuncPtrInfo, val => false), _ => true)) { 1429 auto elem_t = type.array.elementType; 1430 auto decl_c = elem_t.declaration; 1431 rval.primary.type.attr = makeTypeAttr(elem_t, decl_c); 1432 } else { 1433 rval.primary.type.attr = element.primary.type.attr; 1434 } 1435 1436 rval.primary.type.kind.usr = primary_usr; 1437 rval.primary.location = primary_loc; 1438 rval.primary.type.kind.info = info; 1439 rval.extra ~= [element.primary] ~ element.extra; 1440 1441 return typeof(return)(rval); 1442 } 1443 1444 /** Retrieve the type of an instance declaration. 1445 * 1446 * Questions to consider: 1447 * - Is the type a typeref? 1448 * - Is it a function pointer? 1449 * - Is the type a primitive type? 1450 */ 1451 private Nullable!TypeResults retrieveInstanceDecl(const Cursor c, 1452 ref Container container, in uint this_indent) 1453 in { 1454 logNode(c, this_indent); 1455 with (CXCursorKind) { 1456 assert(c.kind.among(varDecl, fieldDecl, templateTypeParameter, parmDecl)); 1457 } 1458 } 1459 out (result) { 1460 logTypeResult(result, this_indent); 1461 } 1462 do { 1463 import std.range : takeOne; 1464 1465 const indent = this_indent + 1; 1466 auto c_type = c.type; 1467 1468 auto handlePointer(ref Nullable!TypeResults rval) { 1469 switch (c_type.kind) with (CXTypeKind) { 1470 // Is it a pointer? 1471 // Then preserve the pointer structure but dig deeper for the 1472 // pointed at type. 1473 case lValueReference: 1474 case pointer: 1475 // must retrieve attributes from the pointed at type thus need a 1476 // more convulated deduction 1477 rval = passType(c, c_type, container, indent); 1478 foreach (tref; c.children.takeOne) { 1479 auto child = retrieveType(tref, container, indent); 1480 if (!child.isNull) { 1481 rval.get.extra ~= [child.get.primary] ~ child.get.extra; 1482 } 1483 } 1484 break; 1485 1486 default: 1487 } 1488 } 1489 1490 auto handleTypedef(ref Nullable!TypeResults rval) { 1491 import std.algorithm : until; 1492 import libclang_ast.cursor_visitor : visitBreathFirst; 1493 1494 // example of tree analyzed: 1495 // VarDecl -> TypedefDecl 1496 // VarDecl -> TypeRef -> TypedefDecl 1497 foreach (child; c.visitBreathFirst.until!(a => a.depth == 3)) { 1498 if (child.kind == CXCursorKind.typeRef) { 1499 rval = retrieveType(child, container, indent); 1500 break; 1501 } else if (child.kind == CXCursorKind.typedefDecl) { 1502 rval = retrieveType(child, container, indent); 1503 break; 1504 } 1505 } 1506 1507 if (!rval.isNull) { 1508 // depend on the underlying cursor 1509 auto old_def = rval.get.primary.type.attr.isDefinition; 1510 rval.get.primary.type.attr = makeTypeAttr(c_type, c); 1511 rval.get.primary.type.attr.isDefinition = old_def; 1512 } 1513 } 1514 1515 auto handleTypeWithDecl(ref Nullable!TypeResults rval) { 1516 auto c_type_decl = c_type.declaration; 1517 if (c_type_decl.isValid) { 1518 auto type = c_type_decl.type; 1519 rval = passType(c_type_decl, type, container, indent); 1520 } 1521 } 1522 1523 auto handleArray(ref Nullable!TypeResults rval) { 1524 // must check for array:nes before Typedef because of the case when it 1525 // is an array of typedef's 1526 if (c_type.isArray) { 1527 rval = typeToArray(c, c_type, container, indent); 1528 } 1529 } 1530 1531 auto fallback(ref Nullable!TypeResults rval) { 1532 rval = passType(c, c_type, container, indent); 1533 } 1534 1535 auto ensureUSR(ref Nullable!TypeResults rval) { 1536 if (!rval.isNull && rval.get.primary.type.kind.usr.length == 0) { 1537 rval.get.primary.type.kind.usr = makeFallbackUSR(c, this_indent); 1538 } 1539 } 1540 1541 Nullable!TypeResults rval; 1542 foreach (idx, f; [ 1543 &handlePointer, &handleArray, &handleTypedef, &handleTypeWithDecl, 1544 &fallback 1545 ]) { 1546 debug { 1547 import std.conv : to; 1548 1549 logger.trace(idx.to!string(), this_indent); 1550 } 1551 1552 f(rval); 1553 if (!rval.isNull) { 1554 break; 1555 } 1556 } 1557 1558 ensureUSR(rval); 1559 1560 return rval; 1561 } 1562 1563 private Nullable!TypeResults retrieveTypeAlias(const Cursor c, 1564 ref Container container, in uint this_indent) 1565 in { 1566 logNode(c, this_indent); 1567 assert(c.kind.among(CXCursorKind.typeAliasDecl, CXCursorKind.typeAliasTemplateDecl)); 1568 } 1569 out (result) { 1570 logTypeResult(result, this_indent); 1571 } 1572 do { 1573 const uint indent = this_indent + 1; 1574 1575 Nullable!TypeResults rval; 1576 1577 foreach (child; c.children) { 1578 if (!child.kind.among(CXCursorKind.typeRef, CXCursorKind.typeAliasDecl)) { 1579 continue; 1580 } 1581 1582 auto tref = pass4(child, container, indent); 1583 1584 auto type = c.type; 1585 // duplicated code from retrieveTypeDef -> handleTyperef 1586 // TODO consider if this can be harmonized with Typedef. 1587 // Maybe this is a special case? 1588 // Shouldn't be per se locked to a TypeDefDecl but rather the concept 1589 // of a type that is an alias for another. 1590 tref.get.primary.type.kind.info.match!((TypeKind.TypeRefInfo t) { 1591 rval = typeToTypedef(c, type, tref.get.primary.type.kind.usr, 1592 t.canonicalRef, container, indent); 1593 }, (_) { 1594 rval = typeToTypedef(c, type, tref.get.primary.type.kind.usr, 1595 tref.get.primary.type.kind.usr, container, indent); 1596 }); 1597 rval.get.extra = [tref.get.primary] ~ tref.get.extra; 1598 } 1599 1600 if (rval.isNull && c.kind == CXCursorKind.typeAliasDecl) { 1601 auto type = c.type; 1602 rval = typeToSimple(c, type, indent); 1603 } 1604 1605 return rval; 1606 } 1607 1608 private Nullable!TypeResults retrieveTypeDef(const Cursor c, 1609 ref Container container, in uint this_indent) 1610 in { 1611 logNode(c, this_indent); 1612 assert(c.kind == CXCursorKind.typedefDecl); 1613 } 1614 out (result) { 1615 logTypeResult(result, this_indent); 1616 } 1617 do { 1618 import std.range : takeOne; 1619 1620 const uint indent = this_indent + 1; 1621 1622 void handleTyperef(ref Nullable!TypeResults rval) { 1623 import std.algorithm : filter; 1624 1625 if (isFuncProtoTypedef(c)) { 1626 // this case is handled by handleTyperefFuncProto 1627 return; 1628 } 1629 1630 // any TypeRef children and thus need to traverse the tree? 1631 foreach (child; c.children.filterByTypeRef.filter!(a => a.kind == CXCursorKind.typeRef) 1632 .takeOne) { 1633 auto tref = pass4(child, container, indent); 1634 1635 auto type = c.type; 1636 tref.get.primary.type.kind.info.match!((TypeKind.TypeRefInfo t) { 1637 rval = typeToTypedef(c, type, tref.get.primary.type.kind.usr, 1638 t.canonicalRef, container, indent); 1639 }, (_) { 1640 rval = typeToTypedef(c, type, tref.get.primary.type.kind.usr, 1641 tref.get.primary.type.kind.usr, container, indent); 1642 }); 1643 rval.get.extra = [tref.get.primary] ~ tref.get.extra; 1644 } 1645 } 1646 1647 void handleDecl(ref Nullable!TypeResults rval) { 1648 auto child_ = c.children.takeOne; 1649 if (child_.length == 0 || !child_[0].kind.canConvertNodeDeclToType) { 1650 return; 1651 } 1652 1653 auto c_child = child_[0]; 1654 auto tref = retrieveType(c_child, container, indent); 1655 1656 auto type = c.type; 1657 tref.get.primary.type.kind.info.match!((TypeKind.TypeRefInfo t) { 1658 rval = typeToTypedef(c, type, tref.get.primary.type.kind.usr, 1659 t.canonicalRef, container, indent); 1660 }, (_) { 1661 rval = typeToTypedef(c, type, tref.get.primary.type.kind.usr, 1662 tref.get.primary.type.kind.usr, container, indent); 1663 }); 1664 1665 rval.get.extra = [tref.get.primary] ~ tref.get.extra; 1666 } 1667 1668 auto handleTypeRefToTypeDeclFuncProto(ref Nullable!TypeResults rval) { 1669 static bool isFuncProto(const Cursor c) { 1670 //TODO consider merging or improving isFuncProtoTypedef with this 1671 if (!isFuncProtoTypedef(c)) { 1672 return false; 1673 } 1674 1675 if (c.children.length == 0) { 1676 return false; 1677 } 1678 1679 auto child_t = c.children[0].type; 1680 if (!child_t.isFunctionType || child_t.isPointer) { 1681 return false; 1682 } 1683 1684 return true; 1685 } 1686 1687 if (!isFuncProto(c)) { 1688 return; 1689 } 1690 1691 auto child = c.children[0]; 1692 auto ref_child = child.referenced; 1693 if (ref_child.kind != CXCursorKind.typedefDecl) { 1694 return; 1695 } 1696 1697 auto tref = retrieveType(ref_child, container, indent); 1698 1699 // TODO consolidate code. Copied from handleDecl 1700 auto type = c.type; 1701 tref.get.primary.type.kind.info.match!((TypeKind.TypeRefInfo t) { 1702 rval = typeToTypedef(c, type, tref.get.primary.type.kind.usr, 1703 t.canonicalRef, container, indent); 1704 }, (_) { 1705 rval = typeToTypedef(c, type, tref.get.primary.type.kind.usr, 1706 tref.get.primary.type.kind.usr, container, indent); 1707 }); 1708 rval.get.extra = [tref.get.primary] ~ tref.get.extra; 1709 } 1710 1711 auto handleFuncProto(ref Nullable!TypeResults rval) { 1712 if (!isFuncProtoTypedef(c)) { 1713 return; 1714 } 1715 1716 auto type = c.type; 1717 auto func = typeToFuncProto!(TypeKind.FuncSignatureInfo)(c, type, container, indent); 1718 1719 rval = typeToTypedef(c, type, func.get.primary.type.kind.usr, 1720 func.get.primary.type.kind.usr, container, indent); 1721 rval.get.extra = [func.get.primary] ~ func.get.extra; 1722 } 1723 1724 auto underlying(ref Nullable!TypeResults rval) { 1725 // TODO this function is convoluted and complex. Consider how it can be rewritten. 1726 1727 auto underlying = c.typedefUnderlyingType; 1728 auto underlying_decl_c = underlying.declaration; 1729 1730 Nullable!TypeResults tref; 1731 // assuming that there are typedef nodes that have no declaration. 1732 if (underlying_decl_c.isValid) { 1733 tref = passType(underlying_decl_c, underlying, container, indent); 1734 } else { 1735 tref = passType(c, underlying, container, indent); 1736 // ensure it is unique 1737 tref.get.primary.type.kind.usr = makeFallbackUSR(c, indent); 1738 } 1739 1740 USRType canonical_usr = tref.get.primary.type.kind.info.match!( 1741 (TypeKind.TypeRefInfo t) => t.canonicalRef, (_) => tref.get.primary.type.kind.usr); 1742 1743 auto type = c.type; 1744 rval = typeToTypedef(c, type, tref.get.primary.type.kind.usr, 1745 canonical_usr, container, indent); 1746 rval.get.extra = [tref.get.primary] ~ tref.get.extra; 1747 } 1748 1749 void handleArray(ref Nullable!TypeResults rval) { 1750 // a constant array typedef has an integerLiteral as child. 1751 // handleDecl is built on the assumption that the first child of a 1752 // declaration that is a typedef is the "reference". As can be seen it 1753 // is wrong in the case for a constant array. 1754 auto underlying_t = c.typedefUnderlyingType; 1755 1756 if (underlying_t.isArray) { 1757 underlying(rval); 1758 } 1759 } 1760 1761 // TODO investigate if this can be removed, aka always covered by underlying. 1762 auto fallback(ref Nullable!TypeResults rval) { 1763 // fallback, unable to represent as a typedef ref'ing a type 1764 auto type = c.type; 1765 rval = passType(c, type, container, indent); 1766 } 1767 1768 typeof(return) rval; 1769 foreach (idx, f; [ 1770 &handleTypeRefToTypeDeclFuncProto, &handleArray, &handleTyperef, 1771 &handleFuncProto, &handleDecl, &underlying, &fallback 1772 ]) { 1773 debug { 1774 import std.conv : to; 1775 1776 logger.trace(idx.to!string(), this_indent); 1777 } 1778 f(rval); 1779 if (!rval.isNull) { 1780 break; 1781 } 1782 } 1783 1784 return rval; 1785 } 1786 1787 /** Retrieve the type representation of a FuncDecl or CXXMethod. 1788 * 1789 * case a. A typedef of a function signature. 1790 * When it is instantiated it results in a FunctionDecl with a TypeRef. 1791 * Note in the example that the child node is a TypeRef. 1792 * Using the resultType to distinguish between a typedef function signature and 1793 * a function returning a function ptr. 1794 * 1795 * Example: 1796 * FunctionDecl "tiger" [Keyword "extern", Identifier "func_type", Identifier "tiger"] c:@F@tiger 1797 * TypeRef "func_type" [Identifier "func_type"] 1798 * 1799 * case b. A function with a return type which is a TypeRef to a TypedefDecl. 1800 * The first child node is a TypeRef. 1801 * This case should NOT be confused with case a. 1802 * 1803 * case c. A function declared "the normal way", void foo(); 1804 * 1805 * solve case a. 1806 * Try resolving the type of the first child node. 1807 * If the canonical type is a function, good. Case a. 1808 * Otherwise case b and c. 1809 */ 1810 private Nullable!TypeResults retrieveFunc(const Cursor c, 1811 ref Container container, const uint this_indent) 1812 in { 1813 logNode(c, this_indent); 1814 assert(c.kind.among(CXCursorKind.functionDecl, CXCursorKind.cxxMethod)); 1815 } 1816 out (result) { 1817 logTypeResult(result, this_indent); 1818 } 1819 do { 1820 import std.algorithm : filter; 1821 import std.range : chain, only; 1822 import cpptooling.data : FuncFmt; 1823 1824 immutable indent = this_indent + 1; 1825 typeof(return) rval; 1826 1827 // distinguish between a child node that is for the return value from those 1828 // cases when it is a function derived from a typedef:ed function signature. 1829 auto result_decl_usr = c.func.resultType.declaration.usr; 1830 1831 foreach (child; c.children.filterByTypeRef.filter!((a) { 1832 auto tmp = a.referenced.usr; 1833 return tmp != result_decl_usr; 1834 })) { 1835 if (child.kind != CXCursorKind.typeRef) { 1836 break; 1837 } 1838 auto retrieved_ref = retrieveType(child, container, indent); 1839 1840 if (retrieved_ref.isNull) { 1841 continue; 1842 } 1843 1844 retrieved_ref.get.primary.type.kind.info.match!((TypeKind.FuncInfo t) { 1845 // fast path 1846 rval = retrieved_ref; 1847 }, (TypeKind.TypeRefInfo t) { 1848 // check the canonical type 1849 foreach (k; chain(only(retrieved_ref.get.primary), retrieved_ref.get.extra)) { 1850 if (k.type.kind.usr != t.canonicalRef) { 1851 continue; 1852 } 1853 1854 k.type.kind.info.match!((TypeKind.FuncInfo t) { 1855 rval = retrieved_ref; 1856 }, (TypeKind.FuncSignatureInfo t) { 1857 // function declaration of a typedef'ed signature 1858 rval = retrieved_ref; 1859 rval.get.extra ~= rval.get.primary; 1860 1861 auto prim = k; 1862 prim.type.kind.info = TypeKind.FuncInfo(FuncFmt(k.type.kind.splitTypeId(indent)), 1863 t.return_, t.returnAttr, t.params); 1864 prim.location = makeLocation(c); 1865 prim.type.kind.usr = makeFallbackUSR(c, this_indent); 1866 rval.get.primary = prim; 1867 }, (_) {}); 1868 1869 } 1870 }, (_) {}); 1871 } 1872 1873 if (rval.isNull) { 1874 auto type = c.type; 1875 rval = passType(c, type, container, indent); 1876 } 1877 1878 return rval; 1879 } 1880 1881 /** Only able to uniquely represent the class template. 1882 * 1883 * TODO Unable to instansiate. 1884 */ 1885 private Nullable!TypeResults retrieveClassTemplate(const Cursor c, 1886 ref Container container, in uint indent) 1887 in { 1888 import std.algorithm : among; 1889 1890 logNode(c, indent); 1891 assert(c.kind.among(CXCursorKind.classTemplate, 1892 CXCursorKind.classTemplatePartialSpecialization)); 1893 } 1894 do { 1895 TypeResults rval; 1896 1897 auto type = c.type; 1898 rval.primary.type = makeTypeKindAttr(type, c); 1899 rval.primary.type.kind.info = TypeKind.SimpleInfo(SimpleFmt(TypeId(c.spelling))); 1900 rval.primary.type.kind.usr = c.usr; 1901 rval.primary.location = makeLocation(c); 1902 1903 return typeof(return)(rval); 1904 } 1905 1906 private Nullable!TypeResults retrieveClassBaseSpecifier(const Cursor c, 1907 ref Container container, in uint this_indent) 1908 in { 1909 logNode(c, this_indent); 1910 assert(c.kind == CXCursorKind.cxxBaseSpecifier); 1911 } 1912 do { 1913 auto indent = this_indent + 1; 1914 1915 // when the cursor references a definition. easy 1916 bool tryReferenced(ref Nullable!TypeResults rval) { 1917 logger.trace("", this_indent); 1918 auto c_ref = c.referenced; 1919 1920 if (c_ref.kind == CXCursorKind.noDeclFound) { 1921 return false; 1922 } 1923 1924 rval = retrieveType(c_ref, container, indent); 1925 1926 return true; 1927 } 1928 1929 // no definition exist. e.g in the cases of a template instantiation. 1930 bool reconstructFromCursor(ref Nullable!TypeResults rval_) { 1931 logger.trace("", this_indent); 1932 1933 TypeResults rval; 1934 1935 auto type = c.type; 1936 rval.primary.type = makeTypeKindAttr(type, c); 1937 1938 rval.primary.type.kind.info = TypeKind.SimpleInfo(SimpleFmt(TypeId(c.spelling))); 1939 rval.primary.type.kind.usr = makeEnsuredUSR(c, indent); 1940 rval.primary.location = makeLocation(c); 1941 1942 rval_ = Nullable!TypeResults(rval); 1943 1944 return true; 1945 } 1946 1947 Nullable!TypeResults rval; 1948 1949 foreach (idx, f; [&tryReferenced, &reconstructFromCursor]) { 1950 if (f(rval)) { 1951 break; 1952 } 1953 } 1954 1955 return rval; 1956 } 1957 1958 /** Extract the type of a parameter cursor. 1959 * 1960 * TODO if nothing changes remove either retrieveParam or retrieveInstanceDecl, 1961 * code duplication. 1962 */ 1963 private Nullable!TypeResults retrieveParam(const Cursor c, ref Container container, 1964 in uint this_indent) 1965 in { 1966 logNode(c, this_indent); 1967 // TODO add assert for the types allowed 1968 } 1969 out (result) { 1970 logTypeResult(result, this_indent); 1971 } 1972 do { 1973 return retrieveInstanceDecl(c, container, this_indent + 1); 1974 } 1975 1976 /** Only able to uniquely represent the class template. 1977 * 1978 * TODO Unable to instansiate. 1979 */ 1980 private Nullable!TypeResults retrieveTemplateParam(const Cursor c, 1981 ref Container container, in uint this_indent) 1982 in { 1983 logNode(c, this_indent); 1984 // TODO add assert for the types allowed 1985 } 1986 do { 1987 import std.range : takeOne; 1988 1989 uint indent = this_indent + 1; 1990 Nullable!TypeResults rval; 1991 1992 if (c.spelling.length == 0) { 1993 //TODO could probably be a random name, the location or something. 1994 // Example when it occurs: 1995 // template <typename/*here*/> class allocator; 1996 return rval; 1997 } 1998 1999 auto type = c.type; 2000 rval = retrieveParam(c, container, indent); 2001 2002 return rval; 2003 } 2004 2005 private alias ExtractParamsResult = Tuple!(TypeResult, "result", string, "id", 2006 Flag!"isVariadic", "isVariadic"); 2007 private alias ExtractParamsResults = Tuple!(ExtractParamsResult[], "params", 2008 TypeResult[], "extra"); 2009 2010 private ExtractParamsResults extractParams(const Cursor c, ref Type type, 2011 ref Container container, in uint this_indent) 2012 in { 2013 logNode(c, this_indent); 2014 logType(type, this_indent); 2015 assert(type.isFunctionType || type.isTypedef || type.kind == CXTypeKind.functionNoProto); 2016 } 2017 out (result) { 2018 foreach (p; result.params) { 2019 logger.trace(p.result.type.toStringDecl(p.id), this_indent); 2020 } 2021 2022 foreach (e; result.extra) { 2023 logTypeResult(e, this_indent); 2024 } 2025 } 2026 do { 2027 const auto indent = this_indent + 1; 2028 2029 void appendParams(const Cursor c, ref ExtractParamsResults rval) { 2030 import std.range : enumerate; 2031 2032 foreach (idx, p; c.children.enumerate) { 2033 if (p.kind != CXCursorKind.parmDecl) { 2034 logNode(p, this_indent); 2035 continue; 2036 } 2037 2038 auto tka = retrieveType(p, container, indent); 2039 auto id = p.spelling; 2040 rval.params ~= ExtractParamsResult(tka.get.primary, id, No.isVariadic); 2041 rval.extra ~= tka.get.extra; 2042 } 2043 2044 if (type.func.isVariadic) { 2045 import clang.SourceLocation; 2046 2047 TypeResult result; 2048 2049 auto info = TypeKind.SimpleInfo(SimpleFmt(TypeId("..."))); 2050 result.type.kind.info = info; 2051 result.type.kind.usr = "..." ~ c.location.toString(); 2052 result.location = makeLocation(c); 2053 2054 // TODO remove this ugly hack 2055 // space as id to indicate it is empty 2056 rval.params ~= ExtractParamsResult(result, " ", Yes.isVariadic); 2057 } 2058 } 2059 2060 ExtractParamsResults rval; 2061 2062 if (c.kind == CXCursorKind.typeRef) { 2063 auto cref = c.referenced; 2064 appendParams(cref, rval); 2065 } else { 2066 appendParams(c, rval); 2067 } 2068 2069 return rval; 2070 } 2071 2072 /// Join an array slice of PTuples to a parameter string of "type" "id" 2073 private string joinParamId(ExtractParamsResult[] r) { 2074 import std.algorithm : joiner, map, filter; 2075 import std.conv : text; 2076 import std.range : enumerate; 2077 2078 static string getTypeId(ref ExtractParamsResult p, ulong uid) { 2079 if (p.id.length == 0) { 2080 //TODO decide if to autogenerate for unnamed parameters here or later 2081 //return p.tka.toStringDecl("x" ~ text(uid)); 2082 return p.result.type.toStringDecl(""); 2083 } else { 2084 return p.result.type.toStringDecl(p.id); 2085 } 2086 } 2087 2088 // using cache to avoid calling getName twice. 2089 return r.enumerate 2090 .map!(a => getTypeId(a.value, a.index)) 2091 .filter!(a => a.length > 0) 2092 .joiner(", ").text(); 2093 2094 } 2095 2096 private Nullable!string translateCursorType(CXTypeKind kind) 2097 in { 2098 import std.conv : to; 2099 2100 logger.trace(to!string(kind)); 2101 } 2102 out (result) { 2103 logger.trace(!result.isNull, result); 2104 } 2105 do { 2106 Nullable!string r; 2107 2108 // a good file to see what the types are: 2109 // https://github.com/llvm-mirror/clang/blob/master/include/clang/AST/BuiltinTypes.def 2110 2111 switch (kind) with (CXTypeKind) { 2112 case invalid: 2113 break; 2114 case unexposed: 2115 break; 2116 case void_: 2117 r = "void"; 2118 break; 2119 case bool_: 2120 r = "bool"; 2121 break; 2122 case charU: 2123 r = "unsigned char"; 2124 break; 2125 case uChar: 2126 r = "unsigned char"; 2127 break; 2128 case char16: 2129 break; 2130 case char32: 2131 break; 2132 case uShort: 2133 r = "unsigned short"; 2134 break; 2135 case uInt: 2136 r = "unsigned int"; 2137 break; 2138 case uLong: 2139 r = "unsigned long"; 2140 break; 2141 case uLongLong: 2142 r = "unsigned long long"; 2143 break; 2144 case uInt128: 2145 r = "__uint128_t"; 2146 break; 2147 case charS: 2148 r = "char"; 2149 break; 2150 case sChar: 2151 r = "char"; 2152 break; 2153 case wChar: 2154 r = "wchar_t"; 2155 break; 2156 case short_: 2157 r = "short"; 2158 break; 2159 case int_: 2160 r = "int"; 2161 break; 2162 case long_: 2163 r = "long"; 2164 break; 2165 case longLong: 2166 r = "long long"; 2167 break; 2168 case int128: 2169 r = "__int128_t"; 2170 break; 2171 case float_: 2172 r = "float"; 2173 break; 2174 case double_: 2175 r = "double"; 2176 break; 2177 case longDouble: 2178 r = "long double"; 2179 break; 2180 case nullPtr: 2181 r = "nullptr"; 2182 break; 2183 case overload: 2184 // The type of an unresolved overload set. A placeholder type. 2185 // Expressions with this type have one of the following basic 2186 // forms, with parentheses generally permitted: 2187 // foo # possibly qualified, not if an implicit access 2188 // foo # possibly qualified, not if an implicit access 2189 // &foo # possibly qualified, not if an implicit access 2190 // x->foo # only if might be a static member function 2191 // &x->foo # only if might be a static member function 2192 // &Class::foo # when a pointer-to-member; sub-expr also has this type 2193 // OverloadExpr::find can be used to analyze the expression. 2194 // 2195 // Overload should be the first placeholder type, or else change 2196 // BuiltinType::isNonOverloadPlaceholderType() 2197 break; 2198 case dependent: 2199 // This represents the type of an expression whose type is 2200 // totally unknown, e.g. 'T::foo'. It is permitted for this to 2201 // appear in situations where the structure of the type is 2202 // theoretically deducible. 2203 break; 2204 2205 case objCId: 2206 case objCClass: 2207 case objCSel: 2208 break; 2209 2210 case float128: 2211 r = "__float128"; 2212 break; 2213 2214 case half: 2215 // half in OpenCL, otherwise __fp16 2216 case float16: 2217 r = "__fp16"; 2218 break; 2219 2220 case shortAccum: 2221 r = "short _Accum"; 2222 break; 2223 case accum: 2224 r = "_Accum"; 2225 break; 2226 case longAccum: 2227 r = "long _Accum"; 2228 break; 2229 case uShortAccum: 2230 r = "unsigned short _Accum"; 2231 break; 2232 case uAccum: 2233 r = "unsigned _Accum"; 2234 break; 2235 case uLongAccum: 2236 r = "unsigned long _Accum"; 2237 break; 2238 2239 case complex: 2240 case pointer: 2241 case blockPointer: 2242 case lValueReference: 2243 case rValueReference: 2244 case record: 2245 case enum_: 2246 case typedef_: 2247 case objCInterface: 2248 case objCObjectPointer: 2249 case functionNoProto: 2250 case functionProto: 2251 case constantArray: 2252 case vector: 2253 case incompleteArray: 2254 case variableArray: 2255 case dependentSizedArray: 2256 case memberPointer: 2257 break; 2258 2259 case auto_: 2260 r = "auto"; 2261 break; 2262 2263 /** 2264 * \brief Represents a type that was referred to using an elaborated type keyword. 2265 * 2266 * E.g., struct S, or via a qualified name, e.g., N::M::type, or both. 2267 */ 2268 case elaborated: 2269 case pipe: 2270 case oclImage1dRO: 2271 case oclImage1dArrayRO: 2272 case oclImage1dBufferRO: 2273 case oclImage2dRO: 2274 case oclImage2dArrayRO: 2275 case oclImage2dDepthRO: 2276 case oclImage2dArrayDepthRO: 2277 case oclImage2dMSAARO: 2278 case oclImage2dArrayMSAARO: 2279 case oclImage2dMSAADepthRO: 2280 case oclImage2dArrayMSAADepthRO: 2281 case oclImage3dRO: 2282 case oclImage1dWO: 2283 case oclImage1dArrayWO: 2284 case oclImage1dBufferWO: 2285 case oclImage2dWO: 2286 case oclImage2dArrayWO: 2287 case oclImage2dDepthWO: 2288 case oclImage2dArrayDepthWO: 2289 case oclImage2dMSAAWO: 2290 case oclImage2dArrayMSAAWO: 2291 case oclImage2dMSAADepthWO: 2292 case oclImage2dArrayMSAADepthWO: 2293 case oclImage3dWO: 2294 case oclImage1dRW: 2295 case oclImage1dArrayRW: 2296 case oclImage1dBufferRW: 2297 case oclImage2dRW: 2298 case oclImage2dArrayRW: 2299 case oclImage2dDepthRW: 2300 case oclImage2dArrayDepthRW: 2301 case oclImage2dMSAARW: 2302 case oclImage2dArrayMSAARW: 2303 case oclImage2dMSAADepthRW: 2304 case oclImage2dArrayMSAADepthRW: 2305 case oclImage3dRW: 2306 case oclSampler: 2307 case oclEvent: 2308 case oclQueue: 2309 case oclReserveID: 2310 2311 case objCObject: 2312 case objCTypeParam: 2313 case attributed: 2314 2315 case oclIntelSubgroupAVCMcePayload: 2316 case oclIntelSubgroupAVCImePayload: 2317 case oclIntelSubgroupAVCRefPayload: 2318 case oclIntelSubgroupAVCSicPayload: 2319 case oclIntelSubgroupAVCMceResult: 2320 case oclIntelSubgroupAVCImeResult: 2321 case oclIntelSubgroupAVCRefResult: 2322 case oclIntelSubgroupAVCSicResult: 2323 case oclIntelSubgroupAVCImeResultSingleRefStreamout: 2324 case oclIntelSubgroupAVCImeResultDualRefStreamout: 2325 case oclIntelSubgroupAVCImeSingleRefStreamin: 2326 2327 case oclIntelSubgroupAVCImeDualRefStreamin: 2328 2329 break; 2330 default: 2331 } 2332 2333 return r; 2334 }