Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/list-of-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ You may continue using obsolete APIs in your application, but we advise explorin
| `LOGGEN036` | A value being logged doesn't have an effective way to be converted into a string |
| `LOGGEN037` | Logging method contains malformed format strings |
| `LOGGEN038` | Primary constructor parameter of type Microsoft.Extensions.Logging.ILogger is hidden by a field |
| `LOGGEN039` | Logging method parameters can't have the "params" or "scoped" modifier |

# Metrics

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,4 +258,10 @@ internal sealed class DiagDescriptors : DiagDescriptorsBase
messageFormat: Resources.PrimaryConstructorParameterLoggerHiddenMessage,
category: Category,
DiagnosticSeverity.Info);

public static DiagnosticDescriptor LoggingMethodParameterParams { get; } = Make(
id: DiagnosticIds.LoggerMessage.LOGGEN039,
title: Resources.LoggingMethodParameterParamsTitle,
messageFormat: Resources.LoggingMethodParameterParamsMessage,
category: Category);
}
16 changes: 16 additions & 0 deletions src/Generators/Microsoft.Gen.Logging/Parsing/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -540,18 +540,34 @@ private void CheckTagNamesAreUnique(LoggingMethod lm, Dictionary<LoggingMethodPa
return null;
}

if (paramSymbol.IsParams)
{
Diag(DiagDescriptors.LoggingMethodParameterParams, paramSymbol.GetLocation(), paramName);
return null;
}

string? qualifier = null;
if (paramSymbol.RefKind == RefKind.In)
{
qualifier = "in";
}
else if (paramSymbol.RefKind == RefKind.RefReadOnlyParameter)
{
qualifier = "ref readonly";
}
else if (paramSymbol.RefKind != RefKind.None)
{
// Parameter has "ref", "out" modifier, no can do
Diag(DiagDescriptors.LoggingMethodParameterRefKind, paramSymbol.GetLocation(), paramSymbol.ContainingSymbol.Name, paramName);
return null;
}

if (paramSymbol.ScopedKind != ScopedKind.None)
{
Diag(DiagDescriptors.LoggingMethodParameterParams, paramSymbol.GetLocation(), paramName);
return null;
}

string typeName = paramTypeSymbol.ToDisplayString(
SymbolDisplayFormat.FullyQualifiedFormat.WithMiscellaneousOptions(
SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier | SymbolDisplayMiscellaneousOptions.UseSpecialTypes));
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/Generators/Microsoft.Gen.Logging/Parsing/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -351,4 +351,10 @@
<data name="PrimaryConstructorParameterLoggerHiddenMessage" xml:space="preserve">
<value>Class '{0}' has a primary constructor parameter of type Microsoft.Extensions.Logging.ILogger that is hidden by a field in the class or a base class, preventing its use</value>
</data>
<data name="LoggingMethodParameterParamsMessage" xml:space="preserve">
<value>Logging method parameter "{0}" has an unsupported modifier ("params" or "scoped")</value>
</data>
<data name="LoggingMethodParameterParamsTitle" xml:space="preserve">
<value>Logging method parameters can't have the "params" or "scoped" modifier</value>
</data>
</root>
1 change: 1 addition & 0 deletions src/Shared/DiagnosticIds/DiagnosticIds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ internal static class LoggerMessage
internal const string LOGGEN036 = nameof(LOGGEN036);
internal const string LOGGEN037 = nameof(LOGGEN037);
internal const string LOGGEN038 = nameof(LOGGEN038);
internal const string LOGGEN039 = nameof(LOGGEN039);
}

internal static class Metrics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,18 @@ public void InParameterTests()
Assert.Contains("Hello from S", collector.LatestRecord.Message);
}

[Fact]
public void RefReadOnlyParameterTests()
{
using var logger = Utils.GetLogger();
var collector = logger.FakeLogCollector;

RefReadOnlyParameterTestExtensions.S s;
RefReadOnlyParameterTestExtensions.M0(logger, ref s);
Assert.Equal(1, collector.Count);
Assert.Contains("Hello from S", collector.LatestRecord.Message);
}

[Fact]
public void AtSymbolsTest()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Extensions.Logging;

namespace TestClasses
{
internal static partial class RefReadOnlyParameterTestExtensions
{
internal struct S
{
public override readonly string ToString() => "Hello from S";
}

[LoggerMessage(0, LogLevel.Information, "M0 {s}")]
internal static partial void M0(ILogger logger, ref readonly S s);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,45 @@ partial class C
await RunGenerator(source, DiagDescriptors.LoggingMethodParameterRefKind);
}

[Fact]
public async Task LogMethodParamsModifier()
{
const string Source = @"
partial class C
{
[LoggerMessage(0, LogLevel.Debug, ""Parameter"")]
static partial void M(ILogger logger, params int[] /*0+*/values/*-0*/);
}";

await RunGenerator(Source, DiagDescriptors.LoggingMethodParameterParams);
}

[Fact]
public async Task LogMethodRefReadOnlyModifier()
{
const string Source = @"
partial class C
{
[LoggerMessage(0, LogLevel.Debug, ""Parameter {p1}"")]
static partial void M(ILogger logger, ref readonly int p1);
}";

await RunGenerator(Source);
}

[Fact]
public async Task LogMethodScopedModifier()
{
const string Source = @"
partial class C
{
[LoggerMessage(0, LogLevel.Debug, ""Parameter {p1}"")]
static partial void M(ILogger logger, scoped ref readonly int /*0+*/p1/*-0*/);
}";

await RunGenerator(Source, DiagDescriptors.LoggingMethodParameterParams);
}

[Theory]
[CombinatorialData]
public async Task LogMethod_DetectsSensitiveMembersInRecord([CombinatorialRange(0, TotalSensitiveCases)] int positionNumber)
Expand Down
Loading