dotnet / roslyn-analyzers

MIT License
1.55k stars 460 forks source link

CA1416 warnings are erroneously shown in lambdas which are only reachable after platform checks #7323

Open jnm2 opened 1 month ago

jnm2 commented 1 month ago

Analyzer

Diagnostic ID: CA1416: Validate platform compatibility

Analyzer source

Version: SDK 8.0.300

This is particularly agonizing for APIs such as the host/services builders.

The below should not show warnings, but it does:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

if (!OperatingSystem.IsWindows()) return 1;

await Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        services.AddLogging(builder =>
        {
            // ⚠️ CA1416: This call site is reachable on all platforms. 'EventLoggerFactoryExtensions.AddEventLog(
            // ILoggingBuilder, Action<EventLogSettings>)' is only supported on: 'windows'.
            builder.AddEventLog(eventLogSettings =>
            {
                // ⚠️ CA1416: This call site is reachable on all platforms. 'EventLogSettings.SourceName' is only
                // supported on: 'windows'.
                eventLogSettings.SourceName = "Foo";
            });
        });
    }).Build().RunAsync();
return 0;

The workaround makes it clear that this is an inconsistency in the analyzer's behavior; an implicit "SupportedOSPlatform" should be applied to all statements following if (!OperatingSystem.IsWindows()) return 1; without manually stating this:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Runtime.Versioning;

if (!OperatingSystem.IsWindows()) return 1;

[SupportedOSPlatform("windows")] void Configure(HostBuilderContext hostContext, IServiceCollection services)
{
    services.AddLogging(builder =>
    {
        builder.AddEventLog(eventLogSettings =>
        {
            eventLogSettings.SourceName = "Foo";
        });
    });
}

await Host.CreateDefaultBuilder(args).ConfigureServices(Configure).Build().RunAsync();
return 0;