diff --git a/analyzers/rspec/cs/Sonar_way_profile.json b/analyzers/rspec/cs/Sonar_way_profile.json index 8ca3d4f38e5..02d9ef0a014 100644 --- a/analyzers/rspec/cs/Sonar_way_profile.json +++ b/analyzers/rspec/cs/Sonar_way_profile.json @@ -174,7 +174,6 @@ "S3398", "S3400", "S3415", - "S3416", "S3427", "S3433", "S3440", diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/LoggersShouldBeNamedForEnclosingType.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/LoggersShouldBeNamedForEnclosingType.cs index 8b6562ea357..67b9d87ec37 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/LoggersShouldBeNamedForEnclosingType.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/LoggersShouldBeNamedForEnclosingType.cs @@ -52,6 +52,7 @@ private static void Process(SonarSyntaxNodeReportingContext context) if (invocation.GetName() is "GetLogger" or "CreateLogger" && invocation.Ancestors().OfType().FirstOrDefault() is { } enclosingType // filter out top-level statements + && !IsArgumentInObjectCreation(invocation) && ExtractArgument(invocation) is { } argument && context.SemanticModel.GetSymbolInfo(invocation).Symbol is IMethodSymbol method && IsValidMethod(method) @@ -61,6 +62,9 @@ private static void Process(SonarSyntaxNodeReportingContext context) } } + private static bool IsArgumentInObjectCreation(InvocationExpressionSyntax invocation) => + invocation.Ancestors().OfType().Any(); + // Extracts T for generic argument, nameof or typeof expressions private static SyntaxNode ExtractArgument(InvocationExpressionSyntax invocation) { diff --git a/analyzers/tests/SonarAnalyzer.Test/Rules/LoggersShouldBeNamedForEnclosingTypeTest.cs b/analyzers/tests/SonarAnalyzer.Test/Rules/LoggersShouldBeNamedForEnclosingTypeTest.cs index 86af60eb7ed..5f5b4dc3f97 100644 --- a/analyzers/tests/SonarAnalyzer.Test/Rules/LoggersShouldBeNamedForEnclosingTypeTest.cs +++ b/analyzers/tests/SonarAnalyzer.Test/Rules/LoggersShouldBeNamedForEnclosingTypeTest.cs @@ -31,7 +31,7 @@ public class LoggersShouldBeNamedForEnclosingTypeTest public void LoggersShouldBeNamedForEnclosingType_CS() => Builder .AddPaths("LoggersShouldBeNamedForEnclosingType.cs") - .AddReferences(NuGetMetadataReference.MicrosoftExtensionsLoggingAbstractions()) + .AddReferences(NuGetMetadataReference.MicrosoftExtensionsLoggingPackages(Constants.NuGetLatestVersion)) .Verify(); [TestMethod] diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/LoggersShouldBeNamedForEnclosingType.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/LoggersShouldBeNamedForEnclosingType.cs index d752871bbff..00636f9b7b1 100644 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/LoggersShouldBeNamedForEnclosingType.cs +++ b/analyzers/tests/SonarAnalyzer.Test/TestCases/LoggersShouldBeNamedForEnclosingType.cs @@ -168,3 +168,53 @@ class LoggerHelper ILogger CreateLogger() => factory.CreateLogger(); // Compliant, T is GenericType } +public class Service +{ + public Service(ILogger logger) + { + } + + public Service(ILogger logger, string otherParameter) + { + } +} + +public class Factory +{ + private readonly ILogger logger = LoggerFactory.Create(builder => { }).CreateLogger(); // Noncompliant + + public Service CreateType(ILoggerFactory loggerFactory) + { + return new Service(loggerFactory.CreateLogger()); + } + + public Service CreateType(ILoggerFactory loggerFactory, string otherParameter) + { + return new Service(loggerFactory.CreateLogger(), otherParameter); + } + + public Service CreateType_LocalVariable(ILoggerFactory loggerFactory) + { + var logger = loggerFactory.CreateLogger(); // Noncompliant FP + return new Service(logger); + } + + public Service CreateType_LocalVariableField() + { + return new Service(logger); + } + + public Service CreateType_Decorator(ILoggerFactory loggerFactory) + { + return new Service(new Decorator(loggerFactory.CreateLogger())); + } + + private class Decorator : ILogger + { + public Decorator(ILogger logger) { } + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { } + public bool IsEnabled(LogLevel logLevel) => true; + public IDisposable BeginScope(TState state) => null; + } +} +