diff --git a/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs b/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs index 2b4568a79eaba0..e67289721d8af9 100644 --- a/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs +++ b/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs @@ -91,7 +91,7 @@ public static async Task AssertNoDiagnostic(this Project proj, params string[] i } } - private static Project WithDocuments(this Project project, IEnumerable sources, IEnumerable? sourceNames = null) + public static Project WithDocuments(this Project project, IEnumerable sources, IEnumerable? sourceNames = null) { int count = 0; Project result = project; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs index 909272c7678447..60ce9f681e077f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs @@ -142,7 +142,7 @@ private void EmitInterceptsLocationAnnotations(List inf { foreach (InterceptorLocationInfo info in infoList) { - _writer.WriteLine($@"[{Identifier.InterceptsLocation}Attribute(@""{info.FilePath}"", {info.LineNumber}, {info.CharacterNumber})]"); + _writer.WriteLine($@"[{Identifier.InterceptsLocation}(@""{info.FilePath}"", {info.LineNumber}, {info.CharacterNumber})]"); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs index b811a8e6ae0eca..d89b124b0695fb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs @@ -85,9 +85,12 @@ @params[1].Type.SpecialType is SpecialType.System_String && private void RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection overload, TypeSpec typeSpec) { + RegisterTypeForBindCoreMainGen(typeSpec); + _sourceGenSpec.MethodsToGen_ServiceCollectionExt |= overload; _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection"); - RegisterTypeForBindCoreMainGen(typeSpec); + // Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource, IConfigureOptions<>, ConfigureNamedOptions<>. + _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options"); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt index 5f186e42e4da7d..775d9052ded435 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt @@ -32,7 +32,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 12, 17)] + [InterceptsLocation(@"src-0.cs", 12, 17)] public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt index 8d1f02b4e62e11..e5b37775cffd4b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] + [InterceptsLocation(@"src-0.cs", 12, 14)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { if (configuration is null) @@ -49,7 +49,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] + [InterceptsLocation(@"src-0.cs", 13, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance, Action? configureOptions) { if (configuration is null) @@ -67,7 +67,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + [InterceptsLocation(@"src-0.cs", 14, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? instance) { if (configuration is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt index f3008878ca3c56..fc35d29e693349 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { if (configuration is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt index 19b955b6ea8bff..0d3eb884c966e2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance, Action? configureOptions) { if (configuration is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt index 8533828221175b..392533daea462f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? instance) { if (configuration is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt index 4acbebff935bca..d0faaa8fc91513 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt @@ -31,19 +31,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 12, 38)] + [InterceptsLocation(@"src-0.cs", 12, 38)] public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 14, 36)] + [InterceptsLocation(@"src-0.cs", 14, 36)] public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 13, 36)] + [InterceptsLocation(@"src-0.cs", 13, 56)] public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 15, 36)] + [InterceptsLocation(@"src-0.cs", 15, 47)] public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt index e4bcaf6a9b7c95..bf7e64bd31f90c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt @@ -30,19 +30,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] + [InterceptsLocation(@"src-0.cs", 13, 18)] public static T? GetValue(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T)); /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 16, 24)] + [InterceptsLocation(@"src-0.cs", 16, 24)] public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] + [InterceptsLocation(@"src-0.cs", 14, 24)] public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key); /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 17, 24)] + [InterceptsLocation(@"src-0.cs", 17, 24)] public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt index 2438cf530ca4ce..b86915b78303b2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 10, 20)] + [InterceptsLocation(@"src-0.cs", 10, 20)] public static T? GetValue(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T)); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt index e6db24d522f3c9..697f710dff3027 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt index a36f9fafebcff8..b5a22e71ccefbf 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 10, 20)] + [InterceptsLocation(@"src-0.cs", 10, 20)] public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt index 356f6bb1a933e2..4a4564796e562f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 11, 20)] + [InterceptsLocation(@"src-0.cs", 11, 20)] public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt index fb5cf5e4b5ca31..0b7031b1da00ba 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + [InterceptsLocation(@"src-0.cs", 11, 40)] public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt index ac8e362b4e2e07..4c950a79266d11 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + [InterceptsLocation(@"src-0.cs", 11, 40)] public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt index 5d0088b908162d..ca323c234b8485 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + [InterceptsLocation(@"src-0.cs", 11, 51)] public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt index 9da3a3a22e9b7c..e4a376a0cb3257 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 20)] + [InterceptsLocation(@"src-0.cs", 11, 20)] public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt index 96e389be895602..f3829683be2bb3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt @@ -33,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region OptionsBuilder extensions. /// Registers the dependency injection container to bind against the obtained from the DI service provider. - [InterceptsLocationAttribute(@"src-0.cs", 12, 24)] + [InterceptsLocation(@"src-0.cs", 12, 24)] public static OptionsBuilder BindConfiguration(this OptionsBuilder optionsBuilder, string configSectionPath, Action? configureBinder = null) where TOptions : class { if (optionsBuilder is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt index 9755ab0df00086..de6ea5a3b9e1c6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt @@ -33,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region OptionsBuilder extensions. /// Registers a configuration instance which will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + [InterceptsLocation(@"src-0.cs", 15, 24)] public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config) where TOptions : class { return Bind(optionsBuilder, config, configureBinder: null); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt index 141d2d41f77f83..2c40ebf69c9b46 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt @@ -33,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region OptionsBuilder extensions. /// Registers a configuration instance which will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + [InterceptsLocation(@"src-0.cs", 15, 24)] public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config, Action? configureBinder) where TOptions : class { if (optionsBuilder is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt index 1fd82a86d72c0d..7d94145d42a511 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 13, 16)] + [InterceptsLocation(@"src-0.cs", 13, 16)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { if (configuration is null) @@ -50,7 +50,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #endregion IConfiguration extensions. #region Core binding extensions. - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22", "Prop28", "Prop29", "Prop30" }); public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { @@ -142,12 +142,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (configuration["Prop23"] is string value18) { - instance.Prop23 = ParseInt(value18, () => configuration.GetSection("Prop23").Path); + instance.Prop23 = ParseTimeSpan(value18, () => configuration.GetSection("Prop23").Path); } if (configuration["Prop24"] is string value19) { - instance.Prop24 = ParseDateTime(value19, () => configuration.GetSection("Prop24").Path); + instance.Prop24 = ParseGuid(value19, () => configuration.GetSection("Prop24").Path); } if (configuration["Prop25"] is string value20) @@ -187,7 +187,22 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (configuration["Prop22"] is string value27) { - instance.Prop22 = ParseByteArray(value27, () => configuration.GetSection("Prop22").Path); + instance.Prop22 = ParseTimeOnly(value27, () => configuration.GetSection("Prop22").Path); + } + + if (configuration["Prop28"] is string value28) + { + instance.Prop28 = ParseByteArray(value28, () => configuration.GetSection("Prop28").Path); + } + + if (configuration["Prop29"] is string value29) + { + instance.Prop29 = ParseInt(value29, () => configuration.GetSection("Prop29").Path); + } + + if (configuration["Prop30"] is string value30) + { + instance.Prop30 = ParseDateTime(value30, () => configuration.GetSection("Prop30").Path); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt index 0ff2de59156df9..973895e09fe55e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, IConfiguration config) where TOptions : class { return Configure(services, string.Empty, config, configureOptions: null); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt index 7058edb884007f..08f233aff5503b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, IConfiguration config, Action? configureOptions) where TOptions : class { return Configure(services, string.Empty, config, configureOptions); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt index a8f247779978ca..cb41ea860980a9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config) where TOptions : class { return Configure(services, name, config, configureOptions: null); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt index 0cbd2fba049558..0a5e5a7ff6d26c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { if (services is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs index 0126744eacbfa4..c3d1ce89c1206f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs @@ -20,7 +20,7 @@ public static void Main() { ConfigurationBuilder configurationBuilder = new(); IConfiguration config = configurationBuilder.Build(); - IConfigurationSection section = config.GetSection(""MySection""); + IConfigurationSection section = config.GetSection("MySection"); ServiceCollection services = new(); services.Configure({{paramList}}); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index 65e812d30b420f..7b3251e7fc85dc 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -5,46 +5,15 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Xunit; namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests { public partial class ConfigurationBindingGeneratorTests { - private const string BindCallSampleCode = @" - using System.Collections.Generic; - using Microsoft.Extensions.Configuration; - - public class Program - { - public static void Main() - { - ConfigurationBuilder configurationBuilder = new(); - IConfigurationRoot config = configurationBuilder.Build(); - - MyClass configObj = new(); - config.Bind(configObj); - config.Bind(configObj, options => { }); - config.Bind(""key"", configObj); - } - - public class MyClass - { - public string MyString { get; set; } - public int MyInt { get; set; } - public List MyList { get; set; } - public Dictionary MyDictionary { get; set; } - public Dictionary MyComplexDictionary { get; set; } - } - - public class MyClass2 { } - }"; - - [Theory] - [InlineData(LanguageVersion.Preview)] - public async Task Bind(LanguageVersion langVersion) => - await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder); + [Fact] + public async Task Bind() => + await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, extType: ExtensionClassType.ConfigurationBinder); [Fact] public async Task Bind_Instance() @@ -163,9 +132,9 @@ public static void Main() IConfigurationRoot config = configurationBuilder.Build(); MyClass configObj = config.Get(); - configObj = config.Get(typeof(MyClass2)); + MyClass2 configObj2 = (MyClass2)config.Get(typeof(MyClass2)); configObj = config.Get(binderOptions => { }); - configObj = config.Get(typeof(MyClass2), binderOptions => { }); + configObj2 = (MyClass2)config.Get(typeof(MyClass2), binderOptions => { }); } public class MyClass @@ -302,7 +271,7 @@ public static void Main() ConfigurationBuilder configurationBuilder = new(); IConfigurationRoot config = configurationBuilder.Build(); - MyClass configObj = config.Get(typeof(MyClass2)); + MyClass2 configObj = (MyClass2)config.Get(typeof(MyClass2)); } public class MyClass @@ -590,9 +559,9 @@ public class MyClass public UInt128 Prop12 { get; set; } public DateOnly Prop18 { get; set; } public TimeOnly Prop22 { get; set; } - public byte[] Prop22 { get; set; } - public int Prop23 { get; set; } - public DateTime Prop24 { get; set; } + public byte[] Prop28 { get; set; } + public int Prop29 { get; set; } + public DateTime Prop30 { get; set; } } } """; @@ -613,7 +582,7 @@ public static void Main() { ConfigurationBuilder configurationBuilder = new(); IConfiguration config = configurationBuilder.Build(); - IConfigurationSection section = config.GetSection(""MySection""); + IConfigurationSection section = config.GetSection("MySection"); section.Get(); } @@ -647,7 +616,7 @@ public interface ICustomSet : ISet } """; - await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, assessDiagnostics: (d) => + await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, validateOutputCompDiags: false, assessDiagnostics: (d) => { Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs new file mode 100644 index 00000000000000..d8818bcf3c1d4c --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs @@ -0,0 +1,171 @@ +// 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; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Binder.SourceGeneration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using SourceGenerators.Tests; +using Xunit; + +namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests +{ + public partial class ConfigurationBindingGeneratorTests + { + private const string BindCallSampleCode = """ + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass configObj = new(); + config.Bind(configObj); + config.Bind(configObj, options => { }); + config.Bind("key", configObj); + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + public Dictionary MyComplexDictionary { get; set; } + } + + public class MyClass2 { } + } + """; + + private static class Diagnostics + { + public static (string Id, string Title) TypeNotSupported = ("SYSLIB1100", "Did not generate binding logic for a type"); + public static (string Id, string Title) PropertyNotSupported = ("SYSLIB1101", "Did not generate binding logic for a property on a type"); + public static (string Id, string Title) ValueTypesInvalidForBind = ("SYSLIB1103", "Value types are invalid inputs to configuration 'Bind' methods"); + public static (string Id, string Title) CouldNotDetermineTypeInfo = ("SYSLIB1104", "The target type for a binder call could not be determined"); + } + + private static readonly Assembly[] s_compilationAssemblyRefs = new[] { + typeof(ConfigurationBinder).Assembly, + typeof(ConfigurationBuilder).Assembly, + typeof(CultureInfo).Assembly, + typeof(Dictionary<,>).Assembly, + typeof(Enumerable).Assembly, + typeof(IConfiguration).Assembly, + typeof(IServiceCollection).Assembly, + typeof(IServiceProvider).Assembly, + typeof(IDictionary).Assembly, + typeof(OptionsBuilder<>).Assembly, + typeof(OptionsConfigurationServiceCollectionExtensions).Assembly, + typeof(Uri).Assembly, + }; + + private enum ExtensionClassType + { + None, + ConfigurationBinder, + OptionsBuilder, + ServiceCollection, + } + + private static async Task VerifyAgainstBaselineUsingFile( + string filename, + string testSourceCode, + Action>? assessDiagnostics = null, + ExtensionClassType extType = ExtensionClassType.None, + bool validateOutputCompDiags = true) + { + string path = extType is ExtensionClassType.None + ? Path.Combine("Baselines", filename) + : Path.Combine("Baselines", extType.ToString(), filename); + string baseline = LineEndingsHelper.Normalize(await File.ReadAllTextAsync(path).ConfigureAwait(false)); + string[] expectedLines = baseline.Replace("%VERSION%", typeof(ConfigurationBindingGenerator).Assembly.GetName().Version?.ToString()) + .Split(Environment.NewLine); + + var (d, r) = await RunGenerator(testSourceCode, validateOutputCompDiags); + bool success = RoslynTestUtils.CompareLines(expectedLines, r[0].SourceText, out string errorMessage); + +#if UPDATE_BASELINES + if (!success) + { + string? repoRootDir = Environment.GetEnvironmentVariable("RepoRootDir"); + Assert.True(repoRootDir is not null, "To update baselines, specifiy the root runtime repo dir"); + + IEnumerable lines = r[0].SourceText.Lines.Select(l => l.ToString()); + string source = string.Join(Environment.NewLine, lines).TrimEnd(Environment.NewLine.ToCharArray()) + Environment.NewLine; + path = Path.Combine($"{repoRootDir}\\src\\libraries\\Microsoft.Extensions.Configuration.Binder\\tests\\SourceGenerationTests\\", path); + + await File.WriteAllTextAsync(path, source).ConfigureAwait(false); + success = true; + } +#endif + + Assert.Single(r); + (assessDiagnostics ?? ((d) => Assert.Empty(d))).Invoke(d); + Assert.True(success, errorMessage); + } + + private static async Task<(ImmutableArray, ImmutableArray)> RunGenerator( + string testSourceCode, + bool validateOutputCompDiags = false, + LanguageVersion langVersion = LanguageVersion.CSharp12, + IEnumerable? references = null) + { + using var workspace = RoslynTestUtils.CreateTestWorkspace(); + CSharpParseOptions parseOptions = new CSharpParseOptions(langVersion).WithFeatures(new[] { new KeyValuePair("InterceptorsPreview", "") }); + + Project proj = RoslynTestUtils.CreateTestProject(workspace, references ?? s_compilationAssemblyRefs, langVersion: langVersion) + .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Annotations)) + .WithDocuments(new string[] { testSourceCode }) + .WithParseOptions(parseOptions); + + Assert.True(proj.Solution.Workspace.TryApplyChanges(proj.Solution)); + + Compilation comp = await proj.GetCompilationAsync(CancellationToken.None).ConfigureAwait(false); + CSharpGeneratorDriver cgd = CSharpGeneratorDriver.Create(new[] { new ConfigurationBindingGenerator().AsSourceGenerator() }, parseOptions: parseOptions); + GeneratorDriver gd = cgd.RunGeneratorsAndUpdateCompilation(comp, out Compilation outputCompilation, out _, CancellationToken.None); + GeneratorDriverRunResult runResult = gd.GetRunResult(); + + if (validateOutputCompDiags) + { + Assert.False(outputCompilation.GetDiagnostics().Any(d => d.Severity > DiagnosticSeverity.Info)); + } + + return (runResult.Results[0].Diagnostics, runResult.Results[0].GeneratedSources); + } + + public static List GetAssemblyRefsWithAdditional(params Type[] additional) + { + List assemblies = new(s_compilationAssemblyRefs); + assemblies.AddRange(additional.Select(t => t.Assembly)); + return assemblies; + } + + public static HashSet GetFilteredAssemblyRefs(IEnumerable exclusions) + { + HashSet assemblies = new(s_compilationAssemblyRefs); + foreach (Type exclusion in exclusions) + { + assemblies.Remove(exclusion.Assembly); + } + return assemblies; + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index 33a4d04834b57a..3fddad379397ef 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -6,19 +6,15 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; -using System.IO; using System.Linq; -using System.Reflection; using System.Text; using System.Text.Json; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Configuration.Binder.SourceGeneration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using SourceGenerators.Tests; using Xunit; namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests @@ -26,39 +22,12 @@ namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests [ActiveIssue("https://github.com/dotnet/runtime/issues/52062", TestPlatforms.Browser)] public partial class ConfigurationBindingGeneratorTests : ConfigurationBinderTestsBase { - private static class Diagnostics - { - public static (string Id, string Title) TypeNotSupported = ("SYSLIB1100", "Did not generate binding logic for a type"); - public static (string Id, string Title) PropertyNotSupported = ("SYSLIB1101", "Did not generate binding logic for a property on a type"); - public static (string Id, string Title) ValueTypesInvalidForBind = ("SYSLIB1103", "Value types are invalid inputs to configuration 'Bind' methods"); - public static (string Id, string Title) CouldNotDetermineTypeInfo = ("SYSLIB1104", "The target type for a binder call could not be determined"); - } - - private static readonly Assembly[] s_compilationAssemblyRefs = new[] { - typeof(ConfigurationBinder).Assembly, - typeof(CultureInfo).Assembly, - typeof(IConfiguration).Assembly, - typeof(IServiceCollection).Assembly, - typeof(IDictionary).Assembly, - typeof(OptionsBuilder<>).Assembly, - typeof(OptionsConfigurationServiceCollectionExtensions).Assembly, - typeof(Uri).Assembly, - }; - - private enum ExtensionClassType - { - None, - ConfigurationBinder, - OptionsBuilder, - ServiceCollection, - } - [Theory] [InlineData(LanguageVersion.CSharp11)] [InlineData(LanguageVersion.CSharp10)] public async Task LangVersionMustBeCharp12OrHigher(LanguageVersion langVersion) { - var (d, r) = await RunGenerator(BindCallSampleCode, langVersion); + var (d, r) = await RunGenerator(BindCallSampleCode, langVersion: langVersion); Assert.Empty(r); Diagnostic diagnostic = Assert.Single(d); @@ -371,69 +340,5 @@ public class AnotherGraphWithUnsupportedMembers Assert.Equal(12, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); Assert.Equal(10, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); } - - private static async Task VerifyAgainstBaselineUsingFile( - string filename, - string testSourceCode, - LanguageVersion languageVersion = LanguageVersion.Preview, - Action>? assessDiagnostics = null, - ExtensionClassType extType = ExtensionClassType.None) - { - string path = extType is ExtensionClassType.None - ? Path.Combine("Baselines", filename) - : Path.Combine("Baselines", extType.ToString(), filename); - string baseline = LineEndingsHelper.Normalize(await File.ReadAllTextAsync(path).ConfigureAwait(false)); - string[] expectedLines = baseline.Replace("%VERSION%", typeof(ConfigurationBindingGenerator).Assembly.GetName().Version?.ToString()) - .Split(Environment.NewLine); - - var (d, r) = await RunGenerator(testSourceCode, languageVersion); - bool success = RoslynTestUtils.CompareLines(expectedLines, r[0].SourceText, out string errorMessage); - -#if UPDATE_BASELINES - if (!success) - { - string? repoRootDir = Environment.GetEnvironmentVariable("RepoRootDir"); - Assert.True(repoRootDir is not null, "To update baselines, specifiy the root runtime repo dir"); - - IEnumerable lines = r[0].SourceText.Lines.Select(l => l.ToString()); - string source = string.Join(Environment.NewLine, lines).TrimEnd(Environment.NewLine.ToCharArray()) + Environment.NewLine; - path = Path.Combine($"{repoRootDir}\\src\\libraries\\Microsoft.Extensions.Configuration.Binder\\tests\\SourceGenerationTests\\", path); - - await File.WriteAllTextAsync(path, source).ConfigureAwait(false); - success = true; - } -#endif - - Assert.Single(r); - (assessDiagnostics ?? ((d) => Assert.Empty(d))).Invoke(d); - Assert.True(success, errorMessage); - } - - private static async Task<(ImmutableArray, ImmutableArray)> RunGenerator( - string testSourceCode, - LanguageVersion langVersion = LanguageVersion.Preview, - IEnumerable? references = null) => - await RoslynTestUtils.RunGenerator( - new ConfigurationBindingGenerator(), - references ?? s_compilationAssemblyRefs, - new[] { testSourceCode }, - langVersion: langVersion).ConfigureAwait(false); - - public static List GetAssemblyRefsWithAdditional(params Type[] additional) - { - List assemblies = new(s_compilationAssemblyRefs); - assemblies.AddRange(additional.Select(t => t.Assembly)); - return assemblies; - } - - public static HashSet GetFilteredAssemblyRefs(IEnumerable exclusions) - { - HashSet assemblies = new(s_compilationAssemblyRefs); - foreach (Type exclusion in exclusions) - { - assemblies.Remove(exclusion.Assembly); - } - return assemblies; - } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index 94d95564a47352..49ee1c1f968c06 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -54,6 +54,7 @@ +