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 private:
177 
178 }
179 
180 struct DeclarationVisitor {
181     mixin Visitor.Constructors;
182 
183     int opApply(Visitor.Delegate dg) {
184         foreach (cursor, parent; visitor) {
185             if (cursor.isDeclaration) {
186                 if (auto result = dg(cursor, parent)) {
187                     return result;
188                 }
189             }
190         }
191 
192         return 0;
193     }
194 }
195 
196 struct TypedVisitor(CXCursorKind kind) {
197     private Visitor visitor;
198 
199     this(Visitor visitor) {
200         this.visitor = visitor;
201     }
202 
203     this(Cursor cursor) {
204         this.visitor = Visitor(cursor);
205     }
206 
207     int opApply(Visitor.Delegate dg) {
208         foreach (cursor, parent; visitor) {
209             if (cursor.kind == kind) {
210                 if (auto result = dg(cursor, parent)) {
211                     return result;
212                 }
213             }
214         }
215 
216         return 0;
217     }
218 }
219 
220 alias ObjCInstanceMethodVisitor = TypedVisitor!(CXCursorKind.objCInstanceMethodDecl);
221 alias ObjCClassMethodVisitor = TypedVisitor!(CXCursorKind.objCClassMethodDecl);
222 alias ObjCPropertyVisitor = TypedVisitor!(CXCursorKind.objCPropertyDecl);
223 alias ObjCProtocolVisitor = TypedVisitor!(CXCursorKind.objCProtocolRef);
224 
225 struct ParamVisitor {
226     mixin Visitor.Constructors;
227 
228     int opApply(int delegate(ref ParamCursor) dg) {
229         foreach (cursor, parent; visitor) {
230             if (cursor.kind == CXCursorKind.parmDecl) {
231                 auto paramCursor = ParamCursor(cursor);
232 
233                 if (auto result = dg(paramCursor))
234                     return result;
235             }
236         }
237 
238         return 0;
239     }
240 
241     @property size_t length() {
242         auto type = Cursor(visitor.cursor).type;
243 
244         if (type.isValid)
245             return type.func.arguments.length;
246 
247         else {
248             size_t i;
249 
250             foreach (_; this)
251                 i++;
252 
253             return i;
254         }
255     }
256 
257     @property bool any() {
258         return length > 0;
259     }
260 
261     @property bool isEmpty() {
262         return !any;
263     }
264 
265     @property ParamCursor first() {
266         assert(any, "Cannot get the first parameter of an empty parameter list");
267 
268         foreach (c; this)
269             return c;
270 
271         assert(0, "Cannot get the first parameter of an empty parameter list");
272     }
273 }
274 
275 /** Determine the set of methods that are overridden by the given
276  * method.
277  *
278  * In both Objective-C and C++, a method (aka virtual member function,
279  * in C++) can override a virtual method in a base class. For
280  * Objective-C, a method is said to override any method in the class's
281  * base class, its protocols, or its categories' protocols, that has the same
282  * selector and is of the same kind (class or instance).
283  * If no such method exists, the search continues to the class's superclass,
284  * its protocols, and its categories, and so on. A method from an Objective-C
285  * implementation is considered to override the same methods as its
286  * corresponding method in the interface.
287  *
288  * For C++, a virtual member function overrides any virtual member
289  * function with the same signature that occurs in its base
290  * classes. With multiple inheritance, a virtual member function can
291  * override several virtual member functions coming from different
292  * base classes.
293  *
294  * In all cases, this function determines the immediate overridden
295  * method, rather than all of the overridden methods. For example, if
296  * a method is originally declared in a class A, then overridden in B
297  * (which in inherits from A) and also in C (which inherited from B),
298  * then the only overridden method returned from this function when
299  * invoked on C's method will be B's method. The client may then
300  * invoke this function again, given the previously-found overridden
301  * methods, to map out the complete method-override set.
302  *
303  * \param cursor A cursor representing an Objective-C or C++
304  * method. This routine will compute the set of methods that this
305  * method overrides.
306  *
307  * \param overridden A pointer whose pointee will be replaced with a
308  * pointer to an array of cursors, representing the set of overridden
309  * methods. If there are no overridden methods, the pointee will be
310  * set to NULL. The pointee must be freed via a call to
311  * \c clang_disposeOverriddenCursors().
312  *
313  * \param num_overridden A pointer to the number of overridden
314  * functions, will be set to the number of overridden functions in the
315  * array pointed to by \p overridden.
316  */
317 struct OverriddenVisitor {
318     alias Delegate = int delegate(ref Cursor);
319 
320     private Cursor cursor;
321 
322     this(Cursor cursor) {
323         this.cursor = cursor;
324     }
325 
326     int opApply(Delegate dg) {
327         int result = 0;
328         CXCursor* overridden;
329         uint num_overridden;
330 
331         clang_getOverriddenCursors(this.cursor.cx, &overridden, &num_overridden);
332         for (uint i = 0; i < num_overridden; ++overridden) {
333             auto c = Cursor(*overridden);
334             result = dg(c);
335             if (result)
336                 break;
337         }
338         clang_disposeOverriddenCursors(overridden);
339 
340         return result;
341     }
342 }