www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Using core.reflect to check for unused paramters

reply Stefan Koch <uplink.coder googlemail.com> writes:
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

```d
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.
Aug 30
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
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. ```d 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. ```d 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.
Sep 02
parent reply user1234 <user1234 12.de> writes:
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 ?
Sep 03
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
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.
Sep 03
parent reply user1234 <user1234 12.de> writes:
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 ?
Sep 03
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
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.
Sep 03
parent user1234 <user1234 12.de> writes:
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.
Sep 03