import core.reflect.reflect;
import core.reflect.transitiveVisitor;
// import core.reflect.nodeToString();

int func(int a, int b)
{
    return a + b;
}
static assert(!hasUnusedParameters(nodeFromName("func")));

int func2(int a, int b, int c)
{
    return func(a, b);
}
static assert(hasUnusedParameters(nodeFromName("func2")));


bool hasUnusedParameters(const Node n)
{
    bool result = false;
    if (auto fd = cast(FunctionDeclaration) n)
    {
        result = hasUnusedParameters(fd);
    }
    return result;
}

bool hasUnusedParameters(const FunctionDeclaration fd)
{
    bool[const(VariableDeclaration)] parameterUsageList;
    foreach(p;fd.parameters)
    {
        parameterUsageList[p] = false;
    }

    class Marker : TransitiveVisitor
    {
        bool[const(VariableDeclaration)]* parameterUsageList;

        this(bool[const(VariableDeclaration)] *parameterUsageList)
        {
            this.parameterUsageList = parameterUsageList;
        }

        alias visit = TransitiveVisitor.visit;
        override void visit(VariableDeclaration vd)
        {
            if (auto b = vd in *parameterUsageList)
            {
                *b = true;
            }
        }
    }

    scope marker = new Marker(&parameterUsageList);
    (cast()fd.fbody).accept(marker);

    foreach(v, unused; parameterUsageList)
    {
        if (!unused) return true;
    }
    return false;
}