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