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 }