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