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