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