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_backtrack; 11 12 import clang.Cursor : Cursor; 13 14 // TODO remove this, shouldn't be needed. 15 import clang.c.Index : CXCursorKind; 16 17 private struct BacktrackResult { 18 private Cursor cursor; 19 20 Cursor front() @safe nothrow const { 21 assert(!empty, "Can't get front of an empty range"); 22 23 return cursor; 24 } 25 26 void popFront() @safe { 27 assert(!empty, "Can't pop front of an empty range"); 28 29 cursor = cursor.semanticParent; 30 } 31 32 bool empty() @safe nothrow const { 33 try { 34 return !cursor.isValid; 35 } catch (Exception ex) { 36 } 37 38 return true; 39 } 40 } 41 42 /** Analyze the scope the declaration/definition reside in by backtracking to 43 * the root. 44 */ 45 auto backtrackScopeRange(NodeT)(const(NodeT) node) { 46 static if (is(NodeT == Cursor)) { 47 Cursor c = node; 48 } else { 49 // a Declaration class 50 // TODO add a constraint 51 Cursor c = node.cursor; 52 } 53 54 import std.algorithm : among, filter; 55 import clang.c.Index : CXCursorKind; 56 57 return BacktrackResult(c).filter!(a => a.kind.among(CXCursorKind.unionDecl, 58 CXCursorKind.structDecl, CXCursorKind.classDecl, CXCursorKind.namespace)); 59 } 60 61 /// Backtrack a cursor until the top cursor is reached. 62 auto backtrack(NodeT)(const(NodeT) node) { 63 static if (is(NodeT == Cursor)) { 64 Cursor c = node; 65 } else { 66 // a Declaration class 67 // TODO add a constraint 68 Cursor c = node.cursor; 69 } 70 71 return BacktrackResult(c); 72 } 73 74 /// Determine if a kind creates a local scope. 75 bool isLocalScope(CXCursorKind kind) @safe pure nothrow @nogc { 76 switch (kind) with (CXCursorKind) { 77 case classTemplate: 78 case structDecl: 79 case unionDecl: 80 case classDecl: 81 case cxxMethod: 82 case functionDecl: 83 case constructor: 84 case destructor: 85 return true; 86 default: 87 return false; 88 } 89 } 90 91 /// Determine if a cursor is in the global or namespace scope. 92 bool isGlobalOrNamespaceScope(const(Cursor) c) @safe { 93 import std.algorithm : among; 94 import clang.c.Index : CXCursorKind; 95 96 // if the loop is never ran it is in the global namespace 97 foreach (bt; c.backtrack) { 98 if (bt.kind.among(CXCursorKind.namespace, CXCursorKind.translationUnit)) { 99 return true; 100 } else if (bt.kind.isLocalScope) { 101 return false; 102 } 103 } 104 105 return false; 106 }