1 // Copyright Brian Schott (Hackerpilot) 2014. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 module dscanner.symbol_finder; 7 8 import std.stdio : File; 9 import dparse.lexer; 10 import dparse.parser; 11 import dparse.ast; 12 import dparse.rollback_allocator; 13 import std.stdio; 14 import std.file : isFile; 15 import std.functional : toDelegate; 16 17 void findDeclarationOf(File output, string symbolName, string[] fileNames) 18 { 19 findDeclarationOf((string fileName, size_t line, size_t column) 20 { 21 output.writefln("%s(%d:%d)", fileName, line, column); 22 }, symbolName, fileNames); 23 } 24 25 /// Delegate that gets called every time a declaration gets found 26 alias OutputHandler = void delegate(string fileName, size_t line, size_t column); 27 28 /// Finds all declarations of a symbol in the given fileNames and calls a handler on every occurence. 29 /// Params: 30 /// output = Callback which gets called when a declaration is found 31 /// symbolName = Symbol name to search for 32 /// fileNames = An array of file names which might contain stdin to read from stdin 33 void findDeclarationOf(scope OutputHandler output, string symbolName, string[] fileNames) 34 { 35 import std.array : uninitializedArray, array; 36 import std.conv : to; 37 38 LexerConfig config; 39 StringCache cache = StringCache(StringCache.defaultBucketCount); 40 auto visitor = new FinderVisitor(output, symbolName); 41 foreach (fileName; fileNames) 42 { 43 File f = fileName == "stdin" ? std.stdio.stdin : File(fileName); 44 assert(fileName == "stdin" || isFile(fileName)); 45 if (f.size == 0) 46 continue; 47 auto bytes = uninitializedArray!(ubyte[])(to!size_t(f.size)); 48 f.rawRead(bytes); 49 auto tokens = getTokensForParser(bytes, config, &cache); 50 RollbackAllocator rba; 51 Module m = parseModule(tokens.array, fileName, &rba, toDelegate(&doNothing)); 52 visitor.fileName = fileName; 53 visitor.visit(m); 54 } 55 } 56 57 private: 58 59 void doNothing(string, size_t, size_t, string, bool) 60 { 61 } 62 63 class FinderVisitor : ASTVisitor 64 { 65 this(OutputHandler output, string symbolName) 66 { 67 this.output = output; 68 this.symbolName = symbolName; 69 } 70 71 mixin generateVisit!FunctionDeclaration; 72 mixin generateVisit!ClassDeclaration; 73 mixin generateVisit!InterfaceDeclaration; 74 mixin generateVisit!StructDeclaration; 75 mixin generateVisit!UnionDeclaration; 76 mixin generateVisit!TemplateDeclaration; 77 78 override void visit(const EnumDeclaration dec) 79 { 80 if (dec.name.text == symbolName) 81 output(fileName, dec.name.line, dec.name.column); 82 } 83 84 override void visit(const AnonymousEnumMember member) 85 { 86 if (member.name.text == symbolName) 87 output(fileName, member.name.line, member.name.column); 88 } 89 90 override void visit(const EnumMember member) 91 { 92 if (member.name.text == symbolName) 93 output(fileName, member.name.line, member.name.column); 94 } 95 96 override void visit(const AliasDeclaration dec) 97 { 98 if (dec.declaratorIdentifierList !is null) 99 { 100 foreach (ident; dec.declaratorIdentifierList.identifiers) 101 { 102 if (ident.text == symbolName) 103 output(fileName, ident.line, ident.column); 104 } 105 } 106 foreach (initializer; dec.initializers) 107 { 108 if (initializer.name.text == symbolName) 109 output(fileName, initializer.name.line, 110 initializer.name.column); 111 } 112 } 113 114 override void visit(const Declarator dec) 115 { 116 if (dec.name.text == symbolName) 117 output(fileName, dec.name.line, dec.name.column); 118 } 119 120 override void visit(const AutoDeclaration ad) 121 { 122 foreach (part; ad.parts) 123 { 124 if (part.identifier.text == symbolName) 125 output(fileName, part.identifier.line, part.identifier.column); 126 } 127 } 128 129 override void visit(const FunctionBody) 130 { 131 } 132 133 mixin template generateVisit(T) 134 { 135 override void visit(const T t) 136 { 137 if (t.name.text == symbolName) 138 output(fileName, t.name.line, t.name.column); 139 t.accept(this); 140 } 141 } 142 143 alias visit = ASTVisitor.visit; 144 145 OutputHandler output; 146 string symbolName; 147 string fileName; 148 }