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