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 }