Thread overview
Using core.reflect to check for unused paramters
Aug 30, 2021
Stefan Koch
Re: Using core.reflect to check for unused parameters
Sep 02, 2021
Stefan Koch
Sep 03, 2021
user1234
Sep 03, 2021
Stefan Koch
Sep 03, 2021
user1234
Sep 03, 2021
Stefan Koch
Sep 03, 2021
user1234
August 30, 2021

Hi,

I've just extended core.reflect's reflection to function bodies.

Which means you can now do fun things such as checking for unused parameters at compile-time.

If you checkout the core.reflect branch from my forks of druntime and dmd you can run the example code below and convince yourself that it works

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;
}

I am aware that these block of code posts of mine are not the most appealing.
Please wait a little I will have more high-levels descriptions as the core.reflect prototype gets closer to a stable state.

September 02, 2021

On Monday, 30 August 2021 at 18:13:59 UTC, Stefan Koch wrote:

>

Hi,

I've just extended core.reflect's reflection to function bodies.

Which means you can now do fun things such as checking for unused parameters at compile-time.

Ah the bugs are biting again.

if you have played with the code I posted you will have seen that it didn't count parameters which were used as variable initializer

i.e.

void func(int p)
{
  auto x = p;
}

would have complained about unused parameters.
The reason is that we didn't visit the _init field of the VariableDeclaration.

luckily it's easily fixed.

    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;
            }
            vd._init.accept(this);
        }
    }

now this visitor will reliably detect usage of parameters.

September 03, 2021

On Thursday, 2 September 2021 at 21:27:33 UTC, Stefan Koch wrote:

>

[...]
now this visitor will reliably detect usage of parameters.

BTW, I'm curious to know how this can work. Should not VarExp (and not VarDecl) be overridden to mark ?

September 03, 2021

On Friday, 3 September 2021 at 13:02:37 UTC, user1234 wrote:

>

On Thursday, 2 September 2021 at 21:27:33 UTC, Stefan Koch wrote:

>

[...]
now this visitor will reliably detect usage of parameters.

BTW, I'm curious to know how this can work. Should not VarExp (and not VarDecl) be overridden to mark ?

VerExps have a VarDecl member.
which the transitive visitor looks into for you.

You could look at VarExps but I chose to look into VarDecls instead.

September 03, 2021

On Friday, 3 September 2021 at 14:45:20 UTC, Stefan Koch wrote:

>

On Friday, 3 September 2021 at 13:02:37 UTC, user1234 wrote:

>

On Thursday, 2 September 2021 at 21:27:33 UTC, Stefan Koch wrote:

>

[...]
now this visitor will reliably detect usage of parameters.

BTW, I'm curious to know how this can work. Should not VarExp (and not VarDecl) be overridden to mark ?

VerExps have a VarDecl member.
which the transitive visitor looks into for you.

You could look at VarExps but I chose to look into VarDecls instead.

so FuncDeclaration parameters are not visited, that's why that works ?
only bodies are visited ?

September 03, 2021

On Friday, 3 September 2021 at 15:32:59 UTC, user1234 wrote:

>

On Friday, 3 September 2021 at 14:45:20 UTC, Stefan Koch wrote:

>

On Friday, 3 September 2021 at 13:02:37 UTC, user1234 wrote:

>

On Thursday, 2 September 2021 at 21:27:33 UTC, Stefan Koch wrote:

>

[...]
now this visitor will reliably detect usage of parameters.

BTW, I'm curious to know how this can work. Should not VarExp (and not VarDecl) be overridden to mark ?

VerExps have a VarDecl member.
which the transitive visitor looks into for you.

You could look at VarExps but I chose to look into VarDecls instead.

so FuncDeclaration parameters are not visited, that's why that works ?
only bodies are visited ?

Exactly this works because of this line.
(cast()fd.fbody).accept(marker);
I am starting the visitor at the body of the function.
And since there no back-edge to the function declaration it works.
If you have a back-edge to the function declaration for example in recursive call it would stop working.
So visiting the VarExp is a better idea.

September 03, 2021

On Friday, 3 September 2021 at 15:47:16 UTC, Stefan Koch wrote:

>

On Friday, 3 September 2021 at 15:32:59 UTC, user1234 wrote:

>

On Friday, 3 September 2021 at 14:45:20 UTC, Stefan Koch wrote:

>

On Friday, 3 September 2021 at 13:02:37 UTC, user1234 wrote:

>

On Thursday, 2 September 2021 at 21:27:33 UTC, Stefan Koch wrote:

>

[...]
now this visitor will reliably detect usage of parameters.

BTW, I'm curious to know how this can work. Should not VarExp (and not VarDecl) be overridden to mark ?

VerExps have a VarDecl member.
which the transitive visitor looks into for you.

You could look at VarExps but I chose to look into VarDecls instead.

so FuncDeclaration parameters are not visited, that's why that works ?
only bodies are visited ?

Exactly this works because of this line.
(cast()fd.fbody).accept(marker);

indeed I've missed that line

>

I am starting the visitor at the body of the function.
And since there no back-edge to the function declaration it works.
If you have a back-edge to the function declaration for example in recursive call it would stop working.
So visiting the VarExp is a better idea.

Yes and no. It's better as example, so that we can see clearly that params are marked on use. Basically my first answer was posted because overridding the visit of VarDecl was confusing.

Otherwise that looks like a convincing example.