Skip to content

Commit

Permalink
Allow use of overloaded methods when using LoggerMessage (#64573)
Browse files Browse the repository at this point in the history
* Compute unique method names for generated code

Calculates and assigns a unique LoggerMethod name as required, and uses
this new unique name for generating types in the source generator. This
allows using the LoggerMessageAttribute on methods that share the same
name but have different method signatures.

Fix #61814

* Rename MethodOverloadTestExtensions to OverloadTestExtensions

Also resolves other PR feedback, an extra blank line and incorrect use
of an implicit type.

* Remove un-needed overload tests
JakeYallop authored Feb 2, 2022

Verified

This commit was signed with the committer’s verified signature.
blittle Bret Little
1 parent 77b69b8 commit 2e35741
Showing 4 changed files with 59 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -138,14 +138,14 @@ private void GenStruct(LoggerMethod lm, string nestedIndentation)
{nestedIndentation}/// {s_generatedTypeSummary}
{nestedIndentation}[{s_generatedCodeAttribute}]
{nestedIndentation}[{s_editorBrowsableAttribute}]
{nestedIndentation}private readonly struct __{lm.Name}Struct : global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.KeyValuePair<string, object?>>
{nestedIndentation}private readonly struct __{lm.UniqueName}Struct : global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.KeyValuePair<string, object?>>
{nestedIndentation}{{");
GenFields(lm, nestedIndentation);

if (lm.TemplateParameters.Count > 0)
{
_builder.Append($@"
{nestedIndentation}public __{lm.Name}Struct(");
{nestedIndentation}public __{lm.UniqueName}Struct(");
GenArguments(lm);
_builder.Append($@")
{nestedIndentation}{{");
@@ -166,7 +166,7 @@ private void GenStruct(LoggerMethod lm, string nestedIndentation)
{nestedIndentation}}}
");
_builder.Append($@"
{nestedIndentation}public static readonly global::System.Func<__{lm.Name}Struct, global::System.Exception?, string> Format = (state, ex) => state.ToString();
{nestedIndentation}public static readonly global::System.Func<__{lm.UniqueName}Struct, global::System.Exception?, string> Format = (state, ex) => state.ToString();
{nestedIndentation}public int Count => {lm.TemplateParameters.Count + 1};
@@ -343,7 +343,7 @@ private void GenArguments(LoggerMethod lm)

private void GenHolder(LoggerMethod lm)
{
string typeName = $"__{lm.Name}Struct";
string typeName = $"__{lm.UniqueName}Struct";

_builder.Append($"new {typeName}(");
foreach (LoggerParameter p in lm.TemplateParameters)
@@ -375,7 +375,7 @@ private void GenLogMethod(LoggerMethod lm, string nestedIndentation)

GenDefineTypes(lm, brackets: false);

_builder.Append($@"global::System.Exception?> __{lm.Name}Callback =
_builder.Append($@"global::System.Exception?> __{lm.UniqueName}Callback =
{nestedIndentation}global::Microsoft.Extensions.Logging.LoggerMessage.Define");

GenDefineTypes(lm, brackets: true);
@@ -404,7 +404,7 @@ private void GenLogMethod(LoggerMethod lm, string nestedIndentation)
if (UseLoggerMessageDefine(lm))
{
_builder.Append($@"
{nestedIndentation}{enabledCheckIndentation}__{lm.Name}Callback({logger}, ");
{nestedIndentation}{enabledCheckIndentation}__{lm.UniqueName}Callback({logger}, ");

GenCallbackArguments(lm);

@@ -420,7 +420,7 @@ private void GenLogMethod(LoggerMethod lm, string nestedIndentation)
GenHolder(lm);
_builder.Append($@",
{nestedIndentation}{enabledCheckIndentation}{exceptionArg},
{nestedIndentation}{enabledCheckIndentation}__{lm.Name}Struct.Format);");
{nestedIndentation}{enabledCheckIndentation}__{lm.UniqueName}Struct.Format);");
}

if (!lm.SkipEnabledCheck)
Original file line number Diff line number Diff line change
@@ -514,6 +514,23 @@ bool IsAllowedKind(SyntaxKind kind) =>

if (lc != null)
{
//once we've collected all methods for the given class, check for overloads
//and provide unique names for logger methods
var methods = new Dictionary<string, int>(lc.Methods.Count);
foreach (LoggerMethod lm in lc.Methods)
{
if (methods.ContainsKey(lm.Name))
{
int currentCount = methods[lm.Name];
lm.UniqueName = $"{lm.Name}{currentCount}";
methods[lm.Name] = currentCount + 1;
}
else
{
lm.UniqueName = lm.Name;
methods[lm.Name] = 1; //start from 1
}
}
results.Add(lc);
}
}
@@ -697,6 +714,7 @@ internal class LoggerMethod
public readonly Dictionary<string, string> TemplateMap = new(StringComparer.OrdinalIgnoreCase);
public readonly List<string> TemplateList = new();
public string Name = string.Empty;
public string UniqueName = string.Empty;
public string Message = string.Empty;
public int? Level;
public int EventId;
Original file line number Diff line number Diff line change
@@ -518,6 +518,26 @@ public void TemplateTests()

}

[Fact]
public void OverloadTests()
{
var logger = new MockLogger();

logger.Reset();
OverloadTestExtensions.M0(logger, 1);
Assert.Null(logger.LastException);
Assert.Equal($"{nameof(OverloadTestExtensions.M0)}1", logger.LastFormattedString);
Assert.Equal(LogLevel.Trace, logger.LastLogLevel);
Assert.Equal("M0", logger.LastEventId.Name);

logger.Reset();
OverloadTestExtensions.M0(logger, "string");
Assert.Null(logger.LastException);
Assert.Equal($"{nameof(OverloadTestExtensions.M0)}string", logger.LastFormattedString);
Assert.Equal(LogLevel.Trace, logger.LastLogLevel);
Assert.Equal("M0", logger.LastEventId.Name);
}

private static void AssertLastState(MockLogger logger, params KeyValuePair<string, object?>[] expected)
{
var rol = (IReadOnlyList<KeyValuePair<string, object?>>)logger.LastState!;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.Extensions.Logging.Generators.Tests.TestClasses
{
internal static partial class OverloadTestExtensions
{
[LoggerMessage(EventId = 0, Level = LogLevel.Trace, Message = "M0{p0}")]
public static partial void M0(ILogger logger, int p0);

[LoggerMessage(EventId = 1, Level = LogLevel.Trace, Message = "M0{p0}")]
public static partial void M0(ILogger logger, string p0);
}
}

0 comments on commit 2e35741

Please sign in to comment.