diff --git a/src/Meziantou.Analyzer/Internals/CompilationExtensions.cs b/src/Meziantou.Analyzer/Internals/CompilationExtensions.cs index 14509257..45165810 100644 --- a/src/Meziantou.Analyzer/Internals/CompilationExtensions.cs +++ b/src/Meziantou.Analyzer/Internals/CompilationExtensions.cs @@ -8,6 +8,13 @@ namespace Meziantou.Analyzer; internal static class CompilationExtensions { + public static bool IsNet9OrGreater(this Compilation compilation) + { + var type = compilation.GetSpecialType(SpecialType.System_Object); + var version = type.ContainingAssembly.Identity.Version; + return version.Major >= 9; + } + #if ROSLYN_3_8 public static ImmutableArray GetTypesByMetadataName(this Compilation compilation, string typeMetadataName) { diff --git a/src/Meziantou.Analyzer/Rules/OptimizeLinqUsageAnalyzer.cs b/src/Meziantou.Analyzer/Rules/OptimizeLinqUsageAnalyzer.cs index 280eee77..abd0ded3 100755 --- a/src/Meziantou.Analyzer/Rules/OptimizeLinqUsageAnalyzer.cs +++ b/src/Meziantou.Analyzer/Rules/OptimizeLinqUsageAnalyzer.cs @@ -287,24 +287,28 @@ private void UseFindInsteadOfFirstOrDefault(OperationAnalysisContext context, II if (firstArgumentType is null) return; - if (firstArgumentType.OriginalDefinition.IsEqualTo(ListOfTSymbol)) - { - ImmutableDictionary properties; - var predicateArgument = operation.Arguments[1].Value; - if (predicateArgument is IDelegateCreationOperation) - { - properties = CreateProperties(OptimizeLinqUsageData.UseFindMethod); - } - else - { - if (!context.Options.GetConfigurationValue(operation, ListMethodsRule.Id + ".report_when_conversion_needed", defaultValue: false)) - return; + if (!firstArgumentType.OriginalDefinition.IsEqualTo(ListOfTSymbol)) + return; - properties = CreateProperties(OptimizeLinqUsageData.UseFindMethodWithConversion); - } + // https://github.com/dotnet/runtime/issues/108064 + if (context.Compilation.IsNet9OrGreater()) + return; + + ImmutableDictionary properties; + var predicateArgument = operation.Arguments[1].Value; + if (predicateArgument is IDelegateCreationOperation) + { + properties = CreateProperties(OptimizeLinqUsageData.UseFindMethod); + } + else + { + if (!context.Options.GetConfigurationValue(operation, ListMethodsRule.Id + ".report_when_conversion_needed", defaultValue: false)) + return; - context.ReportDiagnostic(ListMethodsRule, properties, operation, DiagnosticInvocationReportOptions.ReportOnMember, "Find()", operation.TargetMethod.Name); + properties = CreateProperties(OptimizeLinqUsageData.UseFindMethodWithConversion); } + + context.ReportDiagnostic(ListMethodsRule, properties, operation, DiagnosticInvocationReportOptions.ReportOnMember, "Find()", operation.TargetMethod.Name); } private void UseTrueForAllInsteadOfAll(OperationAnalysisContext context, IInvocationOperation operation) diff --git a/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs b/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs index df94c623..967be2f1 100755 --- a/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs +++ b/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs @@ -191,7 +191,7 @@ private Task CreateProject() break; case TargetFramework.Net9_0: - AddNuGetReference("Microsoft.NETCore.App.Ref", "9.0.0-preview.4.24266.19", "ref/net9.0/"); + AddNuGetReference("Microsoft.NETCore.App.Ref", "9.0.0-rc.1.24431.7", "ref/net9.0/"); break; case TargetFramework.AspNetCore5_0: diff --git a/tests/Meziantou.Analyzer.Test/Rules/OptimizeLinqUsageAnalyzerUseDirectMethodsTests.cs b/tests/Meziantou.Analyzer.Test/Rules/OptimizeLinqUsageAnalyzerUseDirectMethodsTests.cs index 4e3f3615..0bc713fc 100755 --- a/tests/Meziantou.Analyzer.Test/Rules/OptimizeLinqUsageAnalyzerUseDirectMethodsTests.cs +++ b/tests/Meziantou.Analyzer.Test/Rules/OptimizeLinqUsageAnalyzerUseDirectMethodsTests.cs @@ -14,6 +14,27 @@ private static ProjectBuilder CreateProjectBuilder() .WithCodeFixProvider(); } + [Fact] + public Task FirstOrDefaultAsync_Net9() + => CreateProjectBuilder() + .WithTargetFramework(TargetFramework.Net9_0) + .WithSourceCode(""" + using System.Linq; + class Test + { + public Test() + { + var enumerable = System.Linq.Enumerable.Empty(); + var list = new System.Collections.Generic.List(); + list.FirstOrDefault(); + list.FirstOrDefault(x => x == 0); + enumerable.FirstOrDefault(); + enumerable.FirstOrDefault(x => x == 0); + } + } + """) + .ValidateAsync(); + [Fact] public async Task FirstOrDefaultAsync() {