Skip to content

Commit

Permalink
Support generating log methods in nested classes (#54180)
Browse files Browse the repository at this point in the history
  • Loading branch information
maryamariyan committed Jun 15, 2021
1 parent 03b1b38 commit d0ca735
Show file tree
Hide file tree
Showing 22 changed files with 302 additions and 154 deletions.
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

0 comments on commit d0ca735

Please sign in to comment.