1 module clang;
2 
3 
4 import clang.c.index;
5 import clang.c.util: EnumD;
6 
7 
8 
9 mixin EnumD!("TranslationUnitFlags", CXTranslationUnit_Flags, "CXTranslationUnit_");
10 mixin EnumD!("Language", CXLanguageKind, "CXLanguage_");
11 
12 
13 TranslationUnit parse(in string fileName,
14                       in TranslationUnitFlags translUnitflags = TranslationUnitFlags.None)
15     @safe
16 {
17     return parse(fileName, [], translUnitflags);
18 }
19 
20 
21 mixin EnumD!("ErrorCode", CXErrorCode, "");
22 mixin EnumD!("DiagnosticSeverity", CXDiagnosticSeverity, "CXDiagnostic_");
23 mixin EnumD!("TemplateArgumentKind", CXTemplateArgumentKind, "CXTemplateArgumentKind_");
24 
25 
26 TranslationUnit parse(in string fileName,
27                       in string[] commandLineArgs,
28                       in TranslationUnitFlags translUnitflags = TranslationUnitFlags.None)
29     @safe
30 {
31 
32     import std.string: toStringz;
33     import std.algorithm: map;
34     import std.array: array, join;
35     import std.conv: text;
36 
37     // faux booleans
38     const excludeDeclarationsFromPCH = 0;
39     const displayDiagnostics = 0;
40     auto index = clang_createIndex(excludeDeclarationsFromPCH, displayDiagnostics);
41     scope(exit) clang_disposeIndex(index);
42     CXUnsavedFile[] unsavedFiles;
43     const commandLineArgz = commandLineArgs
44         .map!(a => a.toStringz)
45         .array;
46 
47     CXTranslationUnit cx;
48     const err = () @trusted {
49         return cast(ErrorCode)clang_parseTranslationUnit2(
50             index,
51             fileName.toStringz,
52             commandLineArgz.ptr, // .ptr since the length can be 0
53             cast(int)commandLineArgz.length,
54             unsavedFiles.ptr,  // .ptr since the length can be 0
55             cast(uint)unsavedFiles.length,
56             translUnitflags,
57             &cx,
58         );
59     }();
60 
61     if(err != ErrorCode.success) {
62         throw new Exception(text("Could not parse ", fileName, ": ", err));
63     }
64 
65     string[] errorMessages;
66     // throw if there are error diagnostics
67     foreach(i; 0 .. clang_getNumDiagnostics(cx)) {
68         auto diagnostic = clang_getDiagnostic(cx, i);
69         scope(exit) clang_disposeDiagnostic(diagnostic);
70         const severity = cast(DiagnosticSeverity) clang_getDiagnosticSeverity(diagnostic);
71         enum diagnosticOptions = CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn;
72         if(severity == DiagnosticSeverity.Error || severity == DiagnosticSeverity.Fatal)
73             errorMessages ~= clang_formatDiagnostic(diagnostic, diagnosticOptions).toString;
74     }
75 
76     if(errorMessages.length > 0)
77         throw new Exception(text("Error parsing '", fileName, "':\n",
78                                  errorMessages.join("\n")));
79 
80 
81     return TranslationUnit(cx);
82 }
83 
84 string[] systemPaths() @safe {
85     import std.process: execute;
86     import std.string: splitLines, stripLeft;
87     import std.algorithm: map, countUntil;
88     import std.array: array;
89 
90     version(Windows)
91     {
92         enum devnull = "NUL";
93     } else {
94         enum devnull = "/dev/null";
95     }
96 
97     const res = () {
98         try
99         {
100             return execute(["clang", "-v", "-xc++", devnull, "-fsyntax-only"], ["LANG": "C"]);
101         }
102         catch (Exception e)
103         {
104             import std.typecons : Tuple;
105             return Tuple!(int, "status", string, "output")(-1, e.msg);
106         }
107     }();
108     if(res.status != 0) throw new Exception("Failed to call clang:\n" ~ res.output);
109 
110     auto lines = res.output.splitLines;
111 
112     const startIndex = lines.countUntil("#include <...> search starts here:") + 1;
113     assert(startIndex > 0);
114     const endIndex = lines.countUntil("End of search list.");
115     assert(endIndex > 0);
116 
117     return lines[startIndex .. endIndex].map!stripLeft.array;
118 }
119 
120 
121 mixin EnumD!("ChildVisitResult", CXChildVisitResult, "CXChildVisit_");
122 alias CursorVisitor = ChildVisitResult delegate(Cursor cursor, Cursor parent);
123 
124 struct TranslationUnit {
125 
126     CXTranslationUnit cx;
127     Cursor cursor;
128 
129     this(CXTranslationUnit cx) @safe nothrow {
130         this.cx = cx;
131         this.cursor = Cursor(clang_getTranslationUnitCursor(cx));
132     }
133 
134     // This pair of functions *should* work but crash dpp's tests intead
135     // A memory leak is a better than a crash, so...
136 
137     // @disable this(this);
138 
139     // ~this() @safe @nogc pure nothrow {
140     //     clang_disposeTranslationUnit(cx);
141     // }
142 
143     string spelling() @safe pure nothrow const {
144         return clang_getTranslationUnitSpelling(cx).toString;
145     }
146 
147     Language language() @safe pure nothrow const {
148         return fileNameToLanguage(spelling);
149     }
150 }
151 
152 Language fileNameToLanguage(in string fileName) @safe pure nothrow {
153     import std.path: extension;
154     import std.algorithm: among;
155 
156     if(fileName.extension.among(".cpp", ".cxx", ".C", ".cc", ".c++",
157                                 ".hpp", ".hh", ".H", ".hxx", ".h++"))
158         return Language.CPlusPlus;
159 
160     return Language.C;
161 
162 }
163 
164 string toString(CXString cxString) @safe pure nothrow {
165     import std.string: fromStringz;
166 
167     scope(exit) clang_disposeString(cxString);
168     auto cstr = clang_getCString(cxString);
169     return  () @trusted { return cstr.fromStringz.idup; }();
170 }
171 
172 
173 string[] toStrings(CXStringSet* strings) @safe pure nothrow {
174     import std.string: fromStringz;
175     import std.array: appender;
176 
177     scope(exit) clang_disposeStringSet(strings);
178 
179     auto app = appender!(string[]);
180     app.reserve(strings.Count);
181 
182     foreach(cxstr; () @trusted { return strings.Strings[0 .. strings.Count]; }()) {
183         // cannot use the toString above since it frees, and so
184         // does the dispose string set at scope exit, leading to
185         // a double free situation
186         auto cstr = clang_getCString(cxstr);
187         auto str = () @trusted { return cstr.fromStringz.idup; }();
188         app ~= str;
189     }
190 
191     return app.data;
192 }
193 
194 
195 mixin EnumD!("AccessSpecifier", CX_CXXAccessSpecifier, "CX_CXX");
196 
197 
198 struct Cursor {
199 
200     import clang.util: Lazy;
201     import std.traits: ReturnType;
202 
203     mixin EnumD!("Kind", CXCursorKind, "CXCursor_");
204     mixin EnumD!("StorageClass", CX_StorageClass, "CX_SC_");
205 
206     alias Hash = ReturnType!clang_hashCursor;
207 
208     CXCursor cx;
209     private Cursor[] _children;
210     Kind kind;
211     private string _spelling;
212     Type type;
213     Type underlyingType;
214     private SourceRange _sourceRange;
215 
216     mixin Lazy!_spelling;
217     mixin Lazy!_sourceRange;
218 
219     this(CXCursor cx) @safe @nogc pure nothrow {
220         this.cx = cx;
221         kind = cast(Kind) clang_getCursorKind(cx);
222         type = Type(clang_getCursorType(cx));
223 
224         if(kind == Cursor.Kind.TypedefDecl || kind == Cursor.Kind.TypeAliasDecl)
225             underlyingType = Type(clang_getTypedefDeclUnderlyingType(cx));
226     }
227 
228     this(in Kind kind, in string spelling) @safe @nogc pure nothrow {
229         this(kind, spelling, Type());
230     }
231 
232     this(in Kind kind, in string spelling, Type type) @safe @nogc pure nothrow {
233         this.kind = kind;
234         this._spelling = spelling;
235         this._spellingInit = true;
236         this.type = type;
237     }
238 
239     /// Lazily return the cursor's children
240     auto children(this This)() @property {
241         import std.array: appender;
242         import std.traits: isMutable;
243 
244         if(_children.length) return _children;
245 
246         auto app = appender!(Cursor[]);
247         app.reserve(10); // hacky but speeds things up, faster than counting the right number
248         // calling Cursor.visitChildren here would cause infinite recursion
249         // because cvisitor constructs a Cursor out of the parent
250         () @trusted { clang_visitChildren(cx, &childrenVisitor, &app); }();
251 
252         static if(isMutable!This) {
253             _children = app.data;
254             return _children;
255         } else
256             return app.data;
257     }
258 
259     private static extern(C) CXChildVisitResult childrenVisitor(CXCursor cursor,
260                                                                 CXCursor parent,
261                                                                 void* clientData)
262         @safe nothrow
263     {
264         import std.array: Appender;
265 
266         auto app = () @trusted { return cast(Appender!(Cursor[])*) clientData; }();
267         *app ~= Cursor(cursor);
268 
269         return CXChildVisit_Continue;
270     }
271 
272     void children(Cursor[] cursors) @safe @property pure nothrow {
273         _children = cursors;
274     }
275 
276     void setSpelling(string str) @safe @nogc @property pure nothrow {
277         _spelling = str;
278         _spellingInit = true;
279     }
280 
281     Type returnType() @safe pure nothrow const {
282         return Type(clang_getCursorResultType(cx));
283     }
284 
285     /**
286        For EnumConstantDecl cursors, return the numeric value
287      */
288     auto enumConstantValue() @safe @nogc pure nothrow const {
289         assert(kind == Cursor.Kind.EnumConstantDecl);
290         return clang_getEnumConstantDeclValue(cx);
291     }
292 
293     Language language() @safe @nogc pure nothrow const {
294         return cast(Language) clang_getCursorLanguage(cx);
295     }
296 
297     Cursor canonical() @safe nothrow const {
298         return Cursor(clang_getCanonicalCursor(cx));
299     }
300 
301     /**
302        If this is the canonical cursor. Given forward declarations, there may
303        be several cursors for one entity. This returns true if this cursor
304        is the canonical one.
305      */
306     bool isCanonical() @safe @nogc pure nothrow const {
307         return cast(bool) clang_equalCursors(cx, clang_getCanonicalCursor(cx));
308     }
309 
310     bool isDefinition() @safe @nogc pure nothrow const {
311         return cast(bool) clang_isCursorDefinition(cx);
312     }
313 
314     bool isNull() @safe @nogc pure nothrow const {
315         return cast(bool) clang_Cursor_isNull(cx);
316     }
317 
318     static Cursor nullCursor() @safe nothrow {
319         return Cursor(clang_getNullCursor());
320     }
321 
322     Cursor definition() @safe nothrow const {
323         return Cursor(clang_getCursorDefinition(cx));
324     }
325 
326     string toString() @safe pure nothrow const {
327         import std.conv: text;
328         try {
329             const returnTypeStr = kind == Kind.FunctionDecl
330                 ? text(", ", returnType)
331                 : "";
332 
333             return text("Cursor(", kind, `, "`, spelling, `", `, type, returnTypeStr, ")");
334         } catch(Exception e)
335             assert(false, "Fatal error in Cursor.toString: " ~ e.msg);
336     }
337 
338     bool isPredefined() @safe pure nothrow const {
339         import clang.static_: gPredefinedCursors;
340         return (spelling in gPredefinedCursors) !is null;
341     }
342 
343     Cursor semanticParent() @safe nothrow const {
344         return Cursor(clang_getCursorSemanticParent(cx));
345     }
346 
347     Cursor lexicalParent() @safe nothrow const {
348         return Cursor(clang_getCursorLexicalParent(cx));
349     }
350 
351     bool isInvalid() @safe @nogc pure nothrow const {
352         return cast(bool) clang_isInvalid(cx.kind);
353     }
354 
355     auto hash() @safe @nogc pure nothrow const {
356         return clang_hashCursor(cx);
357     }
358 
359     string mangling() @safe pure nothrow const {
360 
361         // constructors and destructors can have multiple mangles,
362         // but everything else is simpler
363         if(kind != Kind.Constructor && kind != Kind.Destructor)
364             return clang_Cursor_getMangling(cx).toString;
365 
366         // for (con|de)structors, there may be multiple mangles,
367         // and the getMangling function doesn't always return
368         // the right one. To be honest, I don't know how to find
369         // the right one all the time, but in testing, the first
370         // one on this function, if it returns one, works more often.
371         // I wish I could explain more, I just know this passes the tests
372         // and the plain impl of just getMangling doesn't.
373         string mangle;
374 
375         auto otherMangles = clang_Cursor_getCXXManglings(cx);
376         if(otherMangles) {
377             auto strings = toStrings(otherMangles);
378             if(strings.length)
379                 mangle = strings[0];
380         }
381         if(mangle is null)
382             mangle = clang_Cursor_getMangling(cx).toString;
383         return mangle;
384     }
385 
386     bool isAnonymous() @safe @nogc pure nothrow const {
387         return cast(bool) clang_Cursor_isAnonymous(cx);
388     }
389 
390     bool isBitField() @safe @nogc pure nothrow const {
391         return cast(bool) clang_Cursor_isBitField(cx);
392     }
393 
394     int bitWidth() @safe @nogc pure nothrow const {
395         return clang_getFieldDeclBitWidth(cx);
396     }
397 
398     auto accessSpecifier() @safe @nogc pure nothrow const {
399         return cast(AccessSpecifier) clang_getCXXAccessSpecifier(cx);
400     }
401 
402     StorageClass storageClass() @safe @nogc pure nothrow const {
403         return cast(StorageClass) clang_Cursor_getStorageClass(cx);
404     }
405 
406     bool isConstCppMethod() @safe @nogc pure nothrow const {
407         return cast(bool) clang_CXXMethod_isConst(cx);
408     }
409 
410     bool isMoveConstructor() @safe @nogc pure nothrow const {
411         return cast(bool) clang_CXXConstructor_isMoveConstructor(cx);
412     }
413 
414     bool isCopyConstructor() @safe @nogc pure nothrow const {
415         return cast(bool) clang_CXXConstructor_isCopyConstructor(cx);
416     }
417 
418     bool isMacroFunction() @safe @nogc pure nothrow const {
419         return cast(bool) clang_Cursor_isMacroFunctionLike(cx);
420     }
421 
422     bool isMacroBuiltin() @safe @nogc pure nothrow const {
423         return cast(bool) clang_Cursor_isMacroBuiltin(cx);
424     }
425 
426     Cursor specializedCursorTemplate() @safe pure nothrow const {
427         return Cursor(clang_getSpecializedCursorTemplate(cx));
428     }
429 
430     TranslationUnit translationUnit() @safe nothrow const {
431         return TranslationUnit(clang_Cursor_getTranslationUnit(cx));
432     }
433 
434     Language translationUnitLanguage() @safe pure nothrow const {
435         return fileNameToLanguage(clang_getTranslationUnitSpelling(clang_Cursor_getTranslationUnit(cx)).toString);
436     }
437 
438     Token[] tokens() @safe nothrow const {
439         import std.algorithm: map;
440         import std.array: array;
441 
442         CXToken* tokens;
443         uint numTokens;
444 
445         auto tu = clang_Cursor_getTranslationUnit(cx);
446 
447         () @trusted { clang_tokenize(tu, sourceRange.cx, &tokens, &numTokens); }();
448         // I hope this only deallocates the array
449         scope(exit) clang_disposeTokens(tu, tokens, numTokens);
450 
451         auto tokenSlice = () @trusted { return tokens[0 .. numTokens]; }();
452 
453         return tokenSlice.map!(a => Token(a, tu)).array;
454     }
455 
456     alias templateParams = templateParameters;
457 
458     const(Cursor)[] templateParameters() @safe nothrow const {
459         import std.algorithm: filter;
460         import std.array: array;
461 
462         const amTemplate =
463             kind == Cursor.Kind.ClassTemplate
464             || kind == Cursor.Kind.TypeAliasTemplateDecl
465             || kind == Cursor.Kind.FunctionTemplate
466             ;
467         auto templateCursor = amTemplate ? this : specializedCursorTemplate;
468 
469         auto range = templateCursor
470             .children
471             .filter!(a => a.kind == Cursor.Kind.TemplateTypeParameter ||
472                           a.kind == Cursor.Kind.NonTypeTemplateParameter);
473 
474         // Why is this @system? Who knows.
475         return () @trusted { return range.array; }();
476     }
477 
478     /**
479        If declared at file scope.
480      */
481     bool isFileScope() @safe nothrow const {
482         return lexicalParent.kind == Cursor.Kind.TranslationUnit;
483     }
484 
485     int numTemplateArguments() @safe @nogc pure nothrow const {
486         return clang_Cursor_getNumTemplateArguments(cx);
487     }
488 
489     TemplateArgumentKind templateArgumentKind(int i) @safe @nogc pure nothrow const {
490         return cast(TemplateArgumentKind) clang_Cursor_getTemplateArgumentKind(cx, i);
491     }
492 
493     Type templateArgumentType(int i) @safe pure nothrow const {
494         return Type(clang_Cursor_getTemplateArgumentType(cx, i));
495     }
496 
497     long templateArgumentValue(int i) @safe @nogc pure nothrow const {
498         return clang_Cursor_getTemplateArgumentValue(cx, i);
499     }
500 
501     bool isVirtual() @safe @nogc pure nothrow const {
502         return cast(bool) clang_CXXMethod_isVirtual(cx);
503     }
504 
505     bool isPureVirtual() @safe @nogc pure nothrow const {
506         return cast(bool) clang_CXXMethod_isPureVirtual(cx);
507     }
508 
509     string displayName() @safe pure nothrow const {
510         return clang_getCursorDisplayName(cx).toString;
511     }
512 
513     /**  Get the raw declaration comment for this referent, if one exists. */
514     auto raw_comment() @safe pure nothrow const {
515         import std.typecons: Nullable;
516         auto cxrawcomment = clang_Cursor_getRawCommentText(cx);
517         if (cxrawcomment.data != null) {
518             return Nullable!string(cxrawcomment.toString());
519         } else {
520             return Nullable!string.init;
521         }
522     }
523 
524     /**  Get the referent parsed comment. */
525     auto comment() const @nogc {
526         import std.typecons: Nullable;
527         auto cxcomment = clang_Cursor_getParsedComment(cx);
528         if (cxcomment.ASTNode != null) {
529             return Nullable!Comment(Comment(cxcomment));
530         } else {
531             return Nullable!Comment.init;
532         }
533     }
534 
535     /**
536        For e.g. TypeRef or TemplateRef
537      */
538     Cursor referencedCursor() @safe nothrow const {
539         return Cursor(clang_getCursorReferenced(cx));
540     }
541 
542     Cursor[] overriddenCursors() @trusted /* @safe with DIP1000 */ const {
543         import std.algorithm: map;
544         import std.array: array;
545 
546         uint length;
547         CXCursor* cursors;
548 
549         clang_getOverriddenCursors(cx, &cursors, &length);
550         scope(exit) clang_disposeOverriddenCursors(cursors);
551 
552         return cursors[0 .. length].map!(a => Cursor(a)).array;
553     }
554 
555     auto numOverloadedDecls() @safe @nogc pure nothrow const {
556         return clang_getNumOverloadedDecls(cx);
557     }
558 
559     Cursor overloadedDecl(int i) @safe nothrow const {
560         return Cursor(clang_getOverloadedDecl(cx, cast(uint) i));
561     }
562 
563     bool opEquals(ref const(Cursor) other) @safe @nogc pure nothrow const {
564         return cast(bool) clang_equalCursors(cx, other.cx);
565     }
566 
567     bool opEquals(in Cursor other) @safe @nogc pure nothrow const {
568         return cast(bool) clang_equalCursors(cx, other.cx);
569     }
570 
571     void visitChildren(scope CursorVisitor visitor) @safe nothrow const {
572         scope clientData = ClientData(visitor);
573         // why isn't this @safe with dip10000???
574         () @trusted { clang_visitChildren(cx, &cvisitor, &clientData); }();
575     }
576 
577     int opApply(scope int delegate(Cursor cursor, Cursor parent) @safe block) @safe nothrow const {
578         return opApplyN(block);
579     }
580 
581     int opApply(scope int delegate(Cursor cursor) @safe block) @safe nothrow const {
582         return opApplyN(block);
583     }
584 
585     private int opApplyN(T)(scope T block) const {
586         import std.traits: Parameters;
587 
588         int stop = 0;
589 
590         enum numParams = Parameters!T.length;
591 
592         visitChildren((cursor, parent) {
593 
594             static if(numParams == 2)
595                 stop = block(cursor, parent);
596             else static if(numParams == 1)
597                 stop = block(cursor);
598             else
599                 static assert(false);
600 
601             return stop
602                 ? ChildVisitResult.Break
603                 : ChildVisitResult.Continue;
604         });
605 
606         return stop;
607     }
608 
609     private string _spellingCreate() @safe pure nothrow const {
610         return clang_getCursorSpelling(cx).toString;
611     }
612 
613     private SourceRange _sourceRangeCreate() @safe pure nothrow const {
614         return SourceRange(clang_getCursorExtent(cx));
615     }
616 }
617 
618 
619 struct SourceRange {
620 
621     import clang.util: Lazy;
622 
623     CXSourceRange cx;
624     private SourceLocation _start;
625     private SourceLocation _end;
626 
627     mixin Lazy!_start;
628     mixin Lazy!_end;
629 
630     this(CXSourceRange cx) @safe @nogc pure nothrow {
631         this.cx = cx;
632     }
633 
634     string path() @safe nothrow const {
635         return start.path;
636     }
637 
638     string toString() @safe pure const {
639         import std.conv: text;
640         return text(`SourceRange("`, start.path, `", `, start.line, ":", start.column, ", ", end.line, ":", end.column, ")");
641     }
642 
643     private auto _startCreate() @safe pure nothrow const {
644         return SourceLocation(clang_getRangeStart(cx));
645     }
646 
647     private auto _endCreate() @safe pure nothrow const {
648         return SourceLocation(clang_getRangeEnd(cx));
649     }
650 }
651 
652 
653 struct SourceLocation {
654 
655     CXSourceLocation cx;
656     string path;
657     uint line;
658     uint column;
659     uint offset;
660 
661     this(CXSourceLocation cx) @safe pure nothrow {
662         this.cx = cx;
663 
664         CXFile file;
665         () @trusted { clang_getExpansionLocation(cx, &file, null, null, null); }();
666         this.path = clang_getFileName(file).toString;
667 
668        () @trusted { clang_getSpellingLocation(cx, &file, &line, &column, &offset); }();
669     }
670 
671     int opCmp(ref const(SourceLocation) other) @safe @nogc pure nothrow const {
672         if(path == other.path && line == other.line && column == other.column &&
673            offset == other.offset)
674             return 0;
675 
676         if(path < other.path) return -1;
677         if(path > other.path) return 1;
678         if(line < other.line) return -1;
679         if(line > other.line) return 1;
680         if(column < other.column) return -1;
681         if(column > other.column) return 1;
682         if(offset < other.offset) return -1;
683         if(offset > other.offset) return 1;
684         assert(false);
685     }
686 
687     string toString() @safe pure nothrow const {
688         import std.conv: text;
689         return text(`"`, path, `" `, line, ":", column, ":", offset);
690     }
691 }
692 
693 private struct ClientData {
694     /**
695        The D visitor delegate
696      */
697     CursorVisitor dvisitor;
698 }
699 
700 // This is the C function actually passed to libclang's clang_visitChildren
701 // The context (clientData) contains the D delegate that's then called on the
702 // (cursor, parent) pair
703 private extern(C) CXChildVisitResult cvisitor(CXCursor cursor, CXCursor parent, void* clientData_) {
704     auto clientData = cast(ClientData*) clientData_;
705     return cast(CXChildVisitResult) clientData.dvisitor(Cursor(cursor), Cursor(parent));
706 }
707 
708 
709 struct Type {
710 
711     import clang.util: Lazy;
712 
713     mixin EnumD!("Kind", CXTypeKind, "CXType_");
714 
715     CXType cx;
716     Kind kind;
717     private string _spelling;
718 
719     mixin Lazy!_spelling;
720 
721     this(CXType cx) @safe @nogc pure nothrow {
722         this.cx = cx;
723         this.kind = cast(Kind) cx.kind;
724     }
725 
726     this(in Type other) @trusted pure nothrow {
727         import std.algorithm: map;
728         import std.array: array;
729 
730         this.cx.kind = other.cx.kind;
731         this.cx.data[] = other.cx.data[].map!(a => cast(void*) a).array;
732 
733         this(this.cx);
734     }
735 
736     this(in Kind kind) @safe @nogc pure nothrow {
737         this(kind, "");
738     }
739 
740     this(in Kind kind, in string spelling) @safe @nogc pure nothrow {
741         this.kind = kind;
742         _spelling = spelling;
743     }
744 
745     Type pointee() @safe pure nothrow const {
746         return Type(clang_getPointeeType(cx));
747     }
748 
749     Type unelaborate() @safe nothrow const {
750         return Type(clang_Type_getNamedType(cx));
751     }
752 
753     Type canonical() @safe pure nothrow const {
754         return Type(clang_getCanonicalType(cx));
755     }
756 
757     Type returnType() @safe pure const {
758         return Type(clang_getResultType(cx));
759     }
760 
761     // Returns a range of Type
762     auto paramTypes()() @safe pure const nothrow {
763 
764         static struct Range {
765             const CXType cx;
766             const int numArgs;
767             int index = 0;
768 
769             bool empty() {
770                 return index < 0 || index >= numArgs;
771             }
772 
773             void popFront() {
774                 ++index;
775             }
776 
777             Type front() {
778                 return Type(clang_getArgType(cx, index));
779             }
780         }
781 
782         return Range(cx, clang_getNumArgTypes(cx));
783     }
784 
785     bool isVariadicFunction() @safe @nogc pure nothrow const {
786         return cast(bool) clang_isFunctionTypeVariadic(cx);
787     }
788 
789     Type elementType() @safe pure nothrow const {
790         return Type(clang_getElementType(cx));
791     }
792 
793     long numElements() @safe @nogc pure nothrow const {
794         return clang_getNumElements(cx);
795     }
796 
797     long arraySize() @safe @nogc pure nothrow const {
798         return clang_getArraySize(cx);
799     }
800 
801     bool isConstQualified() @safe @nogc pure nothrow const scope {
802         return cast(bool) clang_isConstQualifiedType(cx);
803     }
804 
805     bool isVolatileQualified() @safe @nogc pure nothrow const scope {
806         return cast(bool) clang_isVolatileQualifiedType(cx);
807     }
808 
809     Cursor declaration() @safe pure nothrow const {
810         return Cursor(clang_getTypeDeclaration(cx));
811     }
812 
813     Type namedType() @safe pure nothrow const {
814         return Type(clang_Type_getNamedType(cx));
815     }
816 
817     bool opEquals(ref const(Type) other) @safe @nogc pure nothrow const {
818         return cast(bool) clang_equalTypes(cx, other.cx);
819     }
820 
821     bool opEquals(in Type other) @safe @nogc pure nothrow const {
822         return cast(bool) clang_equalTypes(cx, other.cx);
823     }
824 
825     bool isInvalid() @safe @nogc pure nothrow const {
826         return kind == Kind.Invalid;
827     }
828 
829     long getSizeof() @safe @nogc pure nothrow const {
830         return clang_Type_getSizeOf(cx);
831     }
832 
833     int numTemplateArguments() @safe @nogc pure nothrow const {
834         return clang_Type_getNumTemplateArguments(cx);
835     }
836 
837     Type typeTemplateArgument(int i) @safe pure nothrow const {
838         return Type(clang_Type_getTemplateArgumentAsType(cx, i));
839     }
840 
841     string toString() @safe pure nothrow const {
842         import std.conv: text;
843 
844         try {
845             return text("Type(", kind, `, "`, spelling, `")`);
846         } catch(Exception e)
847             assert(false, "Fatal error in Type.toString: " ~ e.msg);
848     }
849 
850     private string _spellingCreate() @safe pure nothrow const {
851         return clang_getTypeSpelling(cx).toString;
852     }
853 }
854 
855 
856 struct Token {
857 
858     mixin EnumD!("Kind", CXTokenKind, "CXToken_");
859 
860     Kind kind;
861     string spelling;
862     CXToken cxToken;
863     CXTranslationUnit cxTU;
864 
865     this(CXToken cxToken, CXTranslationUnit cxTU) @safe pure nothrow {
866         this.cxToken = cxToken;
867         this.cxTU = cxTU;
868         this.kind = cast(Kind) clang_getTokenKind(cxToken);
869         this.spelling = .toString(clang_getTokenSpelling(cxTU, cxToken));
870     }
871 
872     this(Kind kind, string spelling) @safe @nogc pure nothrow {
873         this.kind = kind;
874         this.spelling = spelling;
875     }
876 
877     string toString() @safe pure const {
878         import std.conv: text;
879 
880         return text("Token(", kind, `, "`, spelling, `")`);
881     }
882 
883     bool opEquals(in Token other) @safe pure nothrow const {
884         return kind == other.kind && spelling == other.spelling;
885     }
886 }
887 
888 /** A comment in the source text. */
889 struct Comment {
890     CXComment cx;
891 
892     /**  What kind of comment is this? */
893     auto kind() @nogc {
894         return clang_Comment_getKind(cx);
895     }
896 
897     /**  Get this comment children comment */
898     auto get_children() @nogc {
899         return CommentChildren(cx, clang_Comment_getNumChildren(cx), 0);
900     }
901 
902     /**  Given that this comment is the start or end of an HTML tag, get its tag name. */
903     auto get_tag_name() {
904         return toString(clang_HTMLTagComment_getTagName(cx));
905     }
906 
907     /**  Given that this comment is an HTML start tag index, get its attributes. */
908     auto get_tag_attrs() @nogc {
909         return CommentAttributes(cx, clang_HTMLStartTag_getNumAttrs(cx), 0);
910     }
911 }
912 
913 /**  A range for a comment children */
914 struct CommentChildren {
915     CXComment parent;
916     const uint length;
917     uint index;
918 
919     /** get the current child */
920     auto front() @nogc {
921         return Comment(clang_Comment_getChild(parent, index));
922     }
923 
924     /** increment the index */
925     void popFront() pure @nogc nothrow @safe {
926         index++;
927     }
928 
929     /** is it the end? */
930     auto empty() const pure @nogc nothrow @safe {
931         return index == length;
932     }
933 }
934 
935 /**  An HTML start tag comment attribute */
936 struct CommentAttribute {
937     /**  HTML start tag attribute name */
938     string name;
939     /**  HTML start tag attribute value */
940     string value;
941 }
942 
943 /**  An range for a comment attributes */
944 struct CommentAttributes {
945     CXComment cx;
946     const uint length;
947     uint index;
948 
949     /** get the current attribute */
950     auto front() {
951         return CommentAttribute(
952             toString(clang_HTMLStartTag_getAttrName(cx, index)),
953             toString(clang_HTMLStartTag_getAttrValue(cx, index))
954         );
955     }
956 
957     /** increment the index */
958     void popFront() pure @nogc nothrow @safe {
959         index++;
960     }
961 
962     /** is it the end? */
963     auto empty() const pure @nogc nothrow @safe {
964         return index == length;
965     }
966 }