// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using Microsoft.CodeAnalysis.Text;
+using System;
+using System.Text;
using System.Diagnostics;
+using Microsoft.CodeAnalysis.Text;
-namespace System.Text.Json.SourceGeneration
+namespace SourceGenerators
{
internal sealed class SourceWriter
{
+ private const char IndentationChar = ' ';
+ private const int CharsPerIndentation = 4;
+
private readonly StringBuilder _sb = new();
private int _indentation;
- public SourceWriter()
- {
- IndentationChar = ' ';
- CharsPerIndentation = 4;
- }
-
- public SourceWriter(char indentationChar, int charsPerIndentation)
- {
- if (!char.IsWhiteSpace(indentationChar))
- {
- throw new ArgumentOutOfRangeException(nameof(indentationChar));
- }
-
- if (charsPerIndentation < 1)
- {
- throw new ArgumentOutOfRangeException(nameof(charsPerIndentation));
- }
-
- IndentationChar = indentationChar;
- CharsPerIndentation = charsPerIndentation;
- }
-
- public char IndentationChar { get; }
- public int CharsPerIndentation { get; }
-
- public int Length => _sb.Length;
public int Indentation
{
get => _indentation;
return SourceText.From(_sb.ToString(), Encoding.UTF8);
}
+ public void Reset()
+ {
+ _sb.Clear();
+ _indentation = 0;
+ }
+
private void AddIndentation()
=> _sb.Append(IndentationChar, CharsPerIndentation * _indentation);
Link="Common\Interop\Linux\Interop.ProcFsStat.TryReadStatusFile.cs" />
<Compile Include="$(CommonPath)Interop\Linux\os-release\Interop.OSReleaseFile.cs"
Link="Common\Interop\Linux\os-release\Interop.OSReleaseFile.cs" />
+ <Compile Include="$(CommonPath)SourceGenerators\SourceWriter.cs"
+ Link="Common\SourceGenerators\SourceWriter.cs" />
<Compile Include="$(CommonPath)System\CharArrayHelpers.cs"
Link="Common\System\CharArrayHelpers.cs" />
<Compile Include="$(CommonPath)System\StringExtensions.cs"
<Compile Include="Tests\Interop\cgroupsTests.cs" />
<Compile Include="Tests\Interop\procfsTests.cs" />
<Compile Include="Tests\Interop\OSReleaseTests.cs" />
+ <Compile Include="Tests\SourceGenerators\SourceWriterTests.cs" />
<Compile Include="Tests\System\IO\PathInternal.Tests.cs" />
<Compile Include="Tests\System\IO\StringParserTests.cs" />
<Compile Include="Tests\System\Net\HttpDateParserTests.cs" />
<Folder Include="System\Net\VirtualNetwork\" />
</ItemGroup>
<ItemGroup>
+ <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="$(MicrosoftCodeAnalysisVersion_LatestVS)" PrivateAssets="all" />
+ </ItemGroup>
+ <ItemGroup>
<ProjectReference Include="$(CommonTestPath)StreamConformanceTests\StreamConformanceTests.csproj" />
</ItemGroup>
</Project>
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using SourceGenerators;
+using Xunit;
+
+namespace Common.Tests
+{
+ public sealed class SourceWriterTests
+ {
+ [Fact]
+ public void CanHandleVariousLineEndings()
+ {
+ string testTemplate = "public static void Main(){0}{{{1}\tConsole.WriteLine(\"Hello, world\");{2}}}";
+ SourceWriter writer = new();
+
+ CheckCanWrite(string.Format(testTemplate, "\n", "\n", "\n"));
+ CheckCanWrite(string.Format(testTemplate, "\r\n", "\r\n", "\r\n"));
+ CheckCanWrite(string.Format(testTemplate, "\n", "\r\n", "\n"));
+
+ // Regression test for https://github.com/dotnet/runtime/issues/88918.
+ CheckCanWrite(" global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services);\r\n global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));\r\n return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));\r\n}");
+
+ void CheckCanWrite(string source)
+ {
+ // No exception expected.
+ writer.WriteLine(source);
+ writer.Reset();
+ }
+ }
+ }
+}
using System.Diagnostics;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
+using SourceGenerators;
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
return;
}
- _writer.WriteBlock("""
+ _writer.WriteLine("""
// <auto-generated/>
#nullable enable
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
""");
- _writer.WriteBlankLine();
+ _writer.WriteLine();
_useFullyQualifiedNames = true;
- EmitBinder_ConfigurationBinder();
+ EmitBinder_Extensions_IConfiguration();
EmitBinder_Extensions_OptionsBuilder();
- EmitBinder_Extensions_ServiceCollection();
+ EmitBinder_Extensions_IServiceCollection();
_useFullyQualifiedNames = false;
Emit_CoreBindingHelper();
if (!checkForNullSectionValue)
{
- writeOnSuccess?.Invoke(parsedValueExpr);
+ InvokeWriteOnSuccess();
}
else
{
- _writer.WriteBlockStart($"if ({sectionValueExpr} is string {nonNull_StringValue_Identifier})");
- writeOnSuccess?.Invoke(parsedValueExpr);
- _writer.WriteBlockEnd();
+ EmitStartBlock($"if ({sectionValueExpr} is string {nonNull_StringValue_Identifier})");
+ InvokeWriteOnSuccess();
+ EmitEndBlock();
}
+
+ void InvokeWriteOnSuccess() => writeOnSuccess?.Invoke(parsedValueExpr);
}
private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, InitializationKind initKind, string configArgExpr)
exceptionTypeDisplayString = nameof(InvalidOperationException);
}
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
if ({{Identifier.configuration}} is not {{sectionTypeDisplayString}} {{Identifier.section}})
{
throw new {{exceptionTypeDisplayString}}();
string returnPostfix = voidReturn ? string.Empty : " null";
string methodDisplayString = GetHelperMethodDisplayString(Identifier.HasValueOrChildren);
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
if (!{{methodDisplayString}}({{Identifier.configuration}}))
{
return{{returnPostfix}};
}
""");
- _writer.WriteBlankLine();
+ _writer.WriteLine();
}
}
}
{
private bool ShouldEmitMethods(MethodsToGen_ConfigurationBinder methods) => (_sourceGenSpec.MethodsToGen_ConfigurationBinder & methods) != 0;
- private void EmitBinder_ConfigurationBinder()
+ private void EmitBinder_Extensions_IConfiguration()
{
Debug.Assert(_sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods.Count <= 3 &&
!_sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods.Keys.Any(overload => (overload & MethodsToGen_ConfigurationBinder.Bind) is 0));
}
_emitBlankLineBeforeNextStatement = false;
- EmitRootBindingClassBlockStart(Identifier.GeneratedConfigurationBinder);
+ EmitRootBindingClassStartBlock(Identifier.GeneratedConfigurationBinder);
EmitGetMethods();
EmitGetValueMethods();
EmitBindMethods_ConfigurationBinder();
- _writer.WriteBlockEnd();
+ EmitEndBlock();
_emitBlankLineBeforeNextStatement = true;
}
private void Emit_CoreBindingHelper()
{
Debug.Assert(_emitBlankLineBeforeNextStatement);
- _writer.WriteBlankLine();
+ _writer.WriteLine();
_emitBlankLineBeforeNextStatement = false;
- _writer.WriteBlockStart($"namespace {ProjectName}");
+ EmitStartBlock($"namespace {ProjectName}");
EmitHelperUsingStatements();
- _writer.WriteBlankLine();
+ _writer.WriteLine();
- _writer.WriteBlock($$"""
+ EmitStartBlock($$"""
/// <summary>Provide core binding logic.</summary>
{{GetGeneratedCodeAttributeSrc()}}
file static class {{Identifier.CoreBindingHelper}}
- {
""");
EmitConfigurationKeyCaches();
EmitInitializeMethods();
EmitHelperMethods();
- _writer.WriteBlockEnd(); // End helper class.
- _writer.WriteBlockEnd(); // End namespace.
+ EmitEndBlock(); // End helper class.
+ EmitEndBlock(); // End namespace.
}
private void EmitHelperUsingStatements()
}
EmitBlankLineIfRequired();
- _writer.WriteBlockStart($"public static object? {nameof(MethodsToGen_CoreBindingHelper.GetCore)}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, Action<{Identifier.BinderOptions}>? {Identifier.configureOptions})");
+ EmitStartBlock($"public static object? {nameof(MethodsToGen_CoreBindingHelper.GetCore)}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, Action<{Identifier.BinderOptions}>? {Identifier.configureOptions})");
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
_writer.WriteLine($"{Identifier.BinderOptions}? {Identifier.binderOptions} = {Identifier.GetBinderOptions}({Identifier.configureOptions});");
- _writer.WriteBlankLine();
+ _writer.WriteLine();
EmitIConfigurationHasValueOrChildrenCheck(voidReturn: false);
{
TypeSpecKind kind = type.SpecKind;
- _writer.WriteBlockStart($"if (type == typeof({type.MinimalDisplayString}))");
+ EmitStartBlock($"if (type == typeof({type.MinimalDisplayString}))");
if (type is ParsableFromStringSpec stringParsableType)
{
_writer.WriteLine($"return {Identifier.obj};");
}
- _writer.WriteBlockEnd();
- _writer.WriteBlankLine();
+ EmitEndBlock();
+ _writer.WriteLine();
}
Emit_NotSupportedException_TypeNotDetectedAsInput();
- _writer.WriteBlockEnd();
+ EmitEndBlock();
_emitBlankLineBeforeNextStatement = true;
}
}
EmitBlankLineIfRequired();
- _writer.WriteBlockStart($"public static object? {nameof(MethodsToGen_CoreBindingHelper.GetValueCore)}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key})");
+ EmitStartBlock($"public static object? {nameof(MethodsToGen_CoreBindingHelper.GetValueCore)}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key})");
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
_writer.WriteLine($@"{Identifier.IConfigurationSection} {Identifier.section} = {GetSectionFromConfigurationExpression(Identifier.key, addQuotes: false)};");
- _writer.WriteBlankLine();
+ _writer.WriteLine();
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
if ({{Expression.sectionValue}} is not string {{Identifier.value}})
{
return null;
}
""");
- _writer.WriteBlankLine();
+ _writer.WriteLine();
foreach (TypeSpec type in targetTypes)
{
- _writer.WriteBlockStart($"if ({Identifier.type} == typeof({type.MinimalDisplayString}))");
+ EmitStartBlock($"if ({Identifier.type} == typeof({type.MinimalDisplayString}))");
EmitBindLogicFromString(
(ParsableFromStringSpec)type.EffectiveType,
checkForNullSectionValue: false,
useIncrementalStringValueIdentifier: false);
- _writer.WriteBlockEnd();
- _writer.WriteBlankLine();
+ EmitEndBlock();
+ _writer.WriteLine();
}
_writer.WriteLine("return null;");
- _writer.WriteBlockEnd();
+ EmitEndBlock();
_emitBlankLineBeforeNextStatement = true;
}
EmitBlankLineIfRequired();
- _writer.WriteBlockStart($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)}(this {Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.obj}, Type {Identifier.type}, {MinimalDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})");
+ EmitStartBlock($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)}(this {Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.obj}, Type {Identifier.type}, {MinimalDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})");
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
_writer.WriteLine($"{Identifier.BinderOptions}? {Identifier.binderOptions} = {Identifier.GetBinderOptions}({Identifier.configureOptions});");
- _writer.WriteBlankLine();
+ _writer.WriteLine();
EmitIConfigurationHasValueOrChildrenCheck(voidReturn: true);
foreach (TypeSpec type in targetTypes)
{
- _writer.WriteBlockStart($"if (type == typeof({type.MinimalDisplayString}))");
+ EmitStartBlock($"if (type == typeof({type.MinimalDisplayString}))");
TypeSpec effectiveType = type.EffectiveType;
if (!EmitInitException(effectiveType))
_writer.WriteLine($"return;");
}
- _writer.WriteBlockEnd();
- _writer.WriteBlankLine();
+ EmitEndBlock();
+ _writer.WriteLine();
}
Emit_NotSupportedException_TypeNotDetectedAsInput();
- _writer.WriteBlockEnd();
+ EmitEndBlock();
_emitBlankLineBeforeNextStatement = true;
}
Debug.Assert(type.CanInitialize);
string objParameterExpression = $"ref {type.MinimalDisplayString} {Identifier.obj}";
- _writer.WriteBlockStart(@$"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCore)}({Identifier.IConfiguration} {Identifier.configuration}, {objParameterExpression}, {Identifier.BinderOptions}? {Identifier.binderOptions})");
+ EmitStartBlock(@$"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCore)}({Identifier.IConfiguration} {Identifier.configuration}, {objParameterExpression}, {Identifier.BinderOptions}? {Identifier.binderOptions})");
EmitCheckForNullArgument_WithBlankLine_IfRequired(type.IsValueType);
EmitBindCoreImplForObject((ObjectSpec)effectiveType);
}
- _writer.WriteBlockEnd();
+ EmitEndBlock();
}
private void EmitInitializeMethods()
List<string> ctorArgList = new();
string displayString = type.MinimalDisplayString;
- _writer.WriteBlockStart($"public static {type.MinimalDisplayString} {GetInitalizeMethodDisplayString(type)}({Identifier.IConfiguration} {Identifier.configuration}, {Identifier.BinderOptions}? {Identifier.binderOptions})");
+ EmitStartBlock($"public static {type.MinimalDisplayString} {GetInitalizeMethodDisplayString(type)}({Identifier.IConfiguration} {Identifier.configuration}, {Identifier.BinderOptions}? {Identifier.binderOptions})");
_emitBlankLineBeforeNextStatement = false;
foreach (ParameterSpec parameter in ctorParams)
}
else
{
- _writer.WriteBlockStart(returnExpression);
+ EmitStartBlock(returnExpression);
foreach (PropertySpec property in initOnlyProps)
{
string propertyName = property.Name;
_writer.WriteLine($@"{propertyName} = {propertyName},");
}
- _writer.WriteBlockEnd(";");
+ EmitEndBlock(endBraceTrailingSource: ";");
}
// End method.
- _writer.WriteBlockEnd();
+ EmitEndBlock();
_emitBlankLineBeforeNextStatement = true;
void EmitBindImplForMember(MemberSpec member)
{
string condition = $@" if ({Identifier.configuration}[""{member.ConfigurationKeyName}""] is not {memberType.MinimalDisplayString} {member.Name})";
EmitThrowBlock(condition);
- _writer.WriteBlankLine();
+ _writer.WriteLine();
return;
}
}
EmitThrowBlock(condition: "else");
}
- _writer.WriteBlankLine();
+ _writer.WriteLine();
}
void EmitThrowBlock(string condition) =>
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
{{condition}}
{
throw new {{GetInvalidOperationDisplayName()}}("{{string.Format(ExceptionMessages.ParameterHasNoMatchingConfig, type.Name, member.Name)}}");
""");
}
}
-
private void EmitHelperMethods()
{
if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCore))
if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreUntyped | MethodsToGen_CoreBindingHelper.GetCore))
{
- _writer.WriteBlankLine();
+ _writer.WriteLine();
EmitHasValueOrChildrenMethod();
- _writer.WriteBlankLine();
+ _writer.WriteLine();
EmitAsConfigWithChildrenMethod();
_emitBlankLineBeforeNextStatement = true;
}
else if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.AsConfigWithChildren))
{
- _writer.WriteBlankLine();
+ _writer.WriteLine();
EmitAsConfigWithChildrenMethod();
_emitBlankLineBeforeNextStatement = true;
}
MethodsToGen_CoreBindingHelper.BindCoreUntyped | MethodsToGen_CoreBindingHelper.GetCore) ||
ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions))
{
- _writer.WriteBlankLine();
+ _writer.WriteLine();
EmitGetBinderOptionsHelper();
_emitBlankLineBeforeNextStatement = true;
}
string exceptionMessage = string.Format(ExceptionMessages.MissingConfig, Identifier.ErrorOnUnknownConfiguration, Identifier.BinderOptions, $"{{{Identifier.type}}}", $@"{{string.Join("", "", {Identifier.temp})}}");
EmitBlankLineIfRequired();
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
public static void {{Identifier.ValidateConfigurationKeys}}(Type {{Identifier.type}}, {{MinimalDisplayString.LazyHashSetOfString}} {{keysIdentifier}}, {{Identifier.IConfiguration}} {{Identifier.configuration}}, {{Identifier.BinderOptions}}? {{Identifier.binderOptions}})
{
private void EmitHasValueOrChildrenMethod()
{
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
public static bool {{Identifier.HasValueOrChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}})
{
if (({{Identifier.configuration}} as {{Identifier.IConfigurationSection}})?.{{Identifier.Value}} is not null)
private void EmitAsConfigWithChildrenMethod()
{
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
public static {{Identifier.IConfiguration}}? {{Identifier.AsConfigWithChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}})
{
foreach ({{Identifier.IConfigurationSection}} _ in {{Identifier.configuration}}.{{Identifier.GetChildren}}())
private void EmitGetBinderOptionsHelper()
{
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
public static {{Identifier.BinderOptions}}? {{Identifier.GetBinderOptions}}({{MinimalDisplayString.NullableActionOfBinderOptions}} {{Identifier.configureOptions}})
{
if ({{Identifier.configureOptions}} is null)
}
}
- _writer.WriteBlock($$"""
- public static {{typeDisplayString}} {{type.ParseMethodName}}(string {{Identifier.value}}, Func<string?> {{Identifier.getPath}})
- {
- try
- {
- return {{parsedValueExpr}};
- """);
-
string exceptionArg1 = string.Format(ExceptionMessages.FailedBinding, $"{{{Identifier.getPath}()}}", $"{{typeof({typeDisplayString})}}");
- _writer.WriteBlock($$"""
- }
- catch ({{innerExceptionTypeDisplayString}} {{Identifier.exception}})
- {
- throw new {{GetInvalidOperationDisplayName()}}($"{{exceptionArg1}}", {{Identifier.exception}});
- }
+ EmitStartBlock($"public static {typeDisplayString} {type.ParseMethodName}(string {Identifier.value}, Func<string?> {Identifier.getPath})");
+ EmitEndBlock($$"""
+ try
+ {
+ return {{parsedValueExpr}};
+ }
+ catch ({{innerExceptionTypeDisplayString}} {{Identifier.exception}})
+ {
+ throw new {{GetInvalidOperationDisplayName()}}($"{{exceptionArg1}}", {{Identifier.exception}});
}
""");
}
EmitBindCoreCall(concreteType, tempIdentifier, Identifier.configuration, InitializationKind.Declaration);
// Resize array and add binded elements.
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
{{Identifier.Int32}} {{Identifier.originalCount}} = {{Identifier.obj}}.{{Identifier.Length}};
{{Identifier.Array}}.{{Identifier.Resize}}(ref {{Identifier.obj}}, {{Identifier.originalCount}} + {{tempIdentifier}}.{{Identifier.Count}});
{{tempIdentifier}}.{{Identifier.CopyTo}}({{Identifier.obj}}, {{Identifier.originalCount}});
{
EmitCollectionCastIfRequired(type, out string objIdentifier);
- Emit_Foreach_Section_In_ConfigChildren_BlockHeader();
+ Emit_Foreach_Section_In_ConfigChildren_StartBlock();
TypeSpec elementType = type.ElementType;
_writer.WriteLine($"{objIdentifier}.{Identifier.Add}({Identifier.value});");
}
- _writer.WriteBlockEnd();
+ EmitEndBlock();
}
private void EmitBindCoreImplForDictionary(DictionarySpec type)
{
EmitCollectionCastIfRequired(type, out string objIdentifier);
- Emit_Foreach_Section_In_ConfigChildren_BlockHeader();
+ Emit_Foreach_Section_In_ConfigChildren_StartBlock();
ParsableFromStringSpec keyType = type.KeyType;
TypeSpec elementType = type.ElementType;
conditionToUseExistingElement += $" && {expressionForElementIsNotNull}";
}
- _writer.WriteBlockStart($"if (!({conditionToUseExistingElement}))");
+ EmitStartBlock($"if (!({conditionToUseExistingElement}))");
EmitObjectInit(elementType, Identifier.element, InitializationKind.SimpleAssignment, Identifier.section);
- _writer.WriteBlockEnd();
+ EmitEndBlock();
if (elementType is CollectionSpec { InitializationStrategy: InitializationStrategy.ParameterizedConstructor or InitializationStrategy.ToEnumerableMethod } collectionSpec)
{
? $"new {collectionSpec.ConcreteType.MinimalDisplayString}({Identifier.element})"
: $"{Identifier.element}.{collectionSpec.ToEnumerableMethodCall!}";
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
else
{
{{Identifier.element}} = {{initExpression}};
EmitBindCoreCall(elementType, Identifier.element, Identifier.section, InitializationKind.None);
_writer.WriteLine($"{objIdentifier}[{parsedKeyExpr}] = {Identifier.element};");
}
-
}
- _writer.WriteBlockEnd();
+ EmitEndBlock();
}
private void EmitBindCoreImplForObject(ObjectSpec type)
return true;
}
- string sectionParseExpr = $"{GetSectionFromConfigurationExpression(member.ConfigurationKeyName)}";
+ string sectionParseExpr = GetSectionFromConfigurationExpression(member.ConfigurationKeyName);
EmitBlankLineIfRequired();
string sectionValidationCall = $"{Identifier.AsConfigWithChildren}({sectionParseExpr})";
string sectionIdentifier = GetIncrementalIdentifier(Identifier.section);
- _writer.WriteBlockStart($"if ({sectionValidationCall} is {Identifier.IConfigurationSection} {sectionIdentifier})");
+ EmitStartBlock($"if ({sectionValidationCall} is {Identifier.IConfigurationSection} {sectionIdentifier})");
bool success = !EmitInitException(effectiveMemberType);
if (success)
EmitBindCoreCallForMember(member, memberAccessExpr, sectionIdentifier, canSet);
}
- _writer.WriteBlockEnd();
+ EmitEndBlock();
return success;
}
if (type.PopulationStrategy is CollectionPopulationStrategy.Cast_Then_Add)
{
objIdentifier = Identifier.temp;
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
if ({{Identifier.obj}} is not {{type.PopulationCastType!.MinimalDisplayString}} {{objIdentifier}})
{
return;
}
""");
- _writer.WriteBlankLine();
+ _writer.WriteLine();
}
}
- private void Emit_Foreach_Section_In_ConfigChildren_BlockHeader() =>
- _writer.WriteBlockStart($"foreach ({Identifier.IConfigurationSection} {Identifier.section} in {Identifier.configuration}.{Identifier.GetChildren}())");
+ private void Emit_Foreach_Section_In_ConfigChildren_StartBlock() =>
+ EmitStartBlock($"foreach ({Identifier.IConfigurationSection} {Identifier.section} in {Identifier.configuration}.{Identifier.GetChildren}())");
private static string GetSectionPathFromConfigurationExpression(string configurationKeyName)
=> $@"{GetSectionFromConfigurationExpression(configurationKeyName)}.{Identifier.Path}";
ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Any) ||
ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any);
+ /// <summary>
+ /// Starts a block of source code.
+ /// </summary>
+ /// <param name="source">Source to write after the open brace.</param>
+ public void EmitStartBlock(string? source = null)
+ {
+ if (source is not null)
+ {
+ _writer.WriteLine(source);
+ }
+
+ _writer.WriteLine("{");
+ _writer.Indentation++;
+ }
+
+ /// <summary>
+ /// Ends a block of source code.
+ /// </summary>
+ /// <param name="source">Source to write before the close brace.</param>
+ /// <param name="endBraceTrailingSource">Trailing source after the end brace, e.g. ";" to end an init statement.</param>
+ public void EmitEndBlock(string? source = null, string? endBraceTrailingSource = null)
+ {
+ if (source is not null)
+ {
+ _writer.WriteLine(source);
+ }
+
+ string endBlockSource = endBraceTrailingSource is null ? "}" : $"}}{endBraceTrailingSource}";
+ _writer.Indentation--;
+ _writer.WriteLine(endBlockSource);
+ }
+
private void EmitBlankLineIfRequired()
{
if (_emitBlankLineBeforeNextStatement)
{
- _writer.WriteBlankLine();
+ _writer.WriteLine();
}
_emitBlankLineBeforeNextStatement = true;
? "global::System.ArgumentNullException"
: "ArgumentNullException";
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
if ({{paramName}} is null)
{
throw new {{exceptionTypeDisplayString}}(nameof({{paramName}}));
}
""");
- _writer.WriteBlankLine();
+ _writer.WriteLine();
}
private bool EmitInitException(TypeSpec type)
return false;
}
- private void EmitRootBindingClassBlockStart(string className)
+ private void EmitRootBindingClassStartBlock(string className)
{
EmitBlankLineIfRequired();
- _writer.WriteBlock($$"""
+ EmitStartBlock($$"""
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
{{GetGeneratedCodeAttributeSrc()}}
internal static class {{className}}
- {
""");
_emitBlankLineBeforeNextStatement = false;
return;
}
- EmitRootBindingClassBlockStart(Identifier.GeneratedOptionsBuilderBinder);
+ EmitRootBindingClassStartBlock(Identifier.GeneratedOptionsBuilderBinder);
EmitBindMethods_Extensions_OptionsBuilder();
EmitBindConfigurationMethod();
- _writer.WriteBlockEnd();
+ EmitEndBlock();
}
private void EmitBindMethods_Extensions_OptionsBuilder()
if (ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Bind_T))
{
- EmitMethodBlockStart("Bind", paramList, documentation);
+ EmitMethodStartBlock("Bind", paramList, documentation);
_writer.WriteLine($"return global::{Identifier.GeneratedOptionsBuilderBinder}.Bind({Identifier.optionsBuilder}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
- _writer.WriteBlockEnd();
+ EmitEndBlock();
}
- EmitMethodBlockStart(
+ EmitMethodStartBlock(
"Bind",
paramList + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}",
documentation);
EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder);
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
global::{{Identifier.GeneratedServiceCollectionBinder}}.{{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.configuration}}, {{Identifier.configureOptions}});
return {{Identifier.optionsBuilder}};
""");
- _writer.WriteBlockEnd();
+ EmitEndBlock();
}
private void EmitBindConfigurationMethod()
const string documentation = $@"/// <summary>Registers the dependency injection container to bind <typeparamref name=""TOptions""/> against the <see cref=""{FullyQualifiedDisplayString.IConfiguration}""/> obtained from the DI service provider.</summary>";
string paramList = $"string {Identifier.configSectionPath}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions} = null";
- EmitMethodBlockStart("BindConfiguration", paramList, documentation);
+ EmitMethodStartBlock("BindConfiguration", paramList, documentation);
EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder);
EmitCheckForNullArgument_WithBlankLine(Identifier.configSectionPath);
- _writer.WriteBlockStart($"{Identifier.optionsBuilder}.{Identifier.Configure}<{FullyQualifiedDisplayString.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>");
+ EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{FullyQualifiedDisplayString.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>");
- _writer.WriteBlock($$"""
- {{FullyQualifiedDisplayString.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, global::System.StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}});
- {{FullyQualifiedDisplayString.CoreBindingHelper}}.{{nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}});
- """);
+ _writer.WriteLine($$"""
+ {{FullyQualifiedDisplayString.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, global::System.StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}});
+ {{FullyQualifiedDisplayString.CoreBindingHelper}}.{{nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}});
+ """);
- _writer.WriteBlockEnd(");");
+ EmitEndBlock(endBraceTrailingSource: ");");
- _writer.WriteBlankLine();
+ _writer.WriteLine();
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
{{FullyQualifiedDisplayString.AddSingleton}}<{{FullyQualifiedDisplayString.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>, {{FullyQualifiedDisplayString.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>>({{Identifier.optionsBuilder}}.{{Identifier.Services}});
return {{Identifier.optionsBuilder}};
""");
- _writer.WriteBlockEnd();
+ EmitEndBlock();
}
- private void EmitMethodBlockStart(string methodName, string paramList, string documentation)
+ private void EmitMethodStartBlock(string methodName, string paramList, string documentation)
{
paramList = $"this {FullyQualifiedDisplayString.OptionsBuilderOfTOptions} {Identifier.optionsBuilder}, {paramList}";
EmitBlankLineIfRequired();
_writer.WriteLine(documentation);
- _writer.WriteBlockStart($"public static {FullyQualifiedDisplayString.OptionsBuilderOfTOptions} {methodName}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class");
+ EmitStartBlock($"public static {FullyQualifiedDisplayString.OptionsBuilderOfTOptions} {methodName}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class");
}
}
}
{
private bool ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection methods) => (_sourceGenSpec.MethodsToGen_ServiceCollectionExt & methods) != 0;
- private void EmitBinder_Extensions_ServiceCollection()
+ private void EmitBinder_Extensions_IServiceCollection()
{
if (!ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any))
{
return;
}
- EmitRootBindingClassBlockStart(Identifier.GeneratedServiceCollectionBinder);
+ EmitRootBindingClassStartBlock(Identifier.GeneratedServiceCollectionBinder);
const string defaultNameExpr = "string.Empty";
const string configureMethodString = $"global::{Identifier.GeneratedServiceCollectionBinder}.{Identifier.Configure}";
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T))
{
- EmitBlockStart(configParam);
+ EmitStartMethod(configParam);
_writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
- _writer.WriteBlockEnd();
+ EmitEndBlock();
}
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_name))
{
- EmitBlockStart(
+ EmitStartMethod(
paramList: $"string? {Identifier.name}, " + configParam);
_writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {Identifier.name}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
- _writer.WriteBlockEnd();
+ EmitEndBlock();
}
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions))
{
- EmitBlockStart(
+ EmitStartMethod(
paramList: configParam + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}");
_writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions});");
- _writer.WriteBlockEnd();
+ EmitEndBlock();
}
+ // Core Configure method that the other overloads call.
+ // Like the others, it is public API that could be called directly by users.
+ // So, it is always generated whenever a Configure overload is called.
string optionsNamespaceName = "global::Microsoft.Extensions.Options";
string bindCoreUntypedDisplayString = GetHelperMethodDisplayString(nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped));
- EmitBlockStart(paramList: $"string? {Identifier.name}, " + configParam + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}");
-
+ EmitStartMethod(paramList: $"string? {Identifier.name}, " + configParam + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}");
EmitCheckForNullArgument_WithBlankLine(Identifier.services);
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
-
- _writer.WriteBlock($$"""
+ _writer.WriteLine($$"""
global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}});
{{FullyQualifiedDisplayString.AddSingleton}}<{{FullyQualifiedDisplayString.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>({{Identifier.services}}, new {{FullyQualifiedDisplayString.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.configuration}}));
return {{FullyQualifiedDisplayString.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>({{Identifier.services}}, new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{bindCoreUntypedDisplayString}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}})));
- }
- """);
+ """);
+ EmitEndBlock();
- _writer.WriteBlockEnd();
+ EmitEndBlock();
_emitBlankLineBeforeNextStatement = true;
}
- private void EmitBlockStart(string paramList)
+ private void EmitStartMethod(string paramList)
{
paramList = $"this {FullyQualifiedDisplayString.IServiceCollection} {Identifier.services}, {paramList}";
EmitBlankLineIfRequired();
- _writer.WriteBlock($$"""
- /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
- public static {{FullyQualifiedDisplayString.IServiceCollection}} {{Identifier.Configure}}<{{Identifier.TOptions}}>({{paramList}}) where {{Identifier.TOptions}} : class
- {
- """);
+ EmitStartBlock($$"""
+ /// <summary>Registers a configuration instance which TOptions will bind against.</summary>
+ public static {{FullyQualifiedDisplayString.IServiceCollection}} {{Identifier.Configure}}<{{Identifier.TOptions}}>({{paramList}}) where {{Identifier.TOptions}} : class
+ """);
}
}
}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.Diagnostics;
-using System.Text;
-using Microsoft.CodeAnalysis.Text;
-
-namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
-{
- internal sealed class SourceWriter
- {
- private readonly StringBuilder _sb = new();
- private static readonly char[] s_newLine = Environment.NewLine.ToCharArray();
- private int _indentation;
-
- public void WriteBlockStart(string? declaration = null)
- {
- if (declaration is not null)
- {
- WriteLine(declaration);
- }
- WriteLine("{");
- _indentation++;
- }
-
- public void WriteBlockEnd(string? extra = null)
- {
- _indentation--;
- Debug.Assert(_indentation > -1);
- WriteLine($"}}{extra}");
- }
-
- public void WriteLine(string source)
- {
- _sb.Append(' ', 4 * _indentation);
- _sb.AppendLine(source);
- }
-
- public void WriteBlock(string source)
- {
- bool isFinalLine;
- ReadOnlySpan<char> remainingText = source.AsSpan();
-
- do
- {
- ReadOnlySpan<char> line = GetNextLine(ref remainingText, out isFinalLine);
- switch (line)
- {
- case "{":
- {
- WriteBlockStart();
- }
- break;
- case "}":
- {
- WriteBlockEnd();
- }
- break;
- default:
- {
- WriteLine(line);
- }
- break;
- }
- } while (!isFinalLine);
- }
-
- public void WriteBlankLine() => _sb.AppendLine();
-
- public SourceText ToSourceText()
- {
- Debug.Assert(_indentation == 0 && _sb.Length > 0);
- return SourceText.From(_sb.ToString(), Encoding.UTF8);
- }
-
- private static ReadOnlySpan<char> GetNextLine(ref ReadOnlySpan<char> remainingText, out bool isFinalLine)
- {
- if (remainingText.IsEmpty)
- {
- isFinalLine = true;
- return default;
- }
-
- ReadOnlySpan<char> next;
- ReadOnlySpan<char> rest;
-
- remainingText = remainingText.Trim();
-
- int lineLength = remainingText.IndexOf(s_newLine);
- if (lineLength == -1)
- {
- lineLength = remainingText.Length;
- isFinalLine = true;
- rest = default;
- }
- else
- {
- rest = remainingText.Slice(lineLength + 1);
- isFinalLine = false;
- }
-
- next = remainingText.Slice(0, lineLength);
- remainingText = rest;
- return next;
- }
-
- private unsafe void WriteLine(ReadOnlySpan<char> source)
- {
- _sb.Append(' ', 4 * _indentation);
- fixed (char* ptr = source)
- {
- _sb.Append(ptr, source.Length);
- WriteBlankLine();
- }
- }
- }
-}
<Compile Include="$(CoreLibSharedDir)System\Collections\Generic\ValueListBuilder.cs" Link="Production\ValueListBuilder.cs" />
<Compile Include="$(CoreLibSharedDir)System\Collections\Generic\ValueListBuilder.Pop.cs" Link="Production\ValueListBuilder.Pop.cs" />
<Compile Include="$(CommonPath)\Roslyn\GetBestTypeByMetadataName.cs" Link="Common\Roslyn\GetBestTypeByMetadataName.cs" />
+ <Compile Include="$(CommonPath)\SourceGenerators\SourceWriter.cs" Link="Common\SourceGenerators\SourceWriter.cs" />
<Compile Include="ConfigurationBindingGenerator.cs" />
<Compile Include="ConfigurationBindingGenerator.Emitter.cs" />
<Compile Include="ConfigurationBindingGenerator.Parser.cs" />
<Compile Include="Helpers\Parser\Diagnostics.cs" />
<Compile Include="Helpers\Parser\OptionsBuilderConfigurationExtensions.cs" />
<Compile Include="Helpers\Parser\OptionsConfigurationServiceCollectionExtensions.cs" />
- <Compile Include="Helpers\SourceWriter.cs" />
<Compile Include="Model\CollectionSpec.cs" />
<Compile Include="Model\ConfigurationSectionSpec.cs" />
<Compile Include="Model\InitializationStrategy.cs" />
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
if (binderOptions?.ErrorOnUnknownConfiguration is true)
{
List<string>? temp = null;
+
foreach (IConfigurationSection section in configuration.GetChildren())
{
if (!keys.Value.Contains(section.Key))
(temp ??= new List<string>()).Add($"'{section.Key}'");
}
}
+
if (temp is not null)
{
throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
{
return null;
}
+
BinderOptions binderOptions = new();
configureOptions(binderOptions);
+
if (binderOptions.BindNonPublicProperties)
{
throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
}
+
return binderOptions;
}
.Split(Environment.NewLine);
var (d, r) = await RunGenerator(testSourceCode, languageVersion);
- bool success = RoslynTestUtils.CompareLines(expectedLines, r[0].SourceText,
- out string errorMessage);
+ bool success = RoslynTestUtils.CompareLines(expectedLines, r[0].SourceText, out string errorMessage);
#if !SKIP_BASELINES
Assert.Single(r);
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
+using SourceGenerators;
namespace System.Text.Json.SourceGeneration
{
<Compile Include="$(CoreLibSharedDir)System\Runtime\CompilerServices\IsExternalInit.cs" Link="Common\System\Runtime\CompilerServices\IsExternalInit.cs" />
<Compile Include="$(CoreLibSharedDir)System\Runtime\CompilerServices\CompilerFeatureRequiredAttribute.cs" Link="Common\System\Runtime\CompilerServices\CompilerFeatureRequiredAttribute.cs" />
<Compile Include="$(CoreLibSharedDir)System\Runtime\CompilerServices\RequiredMemberAttribute.cs" Link="Common\System\Runtime\CompilerServices\RequiredMemberAttribute.cs" />
+ <Compile Include="$(CommonPath)\Roslyn\GetBestTypeByMetadataName.cs" Link="Common\Roslyn\GetBestTypeByMetadataName.cs" />
+ <Compile Include="$(CommonPath)\SourceGenerators\SourceWriter.cs" Link="Common\SourceGenerators\SourceWriter.cs" />
<Compile Include="..\Common\JsonCamelCaseNamingPolicy.cs" Link="Common\System\Text\Json\JsonCamelCaseNamingPolicy.cs" />
<Compile Include="..\Common\JsonNamingPolicy.cs" Link="Common\System\Text\Json\JsonNamingPolicy.cs" />
<Compile Include="..\Common\JsonAttribute.cs" Link="Common\System\Text\Json\Serialization\JsonAttribute.cs" />
<Compile Include="..\Common\JsonUnknownTypeHandling.cs" Link="Common\System\Text\Json\Serialization\JsonUnknownTypeHandling.cs" />
<Compile Include="..\Common\JsonUnmappedMemberHandling.cs" Link="Common\System\Text\Json\Serialization\JsonUnmappedMemberHandling.cs" />
<Compile Include="..\Common\ThrowHelper.cs" Link="Common\System\Text\Json\ThrowHelper.cs" />
- <Compile Include="$(CommonPath)\Roslyn\GetBestTypeByMetadataName.cs" Link="Common\Roslyn\GetBestTypeByMetadataName.cs" />
<Compile Include="Helpers\DiagnosticInfo.cs" />
<Compile Include="Helpers\SourceGeneratorHelpers.cs" />
<Compile Include="Helpers\ImmutableEquatableArray.cs" />
<Compile Include="Helpers\KnownTypeSymbols.cs" />
<Compile Include="Helpers\RoslynExtensions.cs" />
- <Compile Include="Helpers\SourceWriter.cs" />
<Compile Include="JsonConstants.cs" />
<Compile Include="JsonSourceGenerator.DiagnosticDescriptors.cs" />
<Compile Include="JsonSourceGenerator.Emitter.cs" />