Open
Description
It looks like Coverlet
misses the inline
directive on F# functions and reports zero coverage for such functions and methods:
In this example above, many of the functions that I test use unwrapHandler
but, zero coverage is returned.
Here we see that valueCurry
is used within the same method, but it is still reported as untested.
If I remove inline
then it looks like:
So, even in my simple case, Coverlet
misses 6K+ passes and reports the code as untested.
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
daveMueller commentedon Sep 19, 2021
Thanks for reporting.
daveMueller commentedon Oct 5, 2021
OK this is really complicated. I looked into the IL and saw that the compiler is generating a second function for
inline
functions with the exact same sequence point but with$W
suffixed. This is described here https://github.com/fsharp/fslang-design/blob/main/FSharp-5.0/FS-1071-witness-passing-quotations.md#compiled-form-of-srtp-constrained-generic-code.Coverlet is properly injecting the tracker in both functions but nevertheless they both never get called. Or at least for me it seems like this.
When I look into the IL without
inline
there is only one function without the$W
. The function is also properly instrumented and the function is beeing call and thus hit.Now when I look into the same IL with
inline
none of the two instrumented functions is called. Seems like the compiler optimized it in a way that the corresponding IL operation is used instead of a function call.Maybe this is just because of the simple code example I'm using but I try to analyze this a bit more. Any information on this is highly welcome.
AlexeyRaga commentedon Oct 5, 2021
I think that this is what
inline
means: the compiler inlines (copies) the function body instead of the function call.From F# documentation:
I also see that
inline
in F# works across compilation units:So based on that I would expect that there'd be no calls to the
inline
functions and that they are only compiled into assemblies as functions (with the flag mentioned above) to be inlined later in assemblies that use them...But I don't know what happens at the edge cases, like:
inline
and not just a function? I would guess that it'd be inlined too (otherwise why enabling the keyword there), but I haven't written much OOP in F# myself...daveMueller commentedon Oct 12, 2021
Thanks for the explanation. I currently don't have any idea how we could work around this. I can't find a way to map the
inline
function body to the executed IL.The only thing that comes to my mind is excluding
inline
functions from the instrumentation to at least get rid of the falsenot covered
report ofinline functions
.@MarcoRossignoli @petli what do you think? Any other ideas?
daveMueller commentedon Oct 18, 2021
OK I just got a response from the
fsharp
team that they currently don't emit this information (dotnet/fsharp#12263). Now I really don't have any other idea how to deal with this except for excludinginline
functions.