www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - static analysis: how to test code reachability at compile time

reply Timothee Cour <thelastmammoth gmail.com> writes:
 I'd like to have the following tools to help with static analysis & code
coverage:

1) test whether code is reachable or not.

Of course it only works for executables and may have some caveats (eg:
goto), but its still useful diagnostic tool.

__traits(isReachable): true when the current context can be reached via at
least one code path starting from main():

----
void fun1(){
//__traits(isReachable) would be false here because even though fun1 is
called by fun2, it can never be called starting from main().
}
void fun2(){fun1;}
void fun3(){} // would also be false, because of static if(temp); with temp
being known to be 0 at compile time.
void fun4(){
return;
//__traits(isReachable) would be false here because all code paths return
above this point.
}
void main(){enum temp=0; static if(temp) fun3; fun4;}
----

When a pointer to a function is taken, we may want to assume by convention
that __traits(isReachable) is true.

This would enable for example to make sure a given code is never called.
Note, static assert(0) is not the same.

2)
static code call graph: know caller/calling functions for a given function.


3) static code coverage
this would allow us to tell at compile time the code coverage of a module;
it is larger than runtime coverage, but still useful to find dead code.
May 21 2013
parent reply "Diggory" <diggsey googlemail.com> writes:
On Tuesday, 21 May 2013 at 21:15:58 UTC, Timothee Cour wrote:
  I'd like to have the following tools to help with static 
 analysis & code
 coverage:

 1) test whether code is reachable or not.

 Of course it only works for executables and may have some 
 caveats (eg:
 goto), but its still useful diagnostic tool.

 __traits(isReachable): true when the current context can be 
 reached via at
 least one code path starting from main():

 ----
 void fun1(){
 //__traits(isReachable) would be false here because even though 
 fun1 is
 called by fun2, it can never be called starting from main().
 }
 void fun2(){fun1;}
 void fun3(){} // would also be false, because of static 
 if(temp); with temp
 being known to be 0 at compile time.
 void fun4(){
 return;
 //__traits(isReachable) would be false here because all code 
 paths return
 above this point.
 }
 void main(){enum temp=0; static if(temp) fun3; fun4;}
 ----

 When a pointer to a function is taken, we may want to assume by 
 convention
 that __traits(isReachable) is true.

 This would enable for example to make sure a given code is 
 never called.
 Note, static assert(0) is not the same.

 2)
 static code call graph: know caller/calling functions for a 
 given function.


 3) static code coverage
 this would allow us to tell at compile time the code coverage 
 of a module;
 it is larger than runtime coverage, but still useful to find 
 dead code.
It would be very easy to introduce paradoxes if this were possible, simply use a static if to call something only if it is unreachable.
May 21 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 05/21/2013 11:31 PM, Diggory wrote:
 ...

 It would be very easy to introduce paradoxes
This is the case already.
 if this were possible,  simply use a static if to call something only if it is
unreachable.
I don't think this would be possible because function-local symbols are not accessible from outside.
May 21 2013