diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Emitter.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Emitter.cs index b969227138f98d..046b518f70a45d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Emitter.cs @@ -4,10 +4,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Text; using System.Text.RegularExpressions; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -79,8 +77,7 @@ public void Emit() EmitGenerationNamespaceAndHelpers(); - SourceText source = SourceText.From(_writer.GetSource(), Encoding.UTF8); - _context.AddSource($"{Identifier.GeneratedConfigurationBinder}.g.cs", source); + _context.AddSource($"{Identifier.GeneratedConfigurationBinder}.g.cs", _writer.ToSourceText()); } private void EmitConfigureMethod() @@ -275,10 +272,10 @@ private void EmitBindCoreImplForArray(EnumerableSpec type) // Resize array and copy fill with additional _writer.WriteBlock($$""" -{{Identifier.Int32}} {{Identifier.originalCount}} = {{Identifier.obj}}.{{Identifier.Length}}; -{{Identifier.Array}}.{{Identifier.Resize}}(ref {{Identifier.obj}}, {{Identifier.originalCount}} + {{tempVarName}}.{{Identifier.Count}}); -{{tempVarName}}.{{Identifier.CopyTo}}({{Identifier.obj}}, {{Identifier.originalCount}}); -"""); + {{Identifier.Int32}} {{Identifier.originalCount}} = {{Identifier.obj}}.{{Identifier.Length}}; + {{Identifier.Array}}.{{Identifier.Resize}}(ref {{Identifier.obj}}, {{Identifier.originalCount}} + {{tempVarName}}.{{Identifier.Count}}); + {{tempVarName}}.{{Identifier.CopyTo}}({{Identifier.obj}}, {{Identifier.originalCount}}); + """); } private void EmitBindCoreImplForDictionary(DictionarySpec type) @@ -675,11 +672,11 @@ private void EmitObjectInit(TypeSpec type, string expressionForMemberAccess, Ini private void EmitIConfigurationHasValueOrChildrenCheck() { _writer.WriteBlock($$""" -if (!{{GetHelperMethodDisplayString(Identifier.HasValueOrChildren)}}({{Identifier.configuration}})) -{ - return default; -} -"""); + if (!{{GetHelperMethodDisplayString(Identifier.HasValueOrChildren)}}({{Identifier.configuration}})) + { + return default; + } + """); _writer.WriteBlankLine(); } @@ -700,31 +697,29 @@ private void EmitHelperMethods() private void EmitHasValueOrChildrenMethod() { _writer.WriteBlock($$""" -public static bool {{Identifier.HasValueOrChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}}) -{ - if (({{Identifier.configuration}} as {{Identifier.IConfigurationSection}})?.{{Identifier.Value}} is not null) - { - return true; - } - - return {{Identifier.HasChildren}}({{Identifier.configuration}}); -} -"""); + public static bool {{Identifier.HasValueOrChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}}) + { + if (({{Identifier.configuration}} as {{Identifier.IConfigurationSection}})?.{{Identifier.Value}} is not null) + { + return true; + } + return {{Identifier.HasChildren}}({{Identifier.configuration}}); + } + """); } private void EmitHasChildrenMethod() { _writer.WriteBlock($$""" -public static bool {{Identifier.HasChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}}) -{ - foreach ({{Identifier.IConfigurationSection}} {{Identifier.section}} in {{Identifier.configuration}}.{{Identifier.GetChildren}}()) - { - return true; - } - - return false; -} -"""); + public static bool {{Identifier.HasChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}}) + { + foreach ({{Identifier.IConfigurationSection}} {{Identifier.section}} in {{Identifier.configuration}}.{{Identifier.GetChildren}}()) + { + return true; + } + return false; + } + """); } private void EmitVarDeclaration(TypeSpec type, string varName) => _writer.WriteLine($"{type.MinimalDisplayString} {varName};"); @@ -747,11 +742,11 @@ private void EmitCastToIConfigurationSection() } _writer.WriteBlock($$""" -if ({{Identifier.configuration}} is not {{sectionTypeDisplayString}} {{Identifier.section}}) -{ - throw new {{exceptionTypeDisplayString}}(); -} -"""); + if ({{Identifier.configuration}} is not {{sectionTypeDisplayString}} {{Identifier.section}}) + { + throw new {{exceptionTypeDisplayString}}(); + } + """); } private void Emit_NotSupportedException_UnableToBindType(string reason, string typeDisplayString = "{typeof(T)}") => @@ -772,11 +767,11 @@ private void EmitCheckForNullArgument_WithBlankLine(string argName, bool useFull : Identifier.ArgumentNullException; _writer.WriteBlock($$""" -if ({{argName}} is null) -{ - throw new {{exceptionTypeDisplayString}}(nameof({{argName}})); -} -"""); + if ({{argName}} is null) + { + throw new {{exceptionTypeDisplayString}}(nameof({{argName}})); + } + """); _writer.WriteBlankLine(); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Helpers.cs index 36feeb419aff55..0556d13cbd323a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Helpers.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Text; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -107,79 +108,5 @@ private static class TypeFullName private static bool TypesAreEqual(ITypeSymbol first, ITypeSymbol second) => first.Equals(second, SymbolEqualityComparer.Default); - - private sealed class SourceWriter - { - private readonly StringBuilder _sb = new(); - private int _indentationLevel; - - public int Length => _sb.Length; - public int IndentationLevel => _indentationLevel; - - public void WriteBlockStart(string? declaration = null) - { - if (declaration is not null) - { - WriteLine(declaration); - } - WriteLine("{"); - _indentationLevel++; - } - - public void WriteBlockEnd(string? extra = null) - { - _indentationLevel--; - Debug.Assert(_indentationLevel > -1); - WriteLine($"}}{extra}"); - } - - public void WriteLine(string source) - { - _sb.Append(' ', 4 * _indentationLevel); - _sb.AppendLine(source); - } - - public void WriteBlock(string source) - { - foreach (string value in source.Split('\n')) - { - string line = value.Trim(); - switch (line) - { - case "{": - { - WriteBlockStart(); - } - break; - case "}": - { - WriteBlockEnd(); - } - break; - case "": - { - WriteBlankLine(); - } - break; - default: - { - WriteLine(line); - } - break; - } - } - } - - public void WriteBlankLine() => _sb.AppendLine(); - - public void RemoveBlankLine() - { - int newLineLength = Environment.NewLine.Length; - int lastNewLineStartIndex = Length - newLineLength; - _sb.Remove(lastNewLineStartIndex, newLineLength); - } - - public string GetSource() => _sb.ToString(); - } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj index 0c1a30fb76bd07..b37529ecbc87e7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj @@ -5,9 +5,7 @@ false true cs - - - + true $(DefineConstants);LAUNCH_DEBUGGER @@ -34,6 +32,7 @@ + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/SourceWriter.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/SourceWriter.cs new file mode 100644 index 00000000000000..46aa34852ec50b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/SourceWriter.cs @@ -0,0 +1,129 @@ +// 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 int _indentationLevel; + + public int Length => _sb.Length; + public int IndentationLevel => _indentationLevel; + + private static readonly char[] s_newLine = Environment.NewLine.ToCharArray(); + + public void WriteBlockStart(string? declaration = null) + { + if (declaration is not null) + { + WriteLine(declaration); + } + WriteLine("{"); + _indentationLevel++; + } + + public void WriteBlockEnd(string? extra = null) + { + _indentationLevel--; + Debug.Assert(_indentationLevel > -1); + WriteLine($"}}{extra}"); + } + + public void WriteLine(string source) + { + _sb.Append(' ', 4 * _indentationLevel); + _sb.AppendLine(source); + } + + public unsafe void WriteLine(ReadOnlySpan source) + { + _sb.Append(' ', 4 * _indentationLevel); + fixed (char* ptr = source) + { + _sb.Append(ptr, source.Length); + WriteBlankLine(); + } + } + + public void WriteBlock(string source) + { + bool isFinalLine; + ReadOnlySpan remainingText = source.AsSpan(); + + do + { + ReadOnlySpan 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 void RemoveBlankLine() + { + int newLineLength = s_newLine.Length; + int lastNewLineStartIndex = Length - newLineLength; + _sb.Remove(lastNewLineStartIndex, newLineLength); + } + + public SourceText ToSourceText() + { + Debug.Assert(_indentationLevel == 0 && _sb.Length > 0); + return SourceText.From(_sb.ToString(), Encoding.UTF8); + } + + private static ReadOnlySpan GetNextLine(ref ReadOnlySpan remainingText, out bool isFinalLine) + { + if (remainingText.IsEmpty) + { + isFinalLine = true; + return default; + } + + ReadOnlySpan next; + ReadOnlySpan 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; + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestBindCallGen.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestBindCallGen.generated.txt index 4448061fc15cf2..30c909d2d5e9dd 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestBindCallGen.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestBindCallGen.generated.txt @@ -139,7 +139,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { return true; } - return false; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestConfigureCallGen.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestConfigureCallGen.generated.txt index 106a70159245df..6f19224ea7b84d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestConfigureCallGen.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestConfigureCallGen.generated.txt @@ -119,7 +119,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { return true; } - return HasChildren(configuration); } @@ -129,7 +128,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { return true; } - return false; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestGetCallGen.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestGetCallGen.generated.txt index 209bfd73e4b7ca..32e497efd4df1d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestGetCallGen.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestGetCallGen.generated.txt @@ -118,7 +118,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { return true; } - return HasChildren(configuration); } @@ -128,7 +127,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { return true; } - return false; } }