1 /** 2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 */ 10 module cpptooling.analyzer.clang.cursor_visitor; 11 12 import clang.Cursor : Cursor; 13 14 private @safe nothrow struct ASTCursor { 15 Cursor cursor; 16 size_t depth; 17 18 alias cursor this; 19 } 20 21 /** 22 */ 23 private @safe nothrow struct AST_BreathFirstResult { 24 import std.container : Array; 25 26 private int depth_; 27 private typeof(Array!(Cursor).opSlice()) r; 28 // index 0: the current range that is operated on. 29 // index 1: the next one that is being filled with data. 30 private Array!(Cursor)[] data; 31 32 this(Cursor c) @trusted { 33 data ~= Array!Cursor(); 34 data ~= Array!Cursor(); 35 data[0].insertBack(c); 36 r = data[0][]; 37 } 38 39 ASTCursor front() @safe nothrow const { 40 assert(!empty, "Can't get front of an empty range"); 41 42 return ASTCursor(r.front, depth_); 43 } 44 45 void popFront() @trusted { 46 assert(!empty, "Can't pop front of an empty range"); 47 48 import clang.Visitor; 49 50 foreach (cursor, _; Visitor(r.front)) { 51 data[1].insertBack(cursor); 52 } 53 54 r.popFront; 55 56 if (r.length == 0) { 57 data = data[1 .. $]; 58 r = data[0][]; 59 data ~= Array!Cursor(); 60 ++depth_; 61 } 62 } 63 64 bool empty() @safe nothrow const { 65 return r.empty && data[1].empty; 66 } 67 68 int depth() { 69 return depth_; 70 } 71 } 72 73 /** opApply compatible visitor of the clang AST, breath first. 74 * 75 * Example: 76 * --- 77 * foreach (child; c.visitBreathFirst.until!(a => a.depth == 3)) { 78 * if (child.kind == CXCursorKind.CXCursor_StructDecl) { 79 * ... 80 * } 81 * } 82 */ 83 auto visitBreathFirst(Cursor c) @trusted { 84 return AST_BreathFirstResult(c); 85 }