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 
11 import clang.Cursor;
12 import clang.TranslationUnit;
13 
14 struct Visitor {
15     alias Delegate = int delegate(ref Cursor, ref Cursor);
16     alias OpApply = int delegate(Delegate dg);
17 
18 @safe:
19 
20     private CXCursor cursor;
21 
22     this(CXCursor cursor) {
23         this.cursor = cursor;
24     }
25 
26     this(Cursor cursor) {
27         this.cursor = cursor.cx;
28     }
29 
30     /**
31      * Trusted: assuming the LLVM function do NOT abuse the pointer in any way.
32      */
33     int opApply(Delegate dg) @trusted {
34         if (dg is null)
35             return 0;
36 
37         auto data = OpApplyData(dg);
38         clang_visitChildren(cursor, &visitorFunction, cast(CXClientData)&data);
39 
40         return data.returnCode;
41     }
42 
43     /**
44      * Trusted: assuming the LLVM function do NOT abuse the pointer in any way.
45      */
46     int opApply(int delegate(ref Cursor) dg) @trusted {
47         int wrapper(ref Cursor cursor, ref Cursor) {
48             return dg(cursor);
49         }
50 
51         if (dg is null)
52             return 0;
53 
54         auto data = OpApplyData(&wrapper);
55         clang_visitChildren(cursor, &visitorFunction, cast(CXClientData)&data);
56 
57         return data.returnCode;
58     }
59 
60 private:
61 
62     extern (C) static CXChildVisitResult visitorFunction(CXCursor cursor,
63             CXCursor parent, CXClientData data) @trusted {
64         if (data is null)
65             return CXChildVisitResult.continue_;
66 
67         auto tmp = cast(OpApplyData*) data;
68 
69         with (CXChildVisitResult) {
70             auto dCursor = Cursor(cursor);
71             auto dParent = Cursor(parent);
72             auto r = tmp.dg(dCursor, dParent);
73             tmp.returnCode = r;
74             return r ? break_ : continue_;
75         }
76     }
77 
78     static struct OpApplyData {
79         int returnCode;
80         Delegate dg;
81 
82         this(Delegate dg) {
83             this.dg = dg;
84         }
85     }
86 
87     template Constructors() {
88         private Visitor visitor;
89 
90         this(Visitor visitor) {
91             this.visitor = visitor;
92         }
93 
94         this(CXCursor cursor) {
95             visitor = Visitor(cursor);
96         }
97 
98         this(Cursor cursor) {
99             visitor = Visitor(cursor);
100         }
101     }
102 }
103 
104 @safe struct InOrderVisitor {
105     alias int delegate(ref Cursor, ref Cursor) Delegate;
106 
107     private Cursor cursor;
108 
109     this(CXCursor cursor) {
110         this.cursor = Cursor(cursor);
111     }
112 
113     this(Cursor cursor) {
114         this.cursor = cursor;
115     }
116 
117     int opApply(Delegate dg) @trusted {
118         import std.array;
119 
120         auto visitor = Visitor(cursor);
121         int result = 0;
122 
123         auto macrosAppender = appender!(Cursor[])();
124         size_t itr = 0;
125 
126         foreach (cursor, _; visitor) {
127             if (cursor.isPreprocessing)
128                 macrosAppender.put(cursor);
129         }
130 
131         auto macros = macrosAppender.data;
132         auto query = cursor.translationUnit.relativeLocationAccessorImpl(macros);
133 
134         ulong macroIndex = macros.length != 0 ? query(macros[0].location) : ulong.max;
135 
136         size_t jtr = 0;
137 
138         foreach (cursor, parent; visitor) {
139             if (!cursor.isPreprocessing) {
140                 ulong cursorIndex = query(cursor.location);
141 
142                 while (macroIndex < cursorIndex) {
143                     Cursor macroParent = macros[jtr].semanticParent;
144 
145                     result = dg(macros[jtr], macroParent);
146 
147                     if (result)
148                         return result;
149 
150                     ++jtr;
151 
152                     macroIndex = jtr < macros.length ? query(macros[jtr].location) : ulong.max;
153                 }
154 
155                 result = dg(cursor, parent);
156 
157                 if (result)
158                     return result;
159             }
160         }
161 
162         while (jtr < macros.length) {
163             Cursor macroParent = macros[jtr].semanticParent;
164 
165             result = dg(macros[jtr], macroParent);
166 
167             if (result)
168                 return result;
169 
170             ++jtr;
171         }
172 
173         return result;
174     }
175 }
176 
177 struct DeclarationVisitor {
178     mixin Visitor.Constructors;
179 
180     int opApply(Visitor.Delegate dg) {
181         foreach (cursor, parent; visitor) {
182             if (cursor.isDeclaration) {
183                 if (auto result = dg(cursor, parent)) {
184                     return result;
185                 }
186             }
187         }
188 
189         return 0;
190     }
191 }
192 
193 struct TypedVisitor(CXCursorKind kind) {
194     private Visitor visitor;
195 
196     this(Visitor visitor) {
197         this.visitor = visitor;
198     }
199 
200     this(Cursor cursor) {
201         this.visitor = Visitor(cursor);
202     }
203 
204     int opApply(Visitor.Delegate dg) {
205         foreach (cursor, parent; visitor) {
206             if (cursor.kind == kind) {
207                 if (auto result = dg(cursor, parent)) {
208                     return result;
209                 }
210             }
211         }
212 
213         return 0;
214     }
215 }
216 
217 alias ObjCInstanceMethodVisitor = TypedVisitor!(CXCursorKind.objCInstanceMethodDecl);
218 alias ObjCClassMethodVisitor = TypedVisitor!(CXCursorKind.objCClassMethodDecl);
219 alias ObjCPropertyVisitor = TypedVisitor!(CXCursorKind.objCPropertyDecl);
220 alias ObjCProtocolVisitor = TypedVisitor!(CXCursorKind.objCProtocolRef);
221 
222 struct ParamVisitor {
223     mixin Visitor.Constructors;
224 
225     int opApply(int delegate(ref ParamCursor) dg) {
226         foreach (cursor, parent; visitor) {
227             if (cursor.kind == CXCursorKind.parmDecl) {
228                 auto paramCursor = ParamCursor(cursor);
229 
230                 if (auto result = dg(paramCursor))
231                     return result;
232             }
233         }
234 
235         return 0;
236     }
237 
238     @property size_t length() {
239         auto type = Cursor(visitor.cursor).type;
240 
241         if (type.isValid)
242             return type.func.arguments.length;
243 
244         else {
245             size_t i;
246 
247             foreach (_; this)
248                 i++;
249 
250             return i;
251         }
252     }
253 
254     @property bool any() {
255         return length > 0;
256     }
257 
258     @property bool isEmpty() {
259         return !any;
260     }
261 
262     @property ParamCursor first() {
263         assert(any, "Cannot get the first parameter of an empty parameter list");
264 
265         foreach (c; this)
266             return c;
267 
268         assert(0, "Cannot get the first parameter of an empty parameter list");
269     }
270 }
271 
272 /** Determine the set of methods that are overridden by the given
273  * method.
274  *
275  * In both Objective-C and C++, a method (aka virtual member function,
276  * in C++) can override a virtual method in a base class. For
277  * Objective-C, a method is said to override any method in the class's
278  * base class, its protocols, or its categories' protocols, that has the same
279  * selector and is of the same kind (class or instance).
280  * If no such method exists, the search continues to the class's superclass,
281  * its protocols, and its categories, and so on. A method from an Objective-C
282  * implementation is considered to override the same methods as its
283  * corresponding method in the interface.
284  *
285  * For C++, a virtual member function overrides any virtual member
286  * function with the same signature that occurs in its base
287  * classes. With multiple inheritance, a virtual member function can
288  * override several virtual member functions coming from different
289  * base classes.
290  *
291  * In all cases, this function determines the immediate overridden
292  * method, rather than all of the overridden methods. For example, if
293  * a method is originally declared in a class A, then overridden in B
294  * (which in inherits from A) and also in C (which inherited from B),
295  * then the only overridden method returned from this function when
296  * invoked on C's method will be B's method. The client may then
297  * invoke this function again, given the previously-found overridden
298  * methods, to map out the complete method-override set.
299  *
300  * \param cursor A cursor representing an Objective-C or C++
301  * method. This routine will compute the set of methods that this
302  * method overrides.
303  *
304  * \param overridden A pointer whose pointee will be replaced with a
305  * pointer to an array of cursors, representing the set of overridden
306  * methods. If there are no overridden methods, the pointee will be
307  * set to NULL. The pointee must be freed via a call to
308  * \c clang_disposeOverriddenCursors().
309  *
310  * \param num_overridden A pointer to the number of overridden
311  * functions, will be set to the number of overridden functions in the
312  * array pointed to by \p overridden.
313  */
314 struct OverriddenVisitor {
315     alias Delegate = int delegate(ref Cursor);
316 
317     private Cursor cursor;
318 
319     this(Cursor cursor) {
320         this.cursor = cursor;
321     }
322 
323     int opApply(Delegate dg) {
324         int result = 0;
325         CXCursor* overridden;
326         uint num_overridden;
327 
328         clang_getOverriddenCursors(this.cursor.cx, &overridden, &num_overridden);
329         for (uint i = 0; i < num_overridden; ++overridden) {
330             auto c = Cursor(*overridden);
331             result = dg(c);
332             if (result)
333                 break;
334         }
335         clang_disposeOverriddenCursors(overridden);
336 
337         return result;
338     }
339 }