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 } 36 catch (Exception ex) { 37 } 38 39 return true; 40 } 41 } 42 43 /** Analyze the scope the declaration/definition reside in by backtracking to 44 * the root. 45 */ 46 auto backtrackScopeRange(NodeT)(const(NodeT) node) { 47 static if (is(NodeT == Cursor)) { 48 Cursor c = node; 49 } else { 50 // a Declaration class 51 // TODO add a constraint 52 Cursor c = node.cursor; 53 } 54 55 import std.algorithm : among, filter; 56 import clang.c.Index : CXCursorKind; 57 58 return BacktrackResult(c).filter!(a => a.kind.among(CXCursorKind.unionDecl, 59 CXCursorKind.structDecl, CXCursorKind.classDecl, CXCursorKind.namespace)); 60 } 61 62 /// Backtrack a cursor until the top cursor is reached. 63 auto backtrack(NodeT)(const(NodeT) node) { 64 static if (is(NodeT == Cursor)) { 65 Cursor c = node; 66 } else { 67 // a Declaration class 68 // TODO add a constraint 69 Cursor c = node.cursor; 70 } 71 72 return BacktrackResult(c); 73 } 74 75 /// Determine if a kind creates a local scope. 76 bool isLocalScope(CXCursorKind kind) @safe pure nothrow @nogc { 77 switch (kind) with (CXCursorKind) { 78 case classTemplate: 79 case structDecl: 80 case unionDecl: 81 case classDecl: 82 case cxxMethod: 83 case functionDecl: 84 case constructor: 85 case destructor: 86 return true; 87 default: 88 return false; 89 } 90 } 91 92 /// Determine if a cursor is in the global or namespace scope. 93 bool isGlobalOrNamespaceScope(const(Cursor) c) @safe { 94 import std.algorithm : among; 95 import clang.c.Index : CXCursorKind; 96 97 // if the loop is never ran it is in the global namespace 98 foreach (bt; c.backtrack) { 99 if (bt.kind.among(CXCursorKind.namespace, CXCursorKind.translationUnit)) { 100 return true; 101 } else if (bt.kind.isLocalScope) { 102 return false; 103 } 104 } 105 106 return false; 107 }