Skip to content

[release/6.0-preview6] Support generating log methods in nested classes #54248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,6 @@ public static class DiagnosticDescriptors
DiagnosticSeverity.Error,
isEnabledByDefault: true);

public static DiagnosticDescriptor LoggingMethodInNestedType { get; } = new DiagnosticDescriptor(
id: "SYSLIB1004",
title: new LocalizableResourceString(nameof(SR.LoggingMethodInNestedTypeMessage), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Logging.Generators.SR)),
messageFormat: new LocalizableResourceString(nameof(SR.LoggingMethodInNestedTypeMessage), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Logging.Generators.SR)),
category: "LoggingGenerator",
DiagnosticSeverity.Error,
isEnabledByDefault: true);

public static DiagnosticDescriptor MissingRequiredType { get; } = new DiagnosticDescriptor(
id: "SYSLIB1005",
title: new LocalizableResourceString(nameof(SR.MissingRequiredTypeTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Logging.Generators.SR)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,29 +65,57 @@ private static bool UseLoggerMessageDefine(LoggerMethod lm)

private void GenType(LoggerClass lc)
{
string nestedIndentation = "";
if (!string.IsNullOrWhiteSpace(lc.Namespace))
{
_builder.Append($@"
namespace {lc.Namespace}
{{");
}

LoggerClass parent = lc.ParentClass;
var parentClasses = new List<string>();
// loop until you find top level nested class
while (parent != null)
{
parentClasses.Add($"partial {parent.Keyword} {parent.Name} {parent.Constraints}");
parent = parent.ParentClass;
}

// write down top level nested class first
for (int i = parentClasses.Count - 1; i >= 0; i--)
{
_builder.Append($@"
{nestedIndentation}{parentClasses[i]}
{nestedIndentation}{{");
nestedIndentation += " ";
}

_builder.Append($@"
partial class {lc.Name} {lc.Constraints}
{{");
{nestedIndentation}partial {lc.Keyword} {lc.Name} {lc.Constraints}
{nestedIndentation}{{");

foreach (LoggerMethod lm in lc.Methods)
{
if (!UseLoggerMessageDefine(lm))
{
GenStruct(lm);
GenStruct(lm, nestedIndentation);
}

GenLogMethod(lm);
GenLogMethod(lm, nestedIndentation);
}

_builder.Append($@"
}}");
{nestedIndentation}}}");

parent = lc.ParentClass;
while (parent != null)
{
nestedIndentation = new String(' ', nestedIndentation.Length - 4);
_builder.Append($@"
{nestedIndentation}}}");
parent = parent.ParentClass;
}

if (!string.IsNullOrWhiteSpace(lc.Namespace))
{
Expand All @@ -96,83 +124,83 @@ partial class {lc.Name} {lc.Constraints}
}
}

private void GenStruct(LoggerMethod lm)
private void GenStruct(LoggerMethod lm, string nestedIndentation)
{
_builder.AppendLine($@"
[{s_generatedCodeAttribute}]
private readonly struct __{lm.Name}Struct : global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.KeyValuePair<string, object?>>
{{");
GenFields(lm);
{nestedIndentation}[{s_generatedCodeAttribute}]
{nestedIndentation}private readonly struct __{lm.Name}Struct : global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.KeyValuePair<string, object?>>
{nestedIndentation}{{");
GenFields(lm, nestedIndentation);

if (lm.TemplateParameters.Count > 0)
{
_builder.Append($@"
public __{lm.Name}Struct(");
{nestedIndentation}public __{lm.Name}Struct(");
GenArguments(lm);
_builder.Append($@")
{{");
{nestedIndentation}{{");
_builder.AppendLine();
GenFieldAssignments(lm);
GenFieldAssignments(lm, nestedIndentation);
_builder.Append($@"
}}
{nestedIndentation}}}
");
}

_builder.Append($@"
public override string ToString()
{{
{nestedIndentation}public override string ToString()
{nestedIndentation}{{
");
GenVariableAssignments(lm);
GenVariableAssignments(lm, nestedIndentation);
_builder.Append($@"
return $""{lm.Message}"";
}}
{nestedIndentation}return $""{lm.Message}"";
{nestedIndentation}}}
");
_builder.Append($@"
public static string Format(__{lm.Name}Struct state, global::System.Exception? ex) => state.ToString();
{nestedIndentation}public static string Format(__{lm.Name}Struct state, global::System.Exception? ex) => state.ToString();

public int Count => {lm.TemplateParameters.Count + 1};
{nestedIndentation}public int Count => {lm.TemplateParameters.Count + 1};

public global::System.Collections.Generic.KeyValuePair<string, object?> this[int index]
{{
get => index switch
{{
{nestedIndentation}public global::System.Collections.Generic.KeyValuePair<string, object?> this[int index]
{nestedIndentation}{{
{nestedIndentation}get => index switch
{nestedIndentation}{{
");
GenCases(lm);
GenCases(lm, nestedIndentation);
_builder.Append($@"
_ => throw new global::System.IndexOutOfRangeException(nameof(index)), // return the same exception LoggerMessage.Define returns in this case
}};
{nestedIndentation}_ => throw new global::System.IndexOutOfRangeException(nameof(index)), // return the same exception LoggerMessage.Define returns in this case
{nestedIndentation}}};
}}

public global::System.Collections.Generic.IEnumerator<global::System.Collections.Generic.KeyValuePair<string, object?>> GetEnumerator()
{{
for (int i = 0; i < {lm.TemplateParameters.Count + 1}; i++)
{{
yield return this[i];
}}
}}
{nestedIndentation}public global::System.Collections.Generic.IEnumerator<global::System.Collections.Generic.KeyValuePair<string, object?>> GetEnumerator()
{nestedIndentation}{{
{nestedIndentation}for (int i = 0; i < {lm.TemplateParameters.Count + 1}; i++)
{nestedIndentation}{{
{nestedIndentation}yield return this[i];
{nestedIndentation}}}
{nestedIndentation}}}

global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
}}
{nestedIndentation}global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
{nestedIndentation}}}
");
}

private void GenFields(LoggerMethod lm)
private void GenFields(LoggerMethod lm, string nestedIndentation)
{
foreach (LoggerParameter p in lm.TemplateParameters)
{
_builder.AppendLine($" private readonly {p.Type} _{p.Name};");
_builder.AppendLine($" {nestedIndentation}private readonly {p.Type} _{p.Name};");
}
}

private void GenFieldAssignments(LoggerMethod lm)
private void GenFieldAssignments(LoggerMethod lm, string nestedIndentation)
{
foreach (LoggerParameter p in lm.TemplateParameters)
{
_builder.AppendLine($" this._{p.Name} = {p.Name};");
_builder.AppendLine($" {nestedIndentation}this._{p.Name} = {p.Name};");
}
}

private void GenVariableAssignments(LoggerMethod lm)
private void GenVariableAssignments(LoggerMethod lm, string nestedIndentation)
{
foreach (KeyValuePair<string, string> t in lm.TemplateMap)
{
Expand All @@ -192,20 +220,20 @@ private void GenVariableAssignments(LoggerMethod lm)
{
if (lm.TemplateParameters[index].IsEnumerable)
{
_builder.AppendLine($" var {t.Key} = "
_builder.AppendLine($" {nestedIndentation}var {t.Key} = "
+ $"global::__LoggerMessageGenerator.Enumerate((global::System.Collections.IEnumerable ?)this._{lm.TemplateParameters[index].Name});");

_needEnumerationHelper = true;
}
else
{
_builder.AppendLine($" var {t.Key} = this._{lm.TemplateParameters[index].Name};");
_builder.AppendLine($" {nestedIndentation}var {t.Key} = this._{lm.TemplateParameters[index].Name};");
}
}
}
}

private void GenCases(LoggerMethod lm)
private void GenCases(LoggerMethod lm, string nestedIndentation)
{
int index = 0;
foreach (LoggerParameter p in lm.TemplateParameters)
Expand All @@ -217,10 +245,10 @@ private void GenCases(LoggerMethod lm)
name = lm.TemplateMap[name];
}

_builder.AppendLine($" {index++} => new global::System.Collections.Generic.KeyValuePair<string, object?>(\"{name}\", this._{p.Name}),");
_builder.AppendLine($" {nestedIndentation}{index++} => new global::System.Collections.Generic.KeyValuePair<string, object?>(\"{name}\", this._{p.Name}),");
}

_builder.AppendLine($" {index++} => new global::System.Collections.Generic.KeyValuePair<string, object?>(\"{{OriginalFormat}}\", \"{ConvertEndOfLineAndQuotationCharactersToEscapeForm(lm.Message)}\"),");
_builder.AppendLine($" {nestedIndentation}{index++} => new global::System.Collections.Generic.KeyValuePair<string, object?>(\"{{OriginalFormat}}\", \"{ConvertEndOfLineAndQuotationCharactersToEscapeForm(lm.Message)}\"),");
}

private void GenCallbackArguments(LoggerMethod lm)
Expand Down Expand Up @@ -321,7 +349,7 @@ private void GenHolder(LoggerMethod lm)
_builder.Append(')');
}

private void GenLogMethod(LoggerMethod lm)
private void GenLogMethod(LoggerMethod lm, string nestedIndentation)
{
string level = GetLogLevel(lm);
string extension = lm.IsExtensionMethod ? "this " : string.Empty;
Expand All @@ -332,13 +360,13 @@ private void GenLogMethod(LoggerMethod lm)
if (UseLoggerMessageDefine(lm))
{
_builder.Append($@"
[{s_generatedCodeAttribute}]
private static readonly global::System.Action<global::Microsoft.Extensions.Logging.ILogger, ");
{nestedIndentation}[{s_generatedCodeAttribute}]
{nestedIndentation}private static readonly global::System.Action<global::Microsoft.Extensions.Logging.ILogger, ");

GenDefineTypes(lm, brackets: false);

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

GenDefineTypes(lm, brackets: true);

Expand All @@ -347,20 +375,20 @@ private void GenLogMethod(LoggerMethod lm)
}

_builder.Append($@"
[{s_generatedCodeAttribute}]
{lm.Modifiers} void {lm.Name}({extension}");
{nestedIndentation}[{s_generatedCodeAttribute}]
{nestedIndentation}{lm.Modifiers} void {lm.Name}({extension}");

GenParameters(lm);

_builder.Append($@")
{{
if ({logger}.IsEnabled({level}))
{{");
{nestedIndentation}{{
{nestedIndentation}if ({logger}.IsEnabled({level}))
{nestedIndentation}{{");

if (UseLoggerMessageDefine(lm))
{
_builder.Append($@"
__{lm.Name}Callback({logger}, ");
{nestedIndentation}__{lm.Name}Callback({logger}, ");

GenCallbackArguments(lm);

Expand All @@ -369,7 +397,7 @@ private void GenLogMethod(LoggerMethod lm)
else
{
_builder.Append($@"
{logger}.Log(
{nestedIndentation}{logger}.Log(
{level},
new global::Microsoft.Extensions.Logging.EventId({lm.EventId}, {eventName}),
");
Expand All @@ -380,8 +408,8 @@ private void GenLogMethod(LoggerMethod lm)
}

_builder.Append($@"
}}
}}");
{nestedIndentation}}}
{nestedIndentation}}}");

static string GetException(LoggerMethod lm)
{
Expand Down
Loading