Skip to content

Escape C# keyword identifiers in Configuration Binder source generator - #131453

Open
rosebyte wants to merge 3 commits into
dotnet:mainfrom
rosebyte:rosebyte-fix-config-binder-keyword-escape
Open

Escape C# keyword identifiers in Configuration Binder source generator#131453
rosebyte wants to merge 3 commits into
dotnet:mainfrom
rosebyte:rosebyte-fix-config-binder-keyword-escape

Conversation

@rosebyte

Copy link
Copy Markdown
Member

Fix Configuration Binder source generator emitting unescaped C# keywords as identifiers

The Configuration Binder source generator emitted constructor parameter and property names verbatim into identifier positions without escaping C# keywords. When a model had keyword-named parameters (e.g. @base, @event), the generated code would not compile.

Changes

  • Added an EscapeIdentifier helper (matching the pattern already used in the Options source generator) that prefixes identifiers with @ when they are C# keywords or contextual keywords.
  • Applied the escaping at all emission points where member names appear in code position in CoreBindingHelpers.cs.
  • Added a test verifying that models with keyword-named constructor parameters produce compilable generated code.

Files changed

  • src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs
  • src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/Helpers.cs
  • src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs

Fixes #130433

The Configuration Binder source generator emitted constructor parameter
names verbatim into identifier position without escaping C# keywords.
When a model had keyword-named parameters (e.g. @base, @event), the
generated code would not compile.

Add an EscapeIdentifier helper (matching the pattern already used in the
Options source generator) that prefixes identifiers with '@' when they
are C# keywords or contextual keywords. Apply it at all emission points
where member names appear in code position.

Fixes dotnet#130433

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-configuration
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes the Configuration Binder source generator so it emits valid C# when constructor parameters or members have names that are C# keywords (e.g., base, event) by escaping identifiers with @ where needed.

Changes:

  • Added an EscapeIdentifier helper to prefix C# keyword/contextual-keyword identifiers with @.
  • Updated CoreBindingHelpers emission sites to use escaped identifiers for locals and member access/initializers.
  • Added a regression test that validates generated code compiles for a model with keyword-named constructor parameters.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs Uses escaped identifiers when emitting locals and member access/initializers in generated binding code.
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/Helpers.cs Introduces EscapeIdentifier helper (Roslyn SyntaxFacts-based) for keyword/contextual-keyword detection.
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs Adds a compilation-based regression test covering keyword-named constructor parameters (and should ideally also cover keyword-named properties).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@svick svick left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@svick

svick commented Jul 28, 2026

Copy link
Copy Markdown
Member

It seems configuration key names also need escaping, e.g.: [ConfigurationKeyName("quoted\"key")] or [ConfigurationKeyName(@"path\key")] will currently result in invalid code.

@rosebyte Should I open an issue for that, or do you want to include that in this PR?

@mrek-msft

Copy link
Copy Markdown
Member

Also found out with copilot the same, here is demo. Remaining missing cases identified by Copilot CLI on my machine are non-senses.

IConfiguration configuration = new ConfigurationManager();
configuration["a\"b"] = "foo";
Options? o = configuration.Get<Options>();
Console.WriteLine(o?.Value);

public sealed class Options {
    [ConfigurationKeyName("a\"b")]
    public string Value { get; set; }
}

Work without source generator. Do not work with enabled.

Copilot AI review requested due to automatic review settings July 28, 2026 16:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs:11

  • using Microsoft.CodeAnalysis.CSharp; appears to be unused in this file (no SyntaxFacts/SyntaxKind references). This can trigger IDE0005 in builds that enforce unused-usings removal; please remove it.
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using SourceGenerators;

src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs:205

  • The PR description lists only the generator + generator-test files, but this PR also changes binder runtime tests (and adds coverage for configuration key string-literal escaping). Please update the PR description/file list (or split into a follow-up) so the scope matches what’s actually being changed.
        [Fact]
        public void CanBindConfigurationKeyNamesRequiringEscaping()
        {
            var dic = new Dictionary<string, string>

@rosebyte

Copy link
Copy Markdown
Member Author

@svick, @mrek-msft, I'd prefer to make another issue but it seems the change is only scoped to the one file so we might just mention it in PR description and perhaps the issue that we did escape this too, what do you think?

@tarekgh tarekgh added the source-generator Indicates an issue with a source generator feature label Jul 28, 2026
@tarekgh tarekgh added this to the 11.0.0 milestone Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-Extensions-Configuration source-generator Indicates an issue with a source generator feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Configuration.Binder source generator produces non-compiling code for properties named with C# keywords (@base, @event, etc.)

6 participants