Skip to content

Logging Source Generator fails to compile using keyword parameters with @ prefixes depending on the placeholder order #95057

Open
@luiscantero

Description

@luiscantero

Description

The code below fails to compile depending on the order of the placeholders in the template. It only happens when a C# keyword with an @ prefix is included.

Reproduction Steps

private readonly ILogger _logger = new LoggerFactory().CreateLogger("SomeNamespace");

static void Main(string[] args) { }

[LoggerMessage(eventId: 1, LogLevel.Information, "Resource: {resource}. Namespace: {namespace}.")]
partial void LogEvent(string @namespace, string resource);

The above generates the following invalid code (see unescaped variable namespace):

public override string ToString()
{
    var resource = this._resource;
    var namespace = this.@namespace;

    return $"Resource: {resource}. Namespace: {namespace}.";
}

Expected behavior

The generator should generate valid escaped code to reference the c# keywords.

Actual behavior

Some of the warnings and errors include:

Warning	S3251: Supply an implementation for this partial method.
error CS0759: No defining declaration found for implementing declaration of partial method '<invalid-global-code>.LogEvent(string, string)'
error CS0751: A partial method must be declared within a partial type
error CS0116: A namespace cannot directly contain members such as fields, methods or statements
error CS0246: The type or namespace name 'namespace' could not be found (are you missing a using directive or an assembly reference?)
error CS0246: The type or namespace name '__LogEventStruct' could not be found (are you missing a using directive or an assembly reference?)
error CS0540: '<invalid-global-code>.IEnumerable.GetEnumerator()': containing type does not implement interface 'IEnumerable'
error CS0548: '<invalid-global-code>.this[namespace]': property or indexer must have at least one accessor
error CS0535: 'Program.__LogEventStruct' does not implement interface member 'IReadOnlyList<KeyValuePair<string, object?>>.this[int]'
error CS0535: 'Program.__LogEventStruct' does not implement interface member 'IReadOnlyCollection<KeyValuePair<string, object?>>.Count'
error CS0535: 'Program.__LogEventStruct' does not implement interface member 'IEnumerable<KeyValuePair<string, object?>>.GetEnumerator()'
error CS0535: 'Program.__LogEventStruct' does not implement interface member 'IEnumerable.GetEnumerator()'

Regression?

No response

Known Workarounds

The order of the placeholders should match the order of the parameters. The following compiles and works fine:

[LoggerMessage(eventId: 1, LogLevel.Information, "Namespace: {namespace}. Resource: {resource}.")]
partial void LogEvent(string @namespace, string resource);

If the placeholder for the C# keyword uses PascalCase as recommended by CA1727, it also works fine:

[LoggerMessage(eventId: 1, LogLevel.Information, "Resource: {resource}. Namespace: {Namespace}.")]
partial void LogEvent(string @namespace, string resource);

Configuration

Reproduced with:

  • .NET 7
  • Microsoft.Extensions.Logging 7.0.0 and 8.0.0
  • Microsoft.Extensions.Logging.Abstractions 7.0.0, 7.0.1 and 8.0.0

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions