altcover icon indicating copy to clipboard operation
altcover copied to clipboard

Generic methods share the same name and signature

Open kert-stratec opened this issue 9 months ago • 2 comments

Hi,

when there are two methods just differentiating based on their derived types, they share the same name and signature in the cobertura output.

Here is an example:

public static void AddSingleton<T1, T2, T>(this IServiceCollection services, Func<IServiceProvider, T> implementationFactory)
  where T : class, T1, T2 where T1 : class where T2 : class
{
  services.AddSingleton<T2, T>(implementationFactory);
  services.AddSingleton<T1, T>(x => (T)x.GetService<T2>()!);
}

public static void AddSingleton<T1, T2, T3, T>(this IServiceCollection services, Func<IServiceProvider, T> implementationFactory)
  where T : class, T1, T2, T3 where T1 : class where T2 : class where T3 : class
{
  services.AddSingleton<T2, T>(implementationFactory);
  services.AddSingleton<T1, T>(x => (T)x.GetService<T2>()!);
  services.AddSingleton<T3, T>(x => (T)x.GetService<T2>()!);
}

This results in a cobertura.xml that looks like this:

<class name="Extensions.DependencyInjectionExtensions" filename="...\Extensions\DependencyInjectionExtensions.cs" line-rate="0" branch-rate="0" complexity="2.6">
  <methods>
    <method name="AddSingleton" signature="System.Void (Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Func`2&lt;System.IServiceProvider,T&gt;)" line-rate="0" branch-rate="0" complexity="2">
      <lines>
        <line number="37" hits="0" branch="false" />
      </lines>
    </method>
    <method name="AddSingleton" signature="System.Void (Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Func`2&lt;System.IServiceProvider,T&gt;)" line-rate="0" branch-rate="0" complexity="3">
      <lines>
        <line number="60" hits="0" branch="false" />
      </lines>
    </method>
  </methods>
</class>

I noticed the issue when I tried to include the output into a Jenkins CI. The coverage plugin threw an Exception, that there is already an item with the key. Just as context, here is the exception thrown by Jenkins:

java.lang.IllegalArgumentException: There is already a child [METHOD] AddSingletonSystem.Void (Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Func`2<System.IServiceProvider,T>) <0> with the name AddSingletonSystem.Void (Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Func`2<System.IServiceProvider,T>) in [CLASS] Extensions.DependencyInjectionExtensions <3, LINE: 0.00% (0/12)>

kert-stratec avatar May 06 '24 13:05 kert-stratec

It's not just cobertura (which is a downstream format) that does not handle this edge case; the base OpenCover format doesn't record the information, so has two method entries of the same name, differing by metadata token. AltCover's JSON format even merges the two methods into one keyed on the non-generic signature. Of all the formats, it's only the ancient NCover that retains the information as it currently stands.

SteveGilham avatar May 07 '24 08:05 SteveGilham

Well, it seems that AltCover perfectly emulates OpenCover for that format, and coverlet for the json format. The latter also merges the two methods in cobertura format, rather than having two records with the same method signature as in this issue.

Time to improve on that.

SteveGilham avatar May 09 '24 07:05 SteveGilham

Should be resolved in release v8.8.74.

SteveGilham avatar May 31 '24 15:05 SteveGilham

Assuming silence as assent; closing.

SteveGilham avatar Jun 07 '24 17:06 SteveGilham

Sorry for the very late reply. Can confirm it is fixed now! Thank you!

kretzlaff avatar Jun 25 '24 07:06 kretzlaff