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