149 lines
3.8 KiB
D
149 lines
3.8 KiB
D
// Copyright Brian Schott (Hackerpilot) 2014.
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
module symbol_finder;
|
|
|
|
import std.stdio : File;
|
|
import dparse.lexer;
|
|
import dparse.parser;
|
|
import dparse.ast;
|
|
import dparse.rollback_allocator;
|
|
import std.stdio;
|
|
import std.file : isFile;
|
|
import std.functional : toDelegate;
|
|
|
|
void findDeclarationOf(File output, string symbolName, string[] fileNames)
|
|
{
|
|
findDeclarationOf((string fileName, size_t line, size_t column)
|
|
{
|
|
output.writefln("%s(%d:%d)", fileName, line, column);
|
|
}, symbolName, fileNames);
|
|
}
|
|
|
|
/// Delegate that gets called every time a declaration gets found
|
|
alias OutputHandler = void delegate(string fileName, size_t line, size_t column);
|
|
|
|
/// Finds all declarations of a symbol in the given fileNames and calls a handler on every occurence.
|
|
/// Params:
|
|
/// output = Callback which gets called when a declaration is found
|
|
/// symbolName = Symbol name to search for
|
|
/// fileNames = An array of file names which might contain stdin to read from stdin
|
|
void findDeclarationOf(scope OutputHandler output, string symbolName, string[] fileNames)
|
|
{
|
|
import std.array : uninitializedArray, array;
|
|
import std.conv : to;
|
|
|
|
LexerConfig config;
|
|
StringCache cache = StringCache(StringCache.defaultBucketCount);
|
|
auto visitor = new FinderVisitor(output, symbolName);
|
|
foreach (fileName; fileNames)
|
|
{
|
|
File f = fileName == "stdin" ? std.stdio.stdin : File(fileName);
|
|
assert(fileName == "stdin" || isFile(fileName));
|
|
if (f.size == 0)
|
|
continue;
|
|
auto bytes = uninitializedArray!(ubyte[])(to!size_t(f.size));
|
|
f.rawRead(bytes);
|
|
auto tokens = getTokensForParser(bytes, config, &cache);
|
|
RollbackAllocator rba;
|
|
Module m = parseModule(tokens.array, fileName, &rba, toDelegate(&doNothing));
|
|
visitor.fileName = fileName;
|
|
visitor.visit(m);
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
void doNothing(string, size_t, size_t, string, bool)
|
|
{
|
|
}
|
|
|
|
class FinderVisitor : ASTVisitor
|
|
{
|
|
this(OutputHandler output, string symbolName)
|
|
{
|
|
this.output = output;
|
|
this.symbolName = symbolName;
|
|
}
|
|
|
|
mixin generateVisit!FunctionDeclaration;
|
|
mixin generateVisit!ClassDeclaration;
|
|
mixin generateVisit!InterfaceDeclaration;
|
|
mixin generateVisit!StructDeclaration;
|
|
mixin generateVisit!UnionDeclaration;
|
|
mixin generateVisit!TemplateDeclaration;
|
|
|
|
override void visit(const EnumDeclaration dec)
|
|
{
|
|
if (dec.name.text == symbolName)
|
|
output(fileName, dec.name.line, dec.name.column);
|
|
}
|
|
|
|
override void visit(const AnonymousEnumMember member)
|
|
{
|
|
if (member.name.text == symbolName)
|
|
output(fileName, member.name.line, member.name.column);
|
|
}
|
|
|
|
override void visit(const EnumMember member)
|
|
{
|
|
if (member.name.text == symbolName)
|
|
output(fileName, member.name.line, member.name.column);
|
|
}
|
|
|
|
override void visit(const AliasDeclaration dec)
|
|
{
|
|
if (dec.identifierList !is null)
|
|
{
|
|
foreach (ident; dec.identifierList.identifiers)
|
|
{
|
|
if (ident.text == symbolName)
|
|
output(fileName, ident.line, ident.column);
|
|
}
|
|
}
|
|
foreach (initializer; dec.initializers)
|
|
{
|
|
if (initializer.name.text == symbolName)
|
|
output(fileName, initializer.name.line,
|
|
initializer.name.column);
|
|
}
|
|
}
|
|
|
|
override void visit(const Declarator dec)
|
|
{
|
|
if (dec.name.text == symbolName)
|
|
output(fileName, dec.name.line, dec.name.column);
|
|
}
|
|
|
|
override void visit(const AutoDeclaration ad)
|
|
{
|
|
foreach (part; ad.parts)
|
|
{
|
|
if (part.identifier.text == symbolName)
|
|
output(fileName, part.identifier.line, part.identifier.column);
|
|
}
|
|
}
|
|
|
|
override void visit(const FunctionBody)
|
|
{
|
|
}
|
|
|
|
mixin template generateVisit(T)
|
|
{
|
|
override void visit(const T t)
|
|
{
|
|
if (t.name.text == symbolName)
|
|
output(fileName, t.name.line, t.name.column);
|
|
t.accept(this);
|
|
}
|
|
}
|
|
|
|
alias visit = ASTVisitor.visit;
|
|
|
|
OutputHandler output;
|
|
string symbolName;
|
|
string fileName;
|
|
}
|