diff --git a/Directory.Build.targets b/Directory.Build.targets
index c96d110b2dd..ff17457a836 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -16,7 +16,17 @@
false
-
+
+ $(NoWarn);CS0436
+
+
$(NoWarn);IL2026;IL2087;IL2067;IL2075;IL2091;IL2072;IL2090;CA1825;IL2070;IL2098;IL2057
@@ -35,14 +45,14 @@
$(NoWarn);CA1062
-
+
$(NoWarn);ASP0019
-
+
$(NoWarn);RS1024
@@ -66,7 +76,9 @@
-
+
+ <_Parameter1>TBD
+
diff --git a/eng/MSBuild/Generators.props b/eng/MSBuild/Generators.props
index 580c36c5592..52f47521cfe 100644
--- a/eng/MSBuild/Generators.props
+++ b/eng/MSBuild/Generators.props
@@ -7,10 +7,6 @@
-
-
-
-
diff --git a/src/Generators/Microsoft.Gen.OptionsValidation/Common/DiagDescriptors.cs b/src/Generators/Microsoft.Gen.OptionsValidation/Common/DiagDescriptors.cs
deleted file mode 100644
index 25a4bbe69c4..00000000000
--- a/src/Generators/Microsoft.Gen.OptionsValidation/Common/DiagDescriptors.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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;
-using Microsoft.Gen.Shared;
-
-namespace Microsoft.Gen.OptionsValidation;
-
-internal sealed class DiagDescriptors : DiagDescriptorsBase
-{
- private const string Category = "OptionsValidation";
-
- // Skipping R9G100
-
- public static DiagnosticDescriptor CantUseWithGenericTypes { get; } = Make(
- id: "R9G101",
- title: Resources.CantUseWithGenericTypesTitle,
- messageFormat: Resources.CantUseWithGenericTypesMessage,
- category: Category);
-
- public static DiagnosticDescriptor NoEligibleMember { get; } = Make(
- id: "R9G102",
- title: Resources.NoEligibleMemberTitle,
- messageFormat: Resources.NoEligibleMemberMessage,
- category: Category,
- defaultSeverity: DiagnosticSeverity.Warning);
-
- public static DiagnosticDescriptor NoEligibleMembersFromValidator { get; } = Make(
- id: "R9G103",
- title: Resources.NoEligibleMembersFromValidatorTitle,
- messageFormat: Resources.NoEligibleMembersFromValidatorMessage,
- category: Category,
- defaultSeverity: DiagnosticSeverity.Warning);
-
- public static DiagnosticDescriptor DoesntImplementIValidateOptions { get; } = Make(
- id: "R9G104",
- title: Resources.DoesntImplementIValidateOptionsTitle,
- messageFormat: Resources.DoesntImplementIValidateOptionsMessage,
- category: Category);
-
- public static DiagnosticDescriptor AlreadyImplementsValidateMethod { get; } = Make(
- id: "R9G105",
- title: Resources.AlreadyImplementsValidateMethodTitle,
- messageFormat: Resources.AlreadyImplementsValidateMethodMessage,
- category: Category);
-
- public static DiagnosticDescriptor MemberIsInaccessible { get; } = Make(
- id: "R9G106",
- title: Resources.MemberIsInaccessibleTitle,
- messageFormat: Resources.MemberIsInaccessibleMessage,
- category: Category);
-
- public static DiagnosticDescriptor NotEnumerableType { get; } = Make(
- id: "R9G107",
- title: Resources.NotEnumerableTypeTitle,
- messageFormat: Resources.NotEnumerableTypeMessage,
- category: Category);
-
- public static DiagnosticDescriptor ValidatorsNeedSimpleConstructor { get; } = Make(
- id: "R9G108",
- title: Resources.ValidatorsNeedSimpleConstructorTitle,
- messageFormat: Resources.ValidatorsNeedSimpleConstructorMessage,
- category: Category);
-
- public static DiagnosticDescriptor CantBeStaticClass { get; } = Make(
- id: "R9G109",
- title: Resources.CantBeStaticClassTitle,
- messageFormat: Resources.CantBeStaticClassMessage,
- category: Category);
-
- public static DiagnosticDescriptor NullValidatorType { get; } = Make(
- id: "R9G110",
- title: Resources.NullValidatorTypeTitle,
- messageFormat: Resources.NullValidatorTypeMessage,
- category: Category);
-
- public static DiagnosticDescriptor CircularTypeReferences { get; } = Make(
- id: "R9G111",
- title: Resources.CircularTypeReferencesTitle,
- messageFormat: Resources.CircularTypeReferencesMessage,
- category: Category);
-
- // 112 is available for reuse
-
- public static DiagnosticDescriptor PotentiallyMissingTransitiveValidation { get; } = Make(
- id: "R9G113",
- title: Resources.PotentiallyMissingTransitiveValidationTitle,
- messageFormat: Resources.PotentiallyMissingTransitiveValidationMessage,
- category: Category,
- defaultSeverity: DiagnosticSeverity.Warning);
-
- public static DiagnosticDescriptor PotentiallyMissingEnumerableValidation { get; } = Make(
- id: "R9G114",
- title: Resources.PotentiallyMissingEnumerableValidationTitle,
- messageFormat: Resources.PotentiallyMissingEnumerableValidationMessage,
- category: Category,
- defaultSeverity: DiagnosticSeverity.Warning);
-}
diff --git a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Emitter.cs b/src/Generators/Microsoft.Gen.OptionsValidation/Common/Emitter.cs
deleted file mode 100644
index c7103aec951..00000000000
--- a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Emitter.cs
+++ /dev/null
@@ -1,368 +0,0 @@
-// 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.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using Microsoft.Gen.OptionsValidation.Model;
-using Microsoft.Gen.Shared;
-
-namespace Microsoft.Gen.OptionsValidation;
-
-// Stryker disable all
-
-///
-/// Emits option validation.
-///
-internal sealed class Emitter : EmitterBase
-{
- private const string StaticValidationAttributeHolderClassName = "__Attributes";
- private const string StaticValidatorHolderClassName = "__Validators";
- private const string StaticFieldHolderClassesNamespace = "__OptionValidationStaticInstances";
- private const string StaticValidationAttributeHolderClassFQN = $"global::{StaticFieldHolderClassesNamespace}.{StaticValidationAttributeHolderClassName}";
- private const string StaticValidatorHolderClassFQN = $"global::{StaticFieldHolderClassesNamespace}.{StaticValidatorHolderClassName}";
- private sealed record StaticFieldInfo(string FieldTypeFQN, int FieldOrder, string FieldName, IList InstantiationLines);
-
- public string Emit(
- IEnumerable validatorTypes,
- CancellationToken cancellationToken)
- {
- var staticValidationAttributesDict = new Dictionary();
- var staticValidatorsDict = new Dictionary();
-
- foreach (var vt in validatorTypes.OrderBy(static lt => lt.Namespace + "." + lt.Name))
- {
- cancellationToken.ThrowIfCancellationRequested();
- GenValidatorType(vt, ref staticValidationAttributesDict, ref staticValidatorsDict);
- }
-
- GenStaticClassWithStaticReadonlyFields(staticValidationAttributesDict.Values, StaticFieldHolderClassesNamespace, StaticValidationAttributeHolderClassName);
- GenStaticClassWithStaticReadonlyFields(staticValidatorsDict.Values, StaticFieldHolderClassesNamespace, StaticValidatorHolderClassName);
-
- return Capture();
- }
-
- private void GenValidatorType(ValidatorType vt, ref Dictionary staticValidationAttributesDict, ref Dictionary staticValidatorsDict)
- {
- OutLn("#pragma warning disable CS0618 // Type or member is obsolete");
-
- if (vt.Namespace.Length > 0)
- {
- OutLn($"namespace {vt.Namespace}");
- OutOpenBrace();
- }
-
- foreach (var p in vt.ParentTypes)
- {
- OutLn(p);
- OutOpenBrace();
- }
-
- if (vt.IsSynthetic)
- {
- OutGeneratedCodeAttribute();
- OutLn($"internal sealed partial {vt.DeclarationKeyword} {vt.Name}");
- }
- else
- {
- OutLn($"partial {vt.DeclarationKeyword} {vt.Name}");
- }
-
- OutOpenBrace();
-
- for (var i = 0; i < vt.ModelsToValidate.Count; i++)
- {
- var modelToValidate = vt.ModelsToValidate[i];
-
- GenModelValidationMethod(modelToValidate, vt.IsSynthetic, ref staticValidationAttributesDict, ref staticValidatorsDict);
- }
-
- OutCloseBrace();
-
- foreach (var _ in vt.ParentTypes)
- {
- OutCloseBrace();
- }
-
- if (vt.Namespace.Length > 0)
- {
- OutCloseBrace();
- }
- }
-
- private void GenStaticClassWithStaticReadonlyFields(IEnumerable staticFields, string classNamespace, string className)
- {
- OutLn($"namespace {classNamespace}");
- OutOpenBrace();
-
- OutGeneratedCodeAttribute();
- OutLn($"file static class {className}");
- OutOpenBrace();
-
- var staticValidationAttributes = staticFields
- .OrderBy(x => x.FieldOrder)
- .ToArray();
-
- for (var i = 0; i < staticValidationAttributes.Length; i++)
- {
- var attributeInstance = staticValidationAttributes[i];
- OutIndent();
- Out($"internal static readonly {attributeInstance.FieldTypeFQN} {attributeInstance.FieldName} = ");
- for (var j = 0; j < attributeInstance.InstantiationLines.Count; j++)
- {
- var line = attributeInstance.InstantiationLines[j];
- Out(line);
- if (j != attributeInstance.InstantiationLines.Count - 1)
- {
- OutLn();
- OutIndent();
- }
- else
- {
- Out(';');
- }
- }
-
- OutLn();
-
- if (i != staticValidationAttributes.Length - 1)
- {
- OutLn();
- }
- }
-
- OutCloseBrace();
-
- OutCloseBrace();
- }
-
- private void GenModelSelfValidationIfNecessary(ValidatedModel modelToValidate)
- {
- if (modelToValidate.SelfValidates)
- {
- OutLn($"builder.AddResults(((global::System.ComponentModel.DataAnnotations.IValidatableObject)options).Validate(context));");
- OutLn();
- }
- }
-
- private void GenModelValidationMethod(
- ValidatedModel modelToValidate,
- bool makeStatic,
- ref Dictionary staticValidationAttributesDict,
- ref Dictionary staticValidatorsDict)
- {
- OutLn($"/// ");
- OutLn($"/// Validates a specific named options instance (or all when is ).");
- OutLn($"/// ");
- OutLn($"/// The name of the options instance being validated.");
- OutLn($"/// The options instance.");
- OutLn($"/// Validation result.");
- OutGeneratedCodeAttribute();
-
- OutLn($"public {(makeStatic ? "static " : string.Empty)}global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, {modelToValidate.Name} options)");
- OutOpenBrace();
- OutLn($"var baseName = (string.IsNullOrEmpty(name) ? \"{modelToValidate.SimpleName}\" : name) + \".\";");
- OutLn($"var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder();");
- OutLn($"var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options);");
- OutLn();
-
- foreach (var vm in modelToValidate.MembersToValidate)
- {
- if (vm.ValidationAttributes.Count > 0)
- {
- GenMemberValidation(vm, ref staticValidationAttributesDict);
- OutLn();
- }
-
- if (vm.TransValidatorType != null)
- {
- GenTransitiveValidation(vm, ref staticValidatorsDict);
- OutLn();
- }
-
- if (vm.EnumerationValidatorType != null)
- {
- GenEnumerationValidation(vm, ref staticValidatorsDict);
- OutLn();
- }
- }
-
- GenModelSelfValidationIfNecessary(modelToValidate);
- OutLn($"return builder.Build();");
- OutCloseBrace();
- }
-
- private void GenMemberValidation(ValidatedMember vm,
- ref Dictionary staticValidationAttributesDict)
- {
- OutLn($"context.MemberName = \"{vm.Name}\";");
- OutLn($"context.DisplayName = baseName + \"{vm.Name}\";");
-
- foreach (var attr in vm.ValidationAttributes)
- {
- var staticValidationAttributeInstance = GetOrAddStaticValidationAttribute(ref staticValidationAttributesDict, attr);
-
- OutLn($"builder.AddResult({StaticValidationAttributeHolderClassFQN}.{staticValidationAttributeInstance.FieldName}.GetValidationResult(options.{vm.Name}, context));");
- }
- }
-
- private StaticFieldInfo GetOrAddStaticValidationAttribute(ref Dictionary staticValidationAttributesDict, ValidationAttributeInfo attr)
- {
- var attrInstantiationStatementLines = new List();
-
- if (attr.ConstructorArguments.Count > 0)
- {
- attrInstantiationStatementLines.Add($"new {attr.AttributeName}(");
-
- for (var i = 0; i < attr.ConstructorArguments.Count; i++)
- {
- if (i != attr.ConstructorArguments.Count - 1)
- {
- attrInstantiationStatementLines.Add($"{GetPaddingString(1)}{attr.ConstructorArguments[i]},");
- }
- else
- {
- attrInstantiationStatementLines.Add($"{GetPaddingString(1)}{attr.ConstructorArguments[i]})");
- }
- }
- }
- else
- {
- attrInstantiationStatementLines.Add($"new {attr.AttributeName}()");
- }
-
- if (attr.Properties.Count > 0)
- {
- attrInstantiationStatementLines.Add("{");
-
- var propertiesOrderedByKey = attr.Properties
- .OrderBy(p => p.Key)
- .ToArray();
-
- for (var i = 0; i < propertiesOrderedByKey.Length; i++)
- {
- var prop = propertiesOrderedByKey[i];
- var notLast = i != propertiesOrderedByKey.Length - 1;
- attrInstantiationStatementLines.Add($"{GetPaddingString(1)}{prop.Key} = {prop.Value}{(notLast ? "," : string.Empty)}");
- }
-
- attrInstantiationStatementLines.Add("}");
- }
-
- var instantiationStatement = string.Join(Environment.NewLine, attrInstantiationStatementLines);
-
- if (!staticValidationAttributesDict.TryGetValue(instantiationStatement, out var staticValidationAttributeInstance))
- {
- var fieldNumber = staticValidationAttributesDict.Count + 1;
- staticValidationAttributeInstance = new StaticFieldInfo(
- FieldTypeFQN: attr.AttributeName,
- FieldOrder: fieldNumber,
- FieldName: $"A{fieldNumber}",
- InstantiationLines: attrInstantiationStatementLines);
-
- staticValidationAttributesDict.Add(instantiationStatement, staticValidationAttributeInstance);
- }
-
- return staticValidationAttributeInstance;
- }
-
- private void GenTransitiveValidation(ValidatedMember vm, ref Dictionary staticValidatorsDict)
- {
- string callSequence;
- if (vm.TransValidateTypeIsSynthetic)
- {
- callSequence = vm.TransValidatorType!;
- }
- else
- {
- var staticValidatorInstance = GetOrAddStaticValidator(ref staticValidatorsDict, vm.TransValidatorType!);
-
- callSequence = $"{StaticValidatorHolderClassFQN}.{staticValidatorInstance.FieldName}";
- }
-
- var valueAccess = (vm.IsNullable && vm.IsValueType) ? ".Value" : string.Empty;
-
- if (vm.IsNullable)
- {
- OutLn($"if (options.{vm.Name} != null)");
- OutLn($"{{");
- OutLn($" builder.AddResult({callSequence}.Validate(baseName + \"{vm.Name}\", options.{vm.Name}{valueAccess}));");
- OutLn($"}}");
- }
- else
- {
- OutLn($"builder.AddResult({callSequence}.Validate(baseName + \"{vm.Name}\", options.{vm.Name}{valueAccess}));");
- }
- }
-
- private void GenEnumerationValidation(ValidatedMember vm, ref Dictionary staticValidatorsDict)
- {
- var valueAccess = (vm.IsValueType && vm.IsNullable) ? ".Value" : string.Empty;
- var enumeratedValueAccess = (vm.EnumeratedIsNullable && vm.EnumeratedIsValueType) ? ".Value" : string.Empty;
- string callSequence;
- if (vm.EnumerationValidatorTypeIsSynthetic)
- {
- callSequence = vm.EnumerationValidatorType!;
- }
- else
- {
- var staticValidatorInstance = GetOrAddStaticValidator(ref staticValidatorsDict, vm.EnumerationValidatorType!);
-
- callSequence = $"{StaticValidatorHolderClassFQN}.{staticValidatorInstance.FieldName}";
- }
-
- if (vm.IsNullable)
- {
- OutLn($"if (options.{vm.Name} != null)");
- }
-
- OutOpenBrace();
-
- OutLn($"var count = 0;");
- OutLn($"foreach (var o in options.{vm.Name}{valueAccess})");
- OutOpenBrace();
-
- if (vm.EnumeratedIsNullable)
- {
- OutLn($"if (o is not null)");
- OutLn($"{{");
- OutLn($" builder.AddResult({callSequence}.Validate(baseName + $\"{vm.Name}[{{count++}}]\", o{enumeratedValueAccess}));");
- OutLn($"}}");
-
- if (!vm.EnumeratedMayBeNull)
- {
- OutLn($"else");
- OutLn($"{{");
- OutLn($" builder.AddError(baseName + $\"{vm.Name}[{{count++}}] is null\");");
- OutLn($"}}");
- }
- }
- else
- {
- OutLn($"builder.AddResult({callSequence}.Validate(baseName + $\"{vm.Name}[{{count++}}]\", o{enumeratedValueAccess}));");
- }
-
- OutCloseBrace();
- OutCloseBrace();
- }
-
-#pragma warning disable CA1822 // Mark members as static: static should come before non-static, but we want the method to be here
- private StaticFieldInfo GetOrAddStaticValidator(ref Dictionary staticValidatorsDict, string validatorTypeFQN)
-#pragma warning restore CA1822
- {
- if (!staticValidatorsDict.TryGetValue(validatorTypeFQN, out var staticValidatorInstance))
- {
- var fieldNumber = staticValidatorsDict.Count + 1;
- staticValidatorInstance = new StaticFieldInfo(
- FieldTypeFQN: validatorTypeFQN,
- FieldOrder: fieldNumber,
- FieldName: $"V{fieldNumber}",
- InstantiationLines: new[] { $"new {validatorTypeFQN}()" });
-
- staticValidatorsDict.Add(validatorTypeFQN, staticValidatorInstance);
- }
-
- return staticValidatorInstance;
- }
-}
diff --git a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Generator.cs b/src/Generators/Microsoft.Gen.OptionsValidation/Common/Generator.cs
deleted file mode 100644
index 3f0a49c5a3d..00000000000
--- a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Generator.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-#if ROSLYN_4_0_OR_GREATER
-
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Text;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Text;
-using Microsoft.Gen.Shared;
-
-namespace Microsoft.Gen.OptionsValidation;
-
-[Generator]
-[ExcludeFromCodeCoverage]
-public class Generator : IIncrementalGenerator
-{
- private static readonly HashSet _attributeNames = new()
- {
- SymbolLoader.OptionsValidatorAttribute,
- };
-
- public void Initialize(IncrementalGeneratorInitializationContext context)
- {
- GeneratorUtilities.Initialize(context, _attributeNames, HandleAnnotatedTypes);
- }
-
- private static void HandleAnnotatedTypes(Compilation compilation, IEnumerable nodes, SourceProductionContext context)
- {
- if (!SymbolLoader.TryLoad(compilation, out var symbolHolder))
- {
- // Not eligible compilation
- return;
- }
-
- var parser = new Parser(compilation, context.ReportDiagnostic, symbolHolder!, context.CancellationToken);
-
- var validatorTypes = parser.GetValidatorTypes(nodes.OfType());
- if (validatorTypes.Count > 0)
- {
- var emitter = new Emitter();
- var result = emitter.Emit(validatorTypes, context.CancellationToken);
-
- context.AddSource("Validators.g.cs", SourceText.From(result, Encoding.UTF8));
- }
- }
-}
-
-#else
-
-using System.Diagnostics.CodeAnalysis;
-using System.Text;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.Text;
-using Microsoft.Gen.Shared;
-
-namespace Microsoft.Gen.OptionsValidation;
-
-///
-/// Generates for classes that are marked with .
-///
-[Generator]
-[ExcludeFromCodeCoverage]
-public class Generator : ISourceGenerator
-{
- public void Initialize(GeneratorInitializationContext context)
- {
- context.RegisterForSyntaxNotifications(TypeDeclarationSyntaxReceiver.Create);
- }
-
- public void Execute(GeneratorExecutionContext context)
- {
- var receiver = context.SyntaxReceiver as TypeDeclarationSyntaxReceiver;
- if (receiver == null || receiver.TypeDeclarations.Count == 0)
- {
- // nothing to do yet
- return;
- }
-
- if (!SymbolLoader.TryLoad(context.Compilation, out var symbolHolder))
- {
- // Not eligible compilation
- return;
- }
-
- var parser = new Parser(context.Compilation, context.ReportDiagnostic, symbolHolder!, context.CancellationToken);
- var validatorTypes = parser.GetValidatorTypes(receiver.TypeDeclarations);
- if (validatorTypes.Count > 0)
- {
- var emitter = new Emitter();
- var result = emitter.Emit(validatorTypes, context.CancellationToken);
- context.AddSource("Validators.g.cs", SourceText.From(result, Encoding.UTF8));
- }
- }
-}
-
-#endif
diff --git a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidatedMember.cs b/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidatedMember.cs
deleted file mode 100644
index 0ffe9385e8f..00000000000
--- a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidatedMember.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Collections.Generic;
-
-namespace Microsoft.Gen.OptionsValidation.Model;
-
-internal sealed record class ValidatedMember(
- string Name,
- List ValidationAttributes,
- string? TransValidatorType,
- bool TransValidateTypeIsSynthetic,
- string? EnumerationValidatorType,
- bool EnumerationValidatorTypeIsSynthetic,
- bool IsNullable,
- bool IsValueType,
- bool EnumeratedIsNullable,
- bool EnumeratedIsValueType,
- bool EnumeratedMayBeNull);
diff --git a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidatedModel.cs b/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidatedModel.cs
deleted file mode 100644
index 8b354f5d235..00000000000
--- a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidatedModel.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Collections.Generic;
-
-namespace Microsoft.Gen.OptionsValidation.Model;
-
-internal sealed record class ValidatedModel(
- string Name,
- string SimpleName,
- bool SelfValidates,
- List MembersToValidate);
diff --git a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidationAttributeInfo.cs b/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidationAttributeInfo.cs
deleted file mode 100644
index 111073d1aa3..00000000000
--- a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidationAttributeInfo.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Collections.Generic;
-
-namespace Microsoft.Gen.OptionsValidation.Model;
-
-internal sealed record class ValidationAttributeInfo(string AttributeName)
-{
- public List ConstructorArguments { get; } = new();
- public Dictionary Properties { get; } = new();
-}
diff --git a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidatorType.cs b/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidatorType.cs
deleted file mode 100644
index 27c5caaa634..00000000000
--- a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Model/ValidatorType.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Collections.Generic;
-
-namespace Microsoft.Gen.OptionsValidation.Model;
-
-internal sealed record class ValidatorType(
- string Namespace,
- string Name,
- string NameWithoutGenerics,
- string DeclarationKeyword,
- List ParentTypes,
- bool IsSynthetic,
- IList ModelsToValidate);
diff --git a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Parser.cs b/src/Generators/Microsoft.Gen.OptionsValidation/Common/Parser.cs
deleted file mode 100644
index 4b27c09597a..00000000000
--- a/src/Generators/Microsoft.Gen.OptionsValidation/Common/Parser.cs
+++ /dev/null
@@ -1,696 +0,0 @@
-// 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.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.Gen.OptionsValidation.Model;
-using Microsoft.Gen.Shared;
-
-namespace Microsoft.Gen.OptionsValidation;
-
-///
-/// Holds an internal parser class that extracts necessary information for generating IValidateOptions.
-///
-internal sealed class Parser
-{
- private const int NumValidationMethodArgs = 2;
-
- private readonly CancellationToken _cancellationToken;
- private readonly Compilation _compilation;
- private readonly Action _reportDiagnostic;
- private readonly SymbolHolder _symbolHolder;
- private readonly Dictionary _synthesizedValidators = new(SymbolEqualityComparer.Default);
- private readonly HashSet _visitedModelTypes = new(SymbolEqualityComparer.Default);
-
- public Parser(
- Compilation compilation,
- Action reportDiagnostic,
- SymbolHolder symbolHolder,
- CancellationToken cancellationToken)
- {
- _compilation = compilation;
- _cancellationToken = cancellationToken;
- _reportDiagnostic = reportDiagnostic;
- _symbolHolder = symbolHolder;
- }
-
- public IReadOnlyList GetValidatorTypes(IEnumerable classes)
- {
- var results = new List();
-
- foreach (var group in classes.GroupBy(x => x.SyntaxTree))
- {
- SemanticModel? sm = null;
- foreach (var typeDec in group)
- {
- _cancellationToken.ThrowIfCancellationRequested();
- sm ??= _compilation.GetSemanticModel(typeDec.SyntaxTree);
-
- var validatorType = sm.GetDeclaredSymbol(typeDec) as ITypeSymbol;
- if (validatorType != null)
- {
-#if !ROSLYN_4_0_OR_GREATER
- if (!IsAnnotated(validatorType))
- {
- continue;
- }
-#endif
- if (validatorType.IsStatic)
- {
- Diag(DiagDescriptors.CantBeStaticClass, typeDec.GetLocation());
- continue;
- }
-
- _visitedModelTypes.Clear();
-
- var modelTypes = GetModelTypes(validatorType);
- if (modelTypes.Count == 0)
- {
- // validator doesn't implement IValidateOptions
- Diag(DiagDescriptors.DoesntImplementIValidateOptions, typeDec.GetLocation(), validatorType.Name);
- continue;
- }
-
- var modelsValidatorTypeValidates = new List(modelTypes.Count);
-
- foreach (var modelType in modelTypes)
- {
- if (modelType.Kind == SymbolKind.ErrorType)
- {
- // the compiler will report this error for us
- continue;
- }
- else
- {
- // keep track of the models we look at, to detect loops
- _ = _visitedModelTypes.Add(modelType.WithNullableAnnotation(NullableAnnotation.None));
- }
-
- if (AlreadyImplementsValidateMethod(validatorType, modelType))
- {
- // this type already implements a validation function, we can't auto-generate a new one
- Diag(DiagDescriptors.AlreadyImplementsValidateMethod, typeDec.GetLocation(), validatorType.Name);
- continue;
- }
-
- var membersToValidate = GetMembersToValidate(modelType, true);
- if (membersToValidate.Count == 0)
- {
- // this type lacks any eligible members
- Diag(DiagDescriptors.NoEligibleMembersFromValidator, typeDec.GetLocation(), modelType.ToString(), validatorType.ToString());
- continue;
- }
-
- modelsValidatorTypeValidates.Add(new ValidatedModel(
- GetFQN(modelType),
- modelType.Name,
- ModelSelfValidates(modelType),
- membersToValidate));
- }
-
- string keyword = GetTypeKeyword(validatorType);
-
- // following code establishes the containment hierarchy for the generated type in terms of nested types
-
- var parents = new List();
- var parent = typeDec.Parent as TypeDeclarationSyntax;
-
- while (parent != null && IsAllowedKind(parent.Kind()))
- {
- parents.Add($"partial {GetTypeKeyword(parent)} {parent.Identifier}{parent.TypeParameterList} {parent.ConstraintClauses}");
- parent = parent.Parent as TypeDeclarationSyntax;
- }
-
- parents.Reverse();
-
- results.Add(new ValidatorType(
- validatorType.ContainingNamespace.IsGlobalNamespace ? string.Empty : validatorType.ContainingNamespace.ToString(),
- GetMinimalFQN(validatorType),
- GetMinimalFQNWithoutGenerics(validatorType),
- keyword,
- parents,
- false,
- modelsValidatorTypeValidates));
- }
- }
- }
-
- results.AddRange(_synthesizedValidators.Values);
- _synthesizedValidators.Clear();
-
- return results;
- }
-
- private static bool IsAllowedKind(SyntaxKind kind) =>
- kind == SyntaxKind.ClassDeclaration ||
- kind == SyntaxKind.StructDeclaration ||
-#if ROSLYN_4_0_OR_GREATER
- kind == SyntaxKind.RecordStructDeclaration ||
-#endif
- kind == SyntaxKind.RecordDeclaration;
-
- private static string GetTypeKeyword(ITypeSymbol type)
- {
-#if ROSLYN_4_0_OR_GREATER
- if (type.IsReferenceType)
- {
- return type.IsRecord ? "record class" : "class";
- }
-
- return type.IsRecord ? "record struct" : "struct";
-#else
- return type.IsReferenceType ? "class" : "struct";
-#endif
- }
-
- private static string GetTypeKeyword(TypeDeclarationSyntax type) =>
- type.Kind() switch
- {
- SyntaxKind.ClassDeclaration => "class",
- SyntaxKind.RecordDeclaration => "record class",
-#if ROSLYN_4_0_OR_GREATER
- SyntaxKind.RecordStructDeclaration => "record struct",
-#endif
- _ => type.Keyword.ValueText,
- };
-
- private static string GetFQN(ISymbol type)
- => type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier));
-
- private static string GetMinimalFQN(ISymbol type)
- => type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat.AddGenericsOptions(SymbolDisplayGenericsOptions.IncludeTypeParameters));
-
- private static string GetMinimalFQNWithoutGenerics(ISymbol type)
- => type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat.WithGenericsOptions(SymbolDisplayGenericsOptions.None));
-
- ///
- /// Checks whether the given validator already implement the IValidationOptions>T< interface.
- ///
- private static bool AlreadyImplementsValidateMethod(INamespaceOrTypeSymbol validatorType, ISymbol modelType)
- => validatorType
- .GetMembers("Validate")
- .Where(m => m.Kind == SymbolKind.Method)
- .Select(m => (IMethodSymbol)m)
- .Any(m => m.Parameters.Length == NumValidationMethodArgs
- && m.Parameters[0].Type.SpecialType == SpecialType.System_String
- && SymbolEqualityComparer.Default.Equals(m.Parameters[1].Type, modelType));
-
- ///
- /// Checks whether the given type contain any unbound generic type arguments.
- ///
- private static bool HasOpenGenerics(ITypeSymbol type, out string genericType)
- {
- if (type is INamedTypeSymbol mt)
- {
- if (mt.IsGenericType)
- {
- foreach (var ta in mt.TypeArguments)
- {
- if (ta.TypeKind == TypeKind.TypeParameter)
- {
- genericType = ta.Name;
- return true;
- }
- }
- }
- }
- else if (type is ITypeParameterSymbol)
- {
- genericType = type.Name;
- return true;
- }
- else if (type is IArrayTypeSymbol ats)
- {
- return HasOpenGenerics(ats.ElementType, out genericType);
- }
-
- genericType = string.Empty;
- return false;
- }
-
-#if !ROSLYN_4_0_OR_GREATER
- private bool IsAnnotated(ISymbol type)
- {
- foreach (var attribute in type.GetAttributes().Where(a => a.AttributeClass != null))
- {
- var attributeType = attribute.AttributeClass!;
-
- if (SymbolEqualityComparer.Default.Equals(attributeType, _symbolHolder.OptionsValidatorSymbol))
- {
- return true;
- }
- }
-
- return false;
- }
-#endif
-
- private ITypeSymbol? GetEnumeratedType(ITypeSymbol type)
- {
- if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
- {
- // extract the T from a Nullable
- type = ((INamedTypeSymbol)type).TypeArguments[0];
- }
-
- foreach (var implementingInterface in type.AllInterfaces)
- {
- if (SymbolEqualityComparer.Default.Equals(implementingInterface.OriginalDefinition, _compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T)))
- {
- return implementingInterface.TypeArguments.First();
- }
- }
-
- return null;
- }
-
- private List GetMembersToValidate(ITypeSymbol modelType, bool speculate)
- {
- // make a list of the most derived members in the model type
-
- if (modelType.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
- {
- // extract the T from a Nullable
- modelType = ((INamedTypeSymbol)modelType).TypeArguments[0];
- }
-
- var members = modelType.GetMembers().ToList();
- var addedMembers = new HashSet(members.Select(m => m.Name));
- var baseType = modelType.BaseType;
- while (baseType is not null && baseType.SpecialType != SpecialType.System_Object)
- {
- var baseMembers = baseType.GetMembers().Where(m => !addedMembers.Contains(m.Name));
- members.AddRange(baseMembers);
- addedMembers.UnionWith(baseMembers.Select(m => m.Name));
- baseType = baseType.BaseType;
- }
-
- var membersToValidate = new List();
- foreach (var member in members)
- {
- var memberInfo = GetMemberInfo(member, speculate);
- if (memberInfo != null)
- {
- if (member.DeclaredAccessibility != Accessibility.Public && member.DeclaredAccessibility != Accessibility.Internal)
- {
- Diag(DiagDescriptors.MemberIsInaccessible, member.Locations.First(), member.Name);
- continue;
- }
-
- membersToValidate.Add(memberInfo);
- }
- }
-
- return membersToValidate;
- }
-
- private ValidatedMember? GetMemberInfo(ISymbol member, bool speculate)
- {
- ITypeSymbol memberType;
- switch (member)
- {
- case IPropertySymbol prop:
- memberType = prop.Type;
- break;
- case IFieldSymbol field:
- if (field.AssociatedSymbol != null)
- {
- // a backing field for a property, don't need those
- return null;
- }
-
- memberType = field.Type;
- break;
- default:
- // we only care about properties and fields
- return null;
- }
-
- var validationAttrs = new List();
- string? transValidatorTypeName = null;
- string? enumerationValidatorTypeName = null;
- var enumeratedIsNullable = false;
- var enumeratedIsValueType = false;
- var enumeratedMayBeNull = false;
- var transValidatorIsSynthetic = false;
- var enumerationValidatorIsSynthetic = false;
-
- foreach (var attribute in member.GetAttributes().Where(a => a.AttributeClass != null))
- {
- var attributeType = attribute.AttributeClass!;
- var attrLoc = attribute.ApplicationSyntaxReference?.GetSyntax().GetLocation();
-
- if (SymbolEqualityComparer.Default.Equals(attributeType, _symbolHolder.ValidateObjectMembersAttributeSymbol)
- || SymbolEqualityComparer.Default.Equals(attributeType, _symbolHolder.LegacyValidateTransitivelyAttributeSymbol))
- {
- if (HasOpenGenerics(memberType, out var genericType))
- {
- Diag(DiagDescriptors.CantUseWithGenericTypes, attrLoc, genericType);
-#pragma warning disable S1226 // Method parameters, caught exceptions and foreach variables' initial values should not be ignored
- speculate = false;
-#pragma warning restore S1226 // Method parameters, caught exceptions and foreach variables' initial values should not be ignored
- continue;
- }
-
- if (attribute.ConstructorArguments.Length == 1)
- {
- var transValidatorType = attribute.ConstructorArguments[0].Value as INamedTypeSymbol;
- if (transValidatorType != null)
- {
- if (CanValidate(transValidatorType, memberType))
- {
- if (transValidatorType.Constructors.Where(c => !c.Parameters.Any()).Any())
- {
- transValidatorTypeName = transValidatorType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
- }
- else
- {
- Diag(DiagDescriptors.ValidatorsNeedSimpleConstructor, attrLoc, transValidatorType.Name);
- }
- }
- else
- {
- Diag(DiagDescriptors.DoesntImplementIValidateOptions, attrLoc, transValidatorType.Name, memberType.Name);
- }
- }
- else
- {
- Diag(DiagDescriptors.NullValidatorType, attrLoc);
- }
- }
- else if (!_visitedModelTypes.Add(memberType.WithNullableAnnotation(NullableAnnotation.None)))
- {
- Diag(DiagDescriptors.CircularTypeReferences, attrLoc, memberType.ToString());
- speculate = false;
- continue;
- }
-
- if (transValidatorTypeName == null)
- {
- transValidatorIsSynthetic = true;
- transValidatorTypeName = AddSynthesizedValidator(memberType, member);
- }
-
- // pop the stack
- _ = _visitedModelTypes.Remove(memberType.WithNullableAnnotation(NullableAnnotation.None));
- }
- else if (SymbolEqualityComparer.Default.Equals(attributeType, _symbolHolder.ValidateEnumeratedItemsAttributeSymbol))
- {
- var enumeratedType = GetEnumeratedType(memberType);
- if (enumeratedType == null)
- {
- Diag(DiagDescriptors.NotEnumerableType, attrLoc, memberType);
- speculate = false;
- continue;
- }
-
- enumeratedIsNullable = enumeratedType.IsReferenceType || enumeratedType.NullableAnnotation == NullableAnnotation.Annotated;
- enumeratedIsValueType = enumeratedType.IsValueType;
- enumeratedMayBeNull = enumeratedType.NullableAnnotation == NullableAnnotation.Annotated;
-
- if (HasOpenGenerics(enumeratedType, out var genericType))
- {
- Diag(DiagDescriptors.CantUseWithGenericTypes, attrLoc, genericType);
- speculate = false;
- continue;
- }
-
- if (attribute.ConstructorArguments.Length == 1)
- {
- var enumerationValidatorType = attribute.ConstructorArguments[0].Value as INamedTypeSymbol;
- if (enumerationValidatorType != null)
- {
- if (CanValidate(enumerationValidatorType, enumeratedType))
- {
- if (enumerationValidatorType.Constructors.Where(c => c.Parameters.Length == 0).Any())
- {
- enumerationValidatorTypeName = enumerationValidatorType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
- }
- else
- {
- Diag(DiagDescriptors.ValidatorsNeedSimpleConstructor, attrLoc, enumerationValidatorType.Name);
- }
- }
- else
- {
- Diag(DiagDescriptors.DoesntImplementIValidateOptions, attrLoc, enumerationValidatorType.Name, enumeratedType.Name);
- }
- }
- else
- {
- Diag(DiagDescriptors.NullValidatorType, attrLoc);
- }
- }
- else if (!_visitedModelTypes.Add(enumeratedType.WithNullableAnnotation(NullableAnnotation.None)))
- {
- Diag(DiagDescriptors.CircularTypeReferences, attrLoc, enumeratedType.ToString());
- speculate = false;
- continue;
- }
-
- if (enumerationValidatorTypeName == null)
- {
- enumerationValidatorIsSynthetic = true;
- enumerationValidatorTypeName = AddSynthesizedValidator(enumeratedType, member);
- }
-
- // pop the stack
- _ = _visitedModelTypes.Remove(enumeratedType.WithNullableAnnotation(NullableAnnotation.None));
- }
- else if (DerivesFrom(attributeType, _symbolHolder.ValidationAttributeSymbol))
- {
- var validationAttr = new ValidationAttributeInfo(attributeType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
- validationAttrs.Add(validationAttr);
-
- foreach (var constructorArgument in attribute.ConstructorArguments)
- {
- validationAttr.ConstructorArguments.Add(GetArgumentExpression(constructorArgument.Type!, constructorArgument.Value));
- }
-
- foreach (var namedArgument in attribute.NamedArguments)
- {
- validationAttr.Properties.Add(namedArgument.Key, GetArgumentExpression(namedArgument.Value.Type!, namedArgument.Value.Value));
- }
- }
- }
-
- // generate a warning if the field/property seems like it should be transitively validated
- if (transValidatorTypeName == null && speculate && memberType.SpecialType == SpecialType.None)
- {
- if (!HasOpenGenerics(memberType, out var genericType))
- {
- var membersToValidate = GetMembersToValidate(memberType, false);
- if (membersToValidate.Count > 0)
- {
- Diag(DiagDescriptors.PotentiallyMissingTransitiveValidation, member.GetLocation(), memberType.Name, member.Name);
- }
- }
- }
-
- // generate a warning if the field/property seems like it should be enumerated
- if (enumerationValidatorTypeName == null && speculate)
- {
- var enumeratedType = GetEnumeratedType(memberType);
- if (enumeratedType != null)
- {
- if (!HasOpenGenerics(enumeratedType, out var genericType))
- {
- var membersToValidate = GetMembersToValidate(enumeratedType, false);
- if (membersToValidate.Count > 0)
- {
- Diag(DiagDescriptors.PotentiallyMissingEnumerableValidation, member.GetLocation(), enumeratedType.Name, member.Name);
- }
- }
- }
- }
-
- if (validationAttrs.Count > 0 || transValidatorTypeName != null || enumerationValidatorTypeName != null)
- {
- return new(
- member.Name,
- validationAttrs,
- transValidatorTypeName,
- transValidatorIsSynthetic,
- enumerationValidatorTypeName,
- enumerationValidatorIsSynthetic,
- memberType.IsReferenceType || memberType.NullableAnnotation == NullableAnnotation.Annotated,
- memberType.IsValueType,
- enumeratedIsNullable,
- enumeratedIsValueType,
- enumeratedMayBeNull);
- }
-
- return null;
- }
-
- private string? AddSynthesizedValidator(ITypeSymbol modelType, ISymbol member)
- {
- var mt = modelType.WithNullableAnnotation(NullableAnnotation.None);
- if (mt.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
- {
- // extract the T from a Nullable
- mt = ((INamedTypeSymbol)mt).TypeArguments[0];
- }
-
- if (_synthesizedValidators.TryGetValue(mt, out var validator))
- {
- return "global::" + validator.Namespace + "." + validator.Name;
- }
-
- var membersToValidate = GetMembersToValidate(mt, true);
- if (membersToValidate.Count == 0)
- {
- // this type lacks any eligible members
- Diag(DiagDescriptors.NoEligibleMember, member.GetLocation(), mt.ToString(), member.ToString());
- return null;
- }
-
- var model = new ValidatedModel(
- GetFQN(mt),
- mt.Name,
- false,
- membersToValidate);
-
- var validatorTypeName = "__" + mt.Name + "Validator__";
-
- var result = new ValidatorType(
- mt.ContainingNamespace.IsGlobalNamespace ? string.Empty : mt.ContainingNamespace.ToString(),
- validatorTypeName,
- validatorTypeName,
- "class",
- new List(),
- true,
- new[] { model });
-
- _synthesizedValidators[mt] = result;
- return "global::" + (result.Namespace.Length > 0 ? result.Namespace + "." + result.Name : result.Name);
- }
-
- private bool DerivesFrom(ITypeSymbol source, ITypeSymbol dest)
- {
- var conversion = _compilation.ClassifyConversion(source, dest);
- return conversion.IsReference && conversion.IsImplicit;
- }
-
- private bool ModelSelfValidates(ITypeSymbol modelType)
- {
- foreach (var implementingInterface in modelType.AllInterfaces)
- {
- if (SymbolEqualityComparer.Default.Equals(implementingInterface.OriginalDefinition, _symbolHolder.IValidatableObjectSymbol))
- {
- return true;
- }
- }
-
- return false;
- }
-
- private List GetModelTypes(ITypeSymbol validatorType)
- {
- var result = new List();
- foreach (var implementingInterface in validatorType.AllInterfaces)
- {
- if (SymbolEqualityComparer.Default.Equals(implementingInterface.OriginalDefinition, _symbolHolder.ValidateOptionsSymbol))
- {
- result.Add(implementingInterface.TypeArguments.First());
- }
- }
-
- return result;
- }
-
- private bool CanValidate(ITypeSymbol validatorType, ISymbol modelType)
- {
- foreach (var implementingInterface in validatorType.AllInterfaces)
- {
- if (SymbolEqualityComparer.Default.Equals(implementingInterface.OriginalDefinition, _symbolHolder.ValidateOptionsSymbol))
- {
- var t = implementingInterface.TypeArguments.First();
- if (SymbolEqualityComparer.Default.Equals(modelType, t))
- {
- return true;
- }
- }
- }
-
- return false;
- }
-
- private string GetArgumentExpression(ITypeSymbol type, object? value)
- {
- if (value == null)
- {
- return "null";
- }
-
- if (type.SpecialType == SpecialType.System_Boolean)
- {
- return (bool)value ? "true" : "false";
- }
-
- if (SymbolEqualityComparer.Default.Equals(type, _symbolHolder.TypeSymbol) &&
- value is INamedTypeSymbol sym)
- {
- return $"typeof({sym.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)})";
- }
-
- if (type.SpecialType == SpecialType.System_String)
- {
- return $@"""{EscapeString(value.ToString())}""";
- }
-
- if (type.SpecialType == SpecialType.System_Char)
- {
- return $@"'{EscapeString(value.ToString())}'";
- }
-
- return $"({type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}){Convert.ToString(value, CultureInfo.InvariantCulture)}";
- }
-
- private static readonly char[] _specialChars = { '\n', '\r', '"', '\\' };
-
- private static string EscapeString(string s)
- {
- int index = s.IndexOfAny(_specialChars);
- if (index < 0)
- {
- return s;
- }
-
- var sb = new StringBuilder(s.Length);
- _ = sb.Append(s, 0, index);
-
- while (index < s.Length)
- {
- _ = s[index] switch
- {
- '\n' => sb.Append("\\n"),
- '\r' => sb.Append("\\r"),
- '"' => sb.Append("\\\""),
- '\\' => sb.Append("\\\\"),
- var other => sb.Append(other),
- };
-
- index++;
- }
-
- return sb.ToString();
- }
-
- private void Diag(DiagnosticDescriptor desc, Location? location)
- {
- _reportDiagnostic(Diagnostic.Create(desc, location, Array.Empty