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 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 16 void findDeclarationOf(File output, string symbolName, string[] fileNames) 17 { 18 import std.array : uninitializedArray, array; 19 import std.conv : to; 20 21 LexerConfig config; 22 StringCache cache = StringCache(StringCache.defaultBucketCount); 23 auto visitor = new FinderVisitor(output, symbolName); 24 foreach (fileName; fileNames) 25 { 26 File f = File(fileName); 27 assert(isFile(fileName)); 28 if (f.size == 0) 29 continue; 30 auto bytes = uninitializedArray!(ubyte[])(to!size_t(f.size)); 31 f.rawRead(bytes); 32 auto tokens = getTokensForParser(bytes, config, &cache); 33 RollbackAllocator rba; 34 Module m = parseModule(tokens.array, fileName, &rba, &doNothing); 35 visitor.fileName = fileName; 36 visitor.visit(m); 37 } 38 } 39 40 private: 41 42 void doNothing(string, size_t, size_t, string, bool) 43 { 44 } 45 46 class FinderVisitor : ASTVisitor 47 { 48 this(File output, string symbolName) 49 { 50 this.output = output; 51 this.symbolName = symbolName; 52 } 53 54 mixin generateVisit!FunctionDeclaration; 55 mixin generateVisit!ClassDeclaration; 56 mixin generateVisit!InterfaceDeclaration; 57 mixin generateVisit!StructDeclaration; 58 mixin generateVisit!UnionDeclaration; 59 mixin generateVisit!TemplateDeclaration; 60 61 override void visit(const EnumDeclaration dec) 62 { 63 if (dec.name.text == symbolName) 64 output.writefln("%s(%d:%d)", fileName, dec.name.line, dec.name.column); 65 } 66 67 override void visit(const AnonymousEnumMember member) 68 { 69 if (member.name.text == symbolName) 70 output.writefln("%s(%d:%d)", fileName, member.name.line, member.name.column); 71 } 72 73 override void visit(const EnumMember member) 74 { 75 if (member.name.text == symbolName) 76 output.writefln("%s(%d:%d)", fileName, member.name.line, member.name.column); 77 } 78 79 override void visit(const AliasDeclaration dec) 80 { 81 if (dec.identifierList !is null) 82 { 83 foreach (ident; dec.identifierList.identifiers) 84 { 85 if (ident.text == symbolName) 86 output.writefln("%s(%d:%d)", fileName, ident.line, ident.column); 87 } 88 } 89 foreach (initializer; dec.initializers) 90 { 91 if (initializer.name.text == symbolName) 92 output.writefln("%s(%d:%d)", fileName, initializer.name.line, 93 initializer.name.column); 94 } 95 } 96 97 override void visit(const Declarator dec) 98 { 99 if (dec.name.text == symbolName) 100 output.writefln("%s(%d:%d)", fileName, dec.name.line, dec.name.column); 101 } 102 103 override void visit(const AutoDeclaration ad) 104 { 105 foreach (id; ad.identifiers) 106 { 107 if (id.text == symbolName) 108 output.writefln("%s(%d:%d)", fileName, id.line, id.column); 109 } 110 } 111 112 override void visit(const FunctionBody) 113 { 114 } 115 116 mixin template generateVisit(T) 117 { 118 override void visit(const T t) 119 { 120 if (t.name.text == symbolName) 121 output.writefln("%s(%d:%d)", fileName, t.name.line, t.name.column); 122 t.accept(this); 123 } 124 } 125 126 alias visit = ASTVisitor.visit; 127 128 File output; 129 string symbolName; 130 string fileName; 131 }