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