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