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