1 /** 2 * Copyright: Copyright (c) 2016 Wojciech Szęszoł. All rights reserved. 3 * Authors: Wojciech Szęszoł 4 * Version: Initial created: Mar 08, 2016 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 6 */ 7 module dstep.translator.MacroIndex; 8 9 import std.typecons; 10 import std.algorithm; 11 import std.range; 12 13 import clang.c.Index; 14 import clang.Cursor; 15 import clang.SourceLocation; 16 import clang.SourceRange; 17 import clang.Token; 18 import clang.TranslationUnit; 19 20 import dstep.translator.Preprocessor; 21 22 class MacroIndex 23 { 24 private TranslationUnit translUnit; 25 private bool delegate (Cursor, Cursor) lessOp; 26 private Cursor[] expansions; 27 private Cursor[string] globalCursors_; 28 public Directive[] directives; 29 30 this(TranslationUnit translUnit) 31 { 32 this.translUnit = translUnit; 33 34 auto expansionsAppender = appender!(Cursor[])(); 35 36 foreach (cursor, parent; translUnit.cursor.all) 37 { 38 if (cursor.kind == CXCursorKind.macroExpansion) 39 expansionsAppender.put(cursor); 40 else if (!cursor.spelling.empty) 41 globalCursors_[extendedSpelling(cursor)] = cursor; 42 } 43 44 lessOp = translUnit.relativeCursorLocationLessOp(); 45 expansions = expansionsAppender.data.sort!((a, b) => lessOp(a, b)).array; 46 directives = dstep.translator.Preprocessor.directives(translUnit); 47 } 48 49 static string extendedSpelling(Cursor cursor) 50 { 51 import std.format : format; 52 53 switch (cursor.kind) 54 { 55 case CXCursorKind.structDecl: 56 return format("struct %s", cursor.spelling); 57 58 case CXCursorKind.unionDecl: 59 return format("union %s", cursor.spelling); 60 61 case CXCursorKind.enumDecl: 62 return format("enum %s", cursor.spelling); 63 64 default: 65 return cursor.spelling; 66 } 67 } 68 69 Cursor[] queryExpansion(Cursor cursor) const 70 { 71 import std.array; 72 import std.algorithm.searching; 73 74 auto expansionsSorted = expansions.assumeSorted!((a, b) => lessOp(a, b)); 75 76 auto equal = expansionsSorted.equalRange(cursor); 77 auto greater = expansionsSorted.upperBound(cursor); 78 79 auto result = appender!(Cursor[])(); 80 81 if (!equal.empty) 82 result ~= equal.array; 83 84 result ~= until 85 !(itr => itr.file != cursor.file || 86 itr.location.offset >= cursor.extent.end.offset) 87 (greater, OpenRight.yes); 88 89 return result.data; 90 } 91 92 93 Tuple!(bool, SourceLocation) includeGuardLocation() 94 { 95 import std.range.primitives : empty; 96 97 static bool checkIfndef(ConditionalDirective directives, string identifier) 98 { 99 auto negation = directives.condition.peek!UnaryExpr; 100 101 if (negation !is null && negation.operator == "!") 102 { 103 auto defined = negation.subexpr.peek!DefinedExpr; 104 return defined !is null && defined.identifier == identifier; 105 } 106 107 return false; 108 } 109 110 if (!directives.empty) 111 { 112 if (directives[0].kind == DirectiveKind.pragmaOnce) 113 { 114 return Tuple!(bool, SourceLocation)(true, directives[0].extent.start); 115 } 116 else if (2 <= directives.length) 117 { 118 auto ifndef = cast (ConditionalDirective) directives[0]; 119 auto define = cast (DefineDirective) directives[1]; 120 auto endif = directives[$ - 1]; 121 122 if (ifndef && define && 123 ifndef.endif == endif && 124 checkIfndef(ifndef, define.spelling)) 125 return Tuple!(bool, SourceLocation)(true, ifndef.location); 126 } 127 } 128 129 return Tuple!(bool, SourceLocation)(false, SourceLocation.empty); 130 } 131 132 Cursor[string] globalCursors() 133 { 134 return globalCursors_; 135 } 136 }