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 
328         // constructors and destructors can have multiple mangles,
329         // but everything else is simpler
330         if(kind != Kind.Constructor && kind != Kind.Destructor)
331             return clang_Cursor_getMangling(cx).toString;
332 
333         // for (con|de)structors, there may be multiple mangles,
334         // and the getMangling function doesn't always return
335         // the right one. To be honest, I don't know how to find
336         // the right one all the time, but in testing, the first
337         // one on this function, if it returns one, works more often.
338         // I wish I could explain more, I just know this passes the tests
339         // and the plain impl of just getMangling doesn't.
340         string mangle;
341 
342         auto otherMangles = clang_Cursor_getCXXManglings(cx);
343         if(otherMangles) {
344             auto strings = toStrings(otherMangles);
345             if(strings.length)
346                 mangle = strings[0];
347         }
348         if(mangle is null)
349             mangle = clang_Cursor_getMangling(cx).toString;
350         return mangle;
351     }
352 
353     bool isAnonymous() @safe @nogc pure nothrow const {
354         return cast(bool) clang_Cursor_isAnonymous(cx);
355     }
356 
357     bool isBitField() @safe @nogc pure nothrow const {
358         return cast(bool) clang_Cursor_isBitField(cx);
359     }
360 
361     int bitWidth() @safe @nogc pure nothrow const {
362         return clang_getFieldDeclBitWidth(cx);
363     }
364 
365     auto accessSpecifier() @safe @nogc pure nothrow const {
366         return cast(AccessSpecifier) clang_getCXXAccessSpecifier(cx);
367     }
368 
369     StorageClass storageClass() @safe @nogc pure nothrow const {
370         return cast(StorageClass) clang_Cursor_getStorageClass(cx);
371     }
372 
373     bool isConstCppMethod() @safe @nogc pure nothrow const {
374         return cast(bool) clang_CXXMethod_isConst(cx);
375     }
376 
377     bool isMoveConstructor() @safe @nogc pure nothrow const {
378         return cast(bool) clang_CXXConstructor_isMoveConstructor(cx);
379     }
380 
381     bool isCopyConstructor() @safe @nogc pure nothrow const {
382         return cast(bool) clang_CXXConstructor_isCopyConstructor(cx);
383     }
384 
385     bool isMacroFunction() @safe @nogc pure nothrow const {
386         return cast(bool) clang_Cursor_isMacroFunctionLike(cx);
387     }
388 
389     bool isMacroBuiltin() @safe @nogc pure nothrow const {
390         return cast(bool) clang_Cursor_isMacroBuiltin(cx);
391     }
392 
393     Cursor specializedCursorTemplate() @safe pure nothrow const {
394         return Cursor(clang_getSpecializedCursorTemplate(cx));
395     }
396 
397     TranslationUnit translationUnit() @safe nothrow const {
398         return TranslationUnit(clang_Cursor_getTranslationUnit(cx));
399     }
400 
401     Token[] tokens() @safe nothrow const {
402         import std.algorithm: map;
403         import std.array: array;
404 
405         CXToken* tokens;
406         uint numTokens;
407 
408         auto tu = clang_Cursor_getTranslationUnit(cx);
409 
410         () @trusted { clang_tokenize(tu, sourceRange.cx, &tokens, &numTokens); }();
411         // I hope this only deallocates the array
412         scope(exit) clang_disposeTokens(tu, tokens, numTokens);
413 
414         auto tokenSlice = () @trusted { return tokens[0 .. numTokens]; }();
415 
416         return tokenSlice.map!(a => Token(a, tu)).array;
417     }
418 
419     alias templateParams = templateParameters;
420 
421     const(Cursor)[] templateParameters() @safe nothrow const {
422         import std.algorithm: filter;
423         import std.array: array;
424 
425         const amTemplate =
426             kind == Cursor.Kind.ClassTemplate
427             || kind == Cursor.Kind.TypeAliasTemplateDecl
428             || kind == Cursor.Kind.FunctionTemplate
429             ;
430         const templateCursor = amTemplate ? this : specializedCursorTemplate;
431 
432         auto range = templateCursor
433             .children
434             .filter!(a => a.kind == Cursor.Kind.TemplateTypeParameter ||
435                           a.kind == Cursor.Kind.NonTypeTemplateParameter);
436 
437         // Why is this @system? Who knows.
438         return () @trusted { return range.array; }();
439     }
440 
441     /**
442        If declared at file scope.
443      */
444     bool isFileScope() @safe nothrow const {
445         return lexicalParent.kind == Cursor.Kind.TranslationUnit;
446     }
447 
448     int numTemplateArguments() @safe @nogc pure nothrow const {
449         return clang_Cursor_getNumTemplateArguments(cx);
450     }
451 
452     TemplateArgumentKind templateArgumentKind(int i) @safe @nogc pure nothrow const {
453         return cast(TemplateArgumentKind) clang_Cursor_getTemplateArgumentKind(cx, i);
454     }
455 
456     Type templateArgumentType(int i) @safe pure nothrow const {
457         return Type(clang_Cursor_getTemplateArgumentType(cx, i));
458     }
459 
460     long templateArgumentValue(int i) @safe @nogc pure nothrow const {
461         return clang_Cursor_getTemplateArgumentValue(cx, i);
462     }
463 
464     bool isVirtual() @safe @nogc pure nothrow const {
465         return cast(bool) clang_CXXMethod_isVirtual(cx);
466     }
467 
468     bool isPureVirtual() @safe @nogc pure nothrow const {
469         return cast(bool) clang_CXXMethod_isPureVirtual(cx);
470     }
471 
472     string displayName() @safe pure nothrow const {
473         return clang_getCursorDisplayName(cx).toString;
474     }
475 
476     /**
477        For e.g. TypeRef or TemplateRef
478      */
479     Cursor referencedCursor() @safe nothrow const {
480         return Cursor(clang_getCursorReferenced(cx));
481     }
482 
483     Cursor[] overriddenCursors() @trusted /* @safe with DIP1000 */ const {
484         import std.algorithm: map;
485         import std.array: array;
486 
487         uint length;
488         CXCursor* cursors;
489 
490         clang_getOverriddenCursors(cx, &cursors, &length);
491         scope(exit) clang_disposeOverriddenCursors(cursors);
492 
493         return cursors[0 .. length].map!(a => Cursor(a)).array;
494     }
495 
496     auto numOverloadedDecls() @safe @nogc pure nothrow const {
497         return clang_getNumOverloadedDecls(cx);
498     }
499 
500     Cursor overloadedDecl(int i) @safe nothrow const {
501         return Cursor(clang_getOverloadedDecl(cx, cast(uint) i));
502     }
503 
504     bool opEquals(ref const(Cursor) other) @safe @nogc pure nothrow const {
505         return cast(bool) clang_equalCursors(cx, other.cx);
506     }
507 
508     bool opEquals(in Cursor other) @safe @nogc pure nothrow const {
509         return cast(bool) clang_equalCursors(cx, other.cx);
510     }
511 
512     void visitChildren(scope CursorVisitor visitor) @safe nothrow const {
513         scope clientData = ClientData(visitor);
514         // why isn't this @safe with dip10000???
515         () @trusted { clang_visitChildren(cx, &cvisitor, &clientData); }();
516     }
517 
518     int opApply(scope int delegate(Cursor cursor, Cursor parent) @safe block) @safe nothrow const {
519         return opApplyN(block);
520     }
521 
522     int opApply(scope int delegate(Cursor cursor) @safe block) @safe nothrow const {
523         return opApplyN(block);
524     }
525 
526     private int opApplyN(T)(scope T block) const {
527         import std.traits: Parameters;
528 
529         int stop = 0;
530 
531         enum numParams = Parameters!T.length;
532 
533         visitChildren((cursor, parent) {
534 
535             static if(numParams == 2)
536                 stop = block(cursor, parent);
537             else static if(numParams == 1)
538                 stop = block(cursor);
539             else
540                 static assert(false);
541 
542             return stop
543                 ? ChildVisitResult.Break
544                 : ChildVisitResult.Continue;
545         });
546 
547         return stop;
548     }
549 
550     private string _spellingCreate() @safe pure nothrow const {
551         return clang_getCursorSpelling(cx).toString;
552     }
553 
554     private SourceRange _sourceRangeCreate() @safe pure nothrow const {
555         return SourceRange(clang_getCursorExtent(cx));
556     }
557 }
558 
559 
560 struct SourceRange {
561 
562     import clang.util: Lazy;
563 
564     CXSourceRange cx;
565     private SourceLocation _start;
566     private SourceLocation _end;
567 
568     mixin Lazy!_start;
569     mixin Lazy!_end;
570 
571     this(CXSourceRange cx) @safe @nogc pure nothrow {
572         this.cx = cx;
573     }
574 
575     string path() @safe nothrow const {
576         return start.path;
577     }
578 
579     string toString() @safe pure const {
580         import std.conv: text;
581         return text(`SourceRange("`, start.path, `", `, start.line, ":", start.column, ", ", end.line, ":", end.column, ")");
582     }
583 
584     private auto _startCreate() @safe pure nothrow const {
585         return SourceLocation(clang_getRangeStart(cx));
586     }
587 
588     private auto _endCreate() @safe pure nothrow const {
589         return SourceLocation(clang_getRangeEnd(cx));
590     }
591 }
592 
593 
594 struct SourceLocation {
595 
596     CXSourceLocation cx;
597     string path;
598     uint line;
599     uint column;
600     uint offset;
601 
602     this(CXSourceLocation cx) @safe pure nothrow {
603         this.cx = cx;
604 
605         CXFile file;
606         () @trusted { clang_getExpansionLocation(cx, &file, null, null, null); }();
607         this.path = clang_getFileName(file).toString;
608 
609        () @trusted { clang_getSpellingLocation(cx, &file, &line, &column, &offset); }();
610     }
611 
612     int opCmp(ref const(SourceLocation) other) @safe @nogc pure nothrow const {
613         if(path == other.path && line == other.line && column == other.column &&
614            offset == other.offset)
615             return 0;
616 
617         if(path < other.path) return -1;
618         if(path > other.path) return 1;
619         if(line < other.line) return -1;
620         if(line > other.line) return 1;
621         if(column < other.column) return -1;
622         if(column > other.column) return 1;
623         if(offset < other.offset) return -1;
624         if(offset > other.offset) return 1;
625         assert(false);
626     }
627 
628     string toString() @safe pure nothrow const {
629         import std.conv: text;
630         return text(`"`, path, `" `, line, ":", column, ":", offset);
631     }
632 }
633 
634 private struct ClientData {
635     /**
636        The D visitor delegate
637      */
638     CursorVisitor dvisitor;
639 }
640 
641 // This is the C function actually passed to libclang's clang_visitChildren
642 // The context (clientData) contains the D delegate that's then called on the
643 // (cursor, parent) pair
644 private extern(C) CXChildVisitResult cvisitor(CXCursor cursor, CXCursor parent, void* clientData_) {
645     auto clientData = cast(ClientData*) clientData_;
646     return cast(CXChildVisitResult) clientData.dvisitor(Cursor(cursor), Cursor(parent));
647 }
648 
649 
650 struct Type {
651 
652     import clang.util: Lazy;
653 
654     mixin EnumD!("Kind", CXTypeKind, "CXType_");
655 
656     CXType cx;
657     Kind kind;
658     private string _spelling;
659 
660     mixin Lazy!_spelling;
661 
662     this(CXType cx) @safe @nogc pure nothrow {
663         this.cx = cx;
664         this.kind = cast(Kind) cx.kind;
665     }
666 
667     this(in Type other) @trusted pure nothrow {
668         import std.algorithm: map;
669         import std.array: array;
670 
671         this.cx.kind = other.cx.kind;
672         this.cx.data[] = other.cx.data[].map!(a => cast(void*) a).array;
673 
674         this(this.cx);
675     }
676 
677     this(in Kind kind) @safe @nogc pure nothrow {
678         this(kind, "");
679     }
680 
681     this(in Kind kind, in string spelling) @safe @nogc pure nothrow {
682         this.kind = kind;
683         _spelling = spelling;
684     }
685 
686     Type pointee() @safe pure nothrow const {
687         return Type(clang_getPointeeType(cx));
688     }
689 
690     Type unelaborate() @safe nothrow const {
691         return Type(clang_Type_getNamedType(cx));
692     }
693 
694     Type canonical() @safe pure nothrow const {
695         return Type(clang_getCanonicalType(cx));
696     }
697 
698     Type returnType() @safe pure const {
699         return Type(clang_getResultType(cx));
700     }
701 
702     // Returns a range of Type
703     auto paramTypes()() @safe pure const nothrow {
704 
705         static struct Range {
706             const CXType cx;
707             const int numArgs;
708             int index = 0;
709 
710             bool empty() {
711                 return index < 0 || index >= numArgs;
712             }
713 
714             void popFront() {
715                 ++index;
716             }
717 
718             Type front() {
719                 return Type(clang_getArgType(cx, index));
720             }
721         }
722 
723         return Range(cx, clang_getNumArgTypes(cx));
724     }
725 
726     bool isVariadicFunction() @safe @nogc pure nothrow const {
727         return cast(bool) clang_isFunctionTypeVariadic(cx);
728     }
729 
730     Type elementType() @safe pure nothrow const {
731         return Type(clang_getElementType(cx));
732     }
733 
734     long numElements() @safe @nogc pure nothrow const {
735         return clang_getNumElements(cx);
736     }
737 
738     long arraySize() @safe @nogc pure nothrow const {
739         return clang_getArraySize(cx);
740     }
741 
742     bool isConstQualified() @safe @nogc pure nothrow const scope {
743         return cast(bool) clang_isConstQualifiedType(cx);
744     }
745 
746     bool isVolatileQualified() @safe @nogc pure nothrow const scope {
747         return cast(bool) clang_isVolatileQualifiedType(cx);
748     }
749 
750     Cursor declaration() @safe pure nothrow const {
751         return Cursor(clang_getTypeDeclaration(cx));
752     }
753 
754     Type namedType() @safe pure nothrow const {
755         return Type(clang_Type_getNamedType(cx));
756     }
757 
758     bool opEquals(ref const(Type) other) @safe @nogc pure nothrow const {
759         return cast(bool) clang_equalTypes(cx, other.cx);
760     }
761 
762     bool opEquals(in Type other) @safe @nogc pure nothrow const {
763         return cast(bool) clang_equalTypes(cx, other.cx);
764     }
765 
766     bool isInvalid() @safe @nogc pure nothrow const {
767         return kind == Kind.Invalid;
768     }
769 
770     long getSizeof() @safe @nogc pure nothrow const {
771         return clang_Type_getSizeOf(cx);
772     }
773 
774     int numTemplateArguments() @safe @nogc pure nothrow const {
775         return clang_Type_getNumTemplateArguments(cx);
776     }
777 
778     Type typeTemplateArgument(int i) @safe pure nothrow const {
779         return Type(clang_Type_getTemplateArgumentAsType(cx, i));
780     }
781 
782     string toString() @safe pure nothrow const {
783         import std.conv: text;
784 
785         try {
786             return text("Type(", kind, `, "`, spelling, `")`);
787         } catch(Exception e)
788             assert(false, "Fatal error in Type.toString: " ~ e.msg);
789     }
790 
791     private string _spellingCreate() @safe pure nothrow const {
792         return clang_getTypeSpelling(cx).toString;
793     }
794 }
795 
796 
797 struct Token {
798 
799     mixin EnumD!("Kind", CXTokenKind, "CXToken_");
800 
801     Kind kind;
802     string spelling;
803     CXToken cxToken;
804     CXTranslationUnit cxTU;
805 
806     this(CXToken cxToken, CXTranslationUnit cxTU) @safe pure nothrow {
807         this.cxToken = cxToken;
808         this.cxTU = cxTU;
809         this.kind = cast(Kind) clang_getTokenKind(cxToken);
810         this.spelling = .toString(clang_getTokenSpelling(cxTU, cxToken));
811     }
812 
813     this(Kind kind, string spelling) @safe @nogc pure nothrow {
814         this.kind = kind;
815         this.spelling = spelling;
816     }
817 
818     string toString() @safe pure const {
819         import std.conv: text;
820 
821         return text("Token(", kind, `, "`, spelling, `")`);
822     }
823 
824     bool opEquals(in Token other) @safe pure nothrow const {
825         return kind == other.kind && spelling == other.spelling;
826     }
827 }