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