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