1 /**
2  * Copyright: Copyright (c) 2012 Jacob Carlborg. All rights reserved.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: Jan 29, 2012
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module clang.Visitor;
8 
9 import clang.c.Index;
10 import clang.Cursor;
11 
12 struct Visitor
13 {
14     alias int delegate (ref Cursor, ref Cursor) Delegate;
15     alias int delegate (Delegate dg) OpApply;
16 
17     private CXCursor cursor;
18 
19     this (CXCursor cursor)
20     {
21         this.cursor = cursor;
22     }
23 
24     this (Cursor cursor)
25     {
26         this.cursor = cursor.cx;
27     }
28 
29     int opApply (Delegate dg)
30     {
31         auto data = OpApplyData(dg);
32         clang_visitChildren(cursor, &visitorFunction, cast(CXClientData) &data);
33 
34         return data.returnCode;
35     }
36 
37 private:
38 
39     extern (C) static CXChildVisitResult visitorFunction (CXCursor cursor, CXCursor parent, CXClientData data)
40     {
41         auto tmp = cast(OpApplyData*) data;
42 
43         with (CXChildVisitResult)
44         {
45             auto dCursor = Cursor(cursor);
46             auto dParent = Cursor(parent);
47             auto r = tmp.dg(dCursor, dParent);
48             tmp.returnCode = r;
49             return r ? CXChildVisit_Break : CXChildVisit_Continue;
50         }
51     }
52 
53     static struct OpApplyData
54     {
55         int returnCode;
56         Delegate dg;
57 
58         this (Delegate dg)
59         {
60             this.dg = dg;
61         }
62     }
63 
64     template Constructors ()
65     {
66         private Visitor visitor;
67 
68         this (Visitor visitor)
69         {
70             this.visitor = visitor;
71         }
72 
73         this (CXCursor cursor)
74         {
75             visitor = Visitor(cursor);
76         }
77 
78         this (Cursor cursor)
79         {
80             visitor = Visitor(cursor);
81         }
82     }
83 }
84 
85 struct DeclarationVisitor
86 {
87     mixin Visitor.Constructors;
88 
89     int opApply (Visitor.Delegate dg)
90     {
91         foreach (cursor, parent ; visitor)
92             if (cursor.isDeclaration)
93                 if (auto result = dg(cursor, parent))
94                     return result;
95 
96         return 0;
97     }
98 }
99 
100 struct TypedVisitor (CXCursorKind kind)
101 {
102     private Visitor visitor;
103 
104     this (Visitor visitor)
105     {
106         this.visitor = visitor;
107     }
108 
109     this (CXCursor cursor)
110     {
111         this(Visitor(cursor));
112     }
113 
114     this (Cursor cursor)
115     {
116         this(cursor.cx);
117     }
118 
119     int opApply (Visitor.Delegate dg)
120     {
121         foreach (cursor, parent ; visitor)
122             if (cursor.kind == kind)
123                 if (auto result = dg(cursor, parent))
124                     return result;
125 
126         return 0;
127     }
128 }
129 
130 alias TypedVisitor!(CXCursorKind.CXCursor_ObjCInstanceMethodDecl) ObjCInstanceMethodVisitor;
131 alias TypedVisitor!(CXCursorKind.CXCursor_ObjCClassMethodDecl) ObjCClassMethodVisitor;
132 alias TypedVisitor!(CXCursorKind.CXCursor_ObjCPropertyDecl) ObjCPropertyVisitor;
133 alias TypedVisitor!(CXCursorKind.CXCursor_ObjCProtocolRef) ObjCProtocolVisitor;
134 
135 struct ParamVisitor
136 {
137     mixin Visitor.Constructors;
138 
139     int opApply (int delegate (ref ParamCursor) dg)
140     {
141         foreach (cursor, parent ; visitor)
142             if (cursor.kind == CXCursorKind.CXCursor_ParmDecl)
143             {
144                 auto paramCursor = ParamCursor(cursor);
145 
146                 if (auto result = dg(paramCursor))
147                     return result;
148             }
149 
150         return 0;
151     }
152 
153     @property size_t length ()
154     {
155         auto type = Cursor(visitor.cursor).type;
156 
157         if (type.isValid)
158             return type.func.arguments.length;
159 
160         else
161         {
162             size_t i;
163 
164             foreach (_ ; this)
165                 i++;
166 
167             return i;
168         }
169     }
170 
171     @property bool any ()
172     {
173         return length > 0;
174     }
175 
176     @property bool isEmpty ()
177     {
178         return !any;
179     }
180 
181     @property ParamCursor first ()
182     {
183         assert(any, "Cannot get the first parameter of an empty parameter list");
184 
185         foreach (c ; this)
186             return c;
187 
188         assert(0, "Cannot get the first parameter of an empty parameter list");
189     }
190 }