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 import clang.SourceLocation;
12 import clang.SourceRange;
13 import clang.TranslationUnit;
14 
15 struct Visitor
16 {
17     alias int delegate (ref Cursor, ref Cursor) Delegate;
18     alias int delegate (Delegate dg) OpApply;
19 
20     private CXCursor cursor;
21 
22     this (CXCursor cursor)
23     {
24         this.cursor = cursor;
25     }
26 
27     this (Cursor cursor)
28     {
29         this.cursor = cursor.cx;
30     }
31 
32     int opApply (Delegate dg)
33     {
34         auto data = OpApplyData(dg);
35         clang_visitChildren(cursor, &visitorFunction, cast(CXClientData) &data);
36 
37         return data.returnCode;
38     }
39 
40     int opApply(int delegate (ref Cursor) dg)
41     {
42         int wrapper (ref Cursor cursor, ref Cursor)
43         {
44             return dg(cursor);
45         }
46 
47         auto data = OpApplyData(&wrapper);
48         clang_visitChildren(cursor, &visitorFunction, cast(CXClientData) &data);
49 
50         return data.returnCode;
51     }
52 
53 private:
54 
55     extern (C) static CXChildVisitResult visitorFunction (
56         CXCursor cursor,
57         CXCursor parent,
58         CXClientData data)
59     {
60         auto tmp = cast(OpApplyData*) data;
61 
62         with (CXChildVisitResult)
63         {
64             auto dCursor = Cursor(cursor);
65             auto dParent = Cursor(parent);
66             auto r = tmp.dg(dCursor, dParent);
67             tmp.returnCode = r;
68             return r ? break_ : continue_;
69         }
70     }
71 
72     static struct OpApplyData
73     {
74         int returnCode;
75         Delegate dg;
76 
77         this (Delegate dg)
78         {
79             this.dg = dg;
80         }
81     }
82 
83     template Constructors ()
84     {
85         private Visitor visitor;
86 
87         this (Visitor visitor)
88         {
89             this.visitor = visitor;
90         }
91 
92         this (CXCursor cursor)
93         {
94             visitor = Visitor(cursor);
95         }
96 
97         this (Cursor cursor)
98         {
99             visitor = Visitor(cursor);
100         }
101     }
102 }
103 
104 struct InOrderVisitor
105 {
106     alias int delegate (ref Cursor, ref Cursor) Delegate;
107 
108     private Cursor cursor;
109 
110     this (CXCursor cursor)
111     {
112         this.cursor = Cursor(cursor);
113     }
114 
115     this (Cursor cursor)
116     {
117         this.cursor = cursor;
118     }
119 
120     int opApply (Delegate dg)
121     {
122         import std.array;
123 
124         auto visitor = Visitor(cursor);
125         int result = 0;
126 
127         auto macrosAppender = appender!(Cursor[])();
128         size_t itr = 0;
129 
130         foreach (cursor, _; visitor)
131         {
132             if (cursor.isPreprocessor)
133                 macrosAppender.put(cursor);
134         }
135 
136         auto macros = macrosAppender.data;
137         auto query = cursor.translationUnit
138             .relativeLocationAccessorImpl(macros);
139 
140         ulong macroIndex = macros.length != 0
141             ? query(macros[0].location)
142             : ulong.max;
143 
144         size_t jtr = 0;
145 
146         foreach (cursor, parent; visitor)
147         {
148             if (!cursor.isPreprocessor)
149             {
150                 ulong cursorIndex = query(cursor.location);
151 
152                 while (macroIndex < cursorIndex)
153                 {
154                     Cursor macroParent = macros[jtr].semanticParent;
155 
156                     result = dg(macros[jtr], macroParent);
157 
158                     if (result)
159                         return result;
160 
161                     ++jtr;
162 
163                     macroIndex = jtr < macros.length
164                         ? query(macros[jtr].location)
165                         : ulong.max;
166                 }
167 
168                 result = dg(cursor, parent);
169 
170                 if (result)
171                     return result;
172             }
173         }
174 
175         while (jtr < macros.length)
176         {
177             Cursor macroParent = macros[jtr].semanticParent;
178 
179             result = dg(macros[jtr], macroParent);
180 
181             if (result)
182                 return result;
183 
184             ++jtr;
185         }
186 
187         return result;
188     }
189 
190 private:
191 
192 }
193 
194 struct DeclarationVisitor
195 {
196     mixin Visitor.Constructors;
197 
198     int opApply (Visitor.Delegate dg)
199     {
200         foreach (cursor, parent ; visitor)
201             if (cursor.isDeclaration)
202                 if (auto result = dg(cursor, parent))
203                     return result;
204 
205         return 0;
206     }
207 }
208 
209 struct TypedVisitor (CXCursorKind kind)
210 {
211     private Visitor visitor;
212 
213     this (Visitor visitor)
214     {
215         this.visitor = visitor;
216     }
217 
218     this (CXCursor cursor)
219     {
220         this(Visitor(cursor));
221     }
222 
223     this (Cursor cursor)
224     {
225         this(cursor.cx);
226     }
227 
228     int opApply (Visitor.Delegate dg)
229     {
230         foreach (cursor, parent ; visitor)
231             if (cursor.kind == kind)
232                 if (auto result = dg(cursor, parent))
233                     return result;
234 
235         return 0;
236     }
237 }
238 
239 alias TypedVisitor!(CXCursorKind.objCInstanceMethodDecl) ObjCInstanceMethodVisitor;
240 alias TypedVisitor!(CXCursorKind.objCClassMethodDecl) ObjCClassMethodVisitor;
241 alias TypedVisitor!(CXCursorKind.objCPropertyDecl) ObjCPropertyVisitor;
242 alias TypedVisitor!(CXCursorKind.objCProtocolRef) ObjCProtocolVisitor;
243 
244 struct ParamVisitor
245 {
246     mixin Visitor.Constructors;
247 
248     int opApply (int delegate (ref ParamCursor) dg)
249     {
250         foreach (cursor, parent ; visitor)
251             if (cursor.kind == CXCursorKind.parmDecl)
252             {
253                 auto paramCursor = ParamCursor(cursor);
254 
255                 if (auto result = dg(paramCursor))
256                     return result;
257             }
258 
259         return 0;
260     }
261 
262     @property size_t length ()
263     {
264         auto type = Cursor(visitor.cursor).type;
265 
266         if (type.isValid)
267             return type.func.arguments.length;
268 
269         else
270         {
271             size_t i;
272 
273             foreach (_ ; this)
274                 i++;
275 
276             return i;
277         }
278     }
279 
280     @property bool any ()
281     {
282         return length > 0;
283     }
284 
285     @property bool isEmpty ()
286     {
287         return !any;
288     }
289 
290     @property ParamCursor first ()
291     {
292         assert(any, "Cannot get the first parameter of an empty parameter list");
293 
294         foreach (c ; this)
295             return c;
296 
297         assert(0, "Cannot get the first parameter of an empty parameter list");
298     }
299 }