Update binder gen parser to issue diagnostics for invalid input types (#86856)
authorLayomi Akinrinade <laakinri@microsoft.com>
Thu, 1 Jun 2023 16:33:36 +0000 (09:33 -0700)
committerGitHub <noreply@github.com>
Thu, 1 Jun 2023 16:33:36 +0000 (09:33 -0700)
* Update binder gen parser to issue diagnostics for invalid input types

* Address feedback; tests for more invalid types; fix failing CI test

28 files changed:
docs/project/list-of-diagnostics.md
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter.ExceptionMessages.cs [new file with mode: 0644]
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/ExceptionMessages.cs [deleted file]
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser.Diagnostics.cs [new file with mode: 0644]
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/ParserDiagnostics.cs [deleted file]
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs [moved from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/KnownTypeSymbols.cs with 100% similarity]
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.Collections.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingSourceGeneratorTests.cs
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj

index 7c814cd..d6783d8 100644 (file)
@@ -219,8 +219,8 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL
 |  __`SYSLIB1100`__ | Configuration binding generator: type is not supported. |
 |  __`SYSLIB1101`__ | Configuration binding generator: property on type is not supported. |
 |  __`SYSLIB1102`__ | Configuration binding generator: project's language version must be at least C# 11.|
-|  __`SYSLIB1103`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
-|  __`SYSLIB1104`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
+|  __`SYSLIB1103`__ | Configuration binding generator: value types are invalid inputs to configuration 'Bind' methods.* |
+|  __`SYSLIB1104`__ | Configuration binding generator: Generator cannot determine the target configuration type.* |
 |  __`SYSLIB1105`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
 |  __`SYSLIB1106`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
 |  __`SYSLIB1107`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
index 020c110..4064232 100644 (file)
@@ -7,7 +7,6 @@ using System.Collections.Immutable;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
-using System.Runtime.CompilerServices;
 using Microsoft.CodeAnalysis;
 using Microsoft.CodeAnalysis.Operations;
 
@@ -15,7 +14,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 {
     public sealed partial class ConfigurationBindingGenerator
     {
-        private sealed class Parser
+        private sealed partial class Parser
         {
             private readonly SourceProductionContext _context;
             private readonly KnownTypeSymbols _typeSymbols;
@@ -140,18 +139,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 }
 
                 ITypeSymbol? type = ResolveType(objectArg.Value)?.WithNullableAnnotation(NullableAnnotation.None);
-                INamedTypeSymbol? namedType;
 
-                if ((namedType = type as INamedTypeSymbol) is null ||
-                    namedType.SpecialType == SpecialType.System_Object ||
-                    namedType.SpecialType == SpecialType.System_Void ||
-                    // Binding to root-level struct is a no-op.
-                    namedType.IsValueType)
+                if (!IsValidRootConfigType(overload, type, binderOperation.Location))
                 {
                     return;
                 }
 
-                AddRootConfigType(methodGroup: BinderMethodSpecifier.Bind, overload, namedType, binderOperation.Location);
+                if (type.IsValueType)
+                {
+                    _context.ReportDiagnostic(Diagnostic.Create(Diagnostics.ValueTypesInvalidForBind, binderOperation.Location, type));
+                    return;
+                }
+
+                AddRootConfigType(methodGroup: BinderMethodSpecifier.Bind, overload, type, binderOperation.Location);
 
                 static ITypeSymbol? ResolveType(IOperation conversionOperation) =>
                     conversionOperation switch
@@ -180,7 +180,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 }
 
                 BinderMethodSpecifier overload = BinderMethodSpecifier.None;
-                INamedTypeSymbol? namedType;
+                ITypeSymbol? type;
 
                 if (targetMethod.IsGenericMethod)
                 {
@@ -189,7 +189,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                         return;
                     }
 
-                    namedType = targetMethod.TypeArguments[0].WithNullableAnnotation(NullableAnnotation.None) as INamedTypeSymbol;
+                    type = targetMethod.TypeArguments[0].WithNullableAnnotation(NullableAnnotation.None);
 
                     if (paramLength is 1)
                     {
@@ -207,7 +207,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 else
                 {
                     ITypeOfOperation? typeOfOperation = operation.Arguments[1].ChildOperations.FirstOrDefault() as ITypeOfOperation;
-                    namedType = typeOfOperation?.TypeOperand as INamedTypeSymbol;
+                    type = typeOfOperation?.TypeOperand;
 
                     if (paramLength is 2)
                     {
@@ -219,15 +219,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     }
                 }
 
-                if (overload is BinderMethodSpecifier.None ||
-                    namedType is null ||
-                    namedType.SpecialType == SpecialType.System_Object ||
-                    namedType.SpecialType == SpecialType.System_Void)
+                if (!IsValidRootConfigType(overload, type, binderOperation.Location))
                 {
                     return;
                 }
 
-                AddRootConfigType(methodGroup: BinderMethodSpecifier.Get, overload, namedType, binderOperation.Location);
+                AddRootConfigType(methodGroup: BinderMethodSpecifier.Get, overload, type, binderOperation.Location);
             }
 
             private void ProcessGetValueCall(BinderInvocationOperation binderOperation)
@@ -282,15 +279,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     }
                 }
 
-                if (overload is BinderMethodSpecifier.None ||
-                    type is null ||
-                    type.SpecialType == SpecialType.System_Object ||
-                    type.SpecialType == SpecialType.System_Void)
+                if (!IsValidRootConfigType(overload, type, binderOperation.Location))
                 {
                     return;
                 }
 
-                ITypeSymbol effectiveType = IsNullable(type, out ITypeSymbol? underlyingType) ? underlyingType : type;
+                ITypeSymbol effectiveType = (IsNullable(type, out ITypeSymbol? underlyingType) ? underlyingType : type)!;
                 if (IsParsableFromString(effectiveType, out _))
                 {
                     AddRootConfigType(methodGroup: BinderMethodSpecifier.GetValue, overload, type, binderOperation.Location);
@@ -310,23 +304,38 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     SymbolEqualityComparer.Default.Equals(_typeSymbols.IConfiguration, @params[1].Type))
                 {
                     ITypeSymbol? type = targetMethod.TypeArguments[0].WithNullableAnnotation(NullableAnnotation.None);
-                    if (type is not INamedTypeSymbol namedType ||
-                        namedType.SpecialType == SpecialType.System_Object)
+
+                    if (!IsValidRootConfigType(BinderMethodSpecifier.Configure, type, binderOperation.Location))
                     {
                         return;
                     }
 
-                    AddRootConfigType(methodGroup: BinderMethodSpecifier.Configure, overload: BinderMethodSpecifier.Configure, namedType, binderOperation.Location);
+                    AddRootConfigType(methodGroup: BinderMethodSpecifier.Configure, overload: BinderMethodSpecifier.Configure, type, binderOperation.Location);
                 }
             }
 
-            private void AddRootConfigType(BinderMethodSpecifier methodGroup, BinderMethodSpecifier overload, ITypeSymbol type, Location? location)
+            private bool IsValidRootConfigType(BinderMethodSpecifier overload, ITypeSymbol? type, Location? location)
             {
-                if (type is INamedTypeSymbol namedType && ContainsGenericParameters(namedType))
+                if (overload is BinderMethodSpecifier.None)
                 {
-                    return;
+                    return false;
+                }
+
+                if (type is null ||
+                    type.SpecialType is SpecialType.System_Object or SpecialType.System_Void ||
+                    type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error ||
+                    type.IsRefLikeType ||
+                    ContainsGenericParameters(type))
+                {
+                    _context.ReportDiagnostic(Diagnostic.Create(Diagnostics.CouldNotDetermineTypeInfo, location));
+                    return false;
                 }
 
+                return true;
+            }
+
+            private void AddRootConfigType(BinderMethodSpecifier methodGroup, BinderMethodSpecifier overload, ITypeSymbol type, Location? location)
+            {
                 if (GetOrCreateTypeSpec(type, location) is TypeSpec spec)
                 {
                     RegisterConfigType(spec, overload);
@@ -345,7 +354,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 if (IsNullable(type, out ITypeSymbol? underlyingType))
                 {
-                    spec = TryGetTypeSpec(underlyingType, ParserDiagnostics.NullableUnderlyingTypeNotSupported, out TypeSpec? underlyingTypeSpec)
+                    spec = TryGetTypeSpec(underlyingType, Diagnostics.NullableUnderlyingTypeNotSupported, out TypeSpec? underlyingTypeSpec)
                         ? new NullableSpec(type) { Location = location, UnderlyingType = underlyingTypeSpec }
                         : null;
                 }
@@ -386,7 +395,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 if (spec is null)
                 {
-                    ReportUnsupportedType(type, ParserDiagnostics.TypeNotSupported, location);
+                    ReportUnsupportedType(type, Diagnostics.TypeNotSupported, location);
                     return null;
                 }
 
@@ -562,7 +571,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
             private EnumerableSpec? CreateArraySpec(IArrayTypeSymbol arrayType, Location? location)
             {
-                if (!TryGetTypeSpec(arrayType.ElementType, ParserDiagnostics.ElementTypeNotSupported, out TypeSpec elementSpec))
+                if (!TryGetTypeSpec(arrayType.ElementType, Diagnostics.ElementTypeNotSupported, out TypeSpec elementSpec))
                 {
                     return null;
                 }
@@ -594,7 +603,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 if (arrayType.Rank > 1)
                 {
-                    ReportUnsupportedType(arrayType, ParserDiagnostics.MultiDimArraysNotSupported, location);
+                    ReportUnsupportedType(arrayType, Diagnostics.MultiDimArraysNotSupported, location);
                     return false;
                 }
 
@@ -624,15 +633,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
             private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, Location? location, ITypeSymbol keyType, ITypeSymbol elementType)
             {
-                if (!TryGetTypeSpec(keyType, ParserDiagnostics.DictionaryKeyNotSupported, out TypeSpec keySpec) ||
-                    !TryGetTypeSpec(elementType, ParserDiagnostics.ElementTypeNotSupported, out TypeSpec elementSpec))
+                if (!TryGetTypeSpec(keyType, Diagnostics.DictionaryKeyNotSupported, out TypeSpec keySpec) ||
+                    !TryGetTypeSpec(elementType, Diagnostics.ElementTypeNotSupported, out TypeSpec elementSpec))
                 {
                     return null;
                 }
 
                 if (keySpec.SpecKind != TypeSpecKind.ParsableFromString)
                 {
-                    ReportUnsupportedType(type, ParserDiagnostics.DictionaryKeyNotSupported, location);
+                    ReportUnsupportedType(type, Diagnostics.DictionaryKeyNotSupported, location);
                     return null;
                 }
 
@@ -657,7 +666,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     }
                     else
                     {
-                        ReportUnsupportedType(type, ParserDiagnostics.CollectionNotSupported, location);
+                        ReportUnsupportedType(type, Diagnostics.CollectionNotSupported, location);
                         return null;
                     }
                 }
@@ -678,7 +687,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 }
                 else
                 {
-                    ReportUnsupportedType(type, ParserDiagnostics.CollectionNotSupported, location);
+                    ReportUnsupportedType(type, Diagnostics.CollectionNotSupported, location);
                     return null;
                 }
 
@@ -702,7 +711,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
             private EnumerableSpec? CreateEnumerableSpec(INamedTypeSymbol type, Location? location)
             {
                 if (!TryGetElementType(type, out ITypeSymbol? elementType) ||
-                    !TryGetTypeSpec(elementType, ParserDiagnostics.ElementTypeNotSupported, out TypeSpec elementSpec))
+                    !TryGetTypeSpec(elementType, Diagnostics.ElementTypeNotSupported, out TypeSpec elementSpec))
                 {
                     return null;
                 }
@@ -727,7 +736,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     }
                     else
                     {
-                        ReportUnsupportedType(type, ParserDiagnostics.CollectionNotSupported, location);
+                        ReportUnsupportedType(type, Diagnostics.CollectionNotSupported, location);
                         return null;
                     }
                 }
@@ -767,7 +776,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 }
                 else
                 {
-                    ReportUnsupportedType(type, ParserDiagnostics.CollectionNotSupported, location);
+                    ReportUnsupportedType(type, Diagnostics.CollectionNotSupported, location);
                     return null;
                 }
 
@@ -829,8 +838,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                     bool hasPublicParameterlessCtor = type.IsValueType || parameterlessCtor is not null;
                     if (!hasPublicParameterlessCtor && hasMultipleParameterizedCtors)
                     {
-                        diagnosticDescriptor = ParserDiagnostics.MultipleParameterizedConstructors;
-                        objectSpec.InitExceptionMessage = string.Format(ExceptionMessages.MultipleParameterizedConstructors, typeName);
+                        diagnosticDescriptor = Diagnostics.MultipleParameterizedConstructors;
+                        objectSpec.InitExceptionMessage = string.Format(Emitter.ExceptionMessages.MultipleParameterizedConstructors, typeName);
                     }
 
                     ctor = type.IsValueType
@@ -843,8 +852,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                 if (ctor is null)
                 {
-                    diagnosticDescriptor = ParserDiagnostics.MissingPublicInstanceConstructor;
-                    objectSpec.InitExceptionMessage = string.Format(ExceptionMessages.MissingPublicInstanceConstructor, typeName);
+                    diagnosticDescriptor = Diagnostics.MissingPublicInstanceConstructor;
+                    objectSpec.InitExceptionMessage = string.Format(Emitter.ExceptionMessages.MissingPublicInstanceConstructor, typeName);
                 }
 
                 if (diagnosticDescriptor is not null)
@@ -869,7 +878,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                             TypeSpec? propertyTypeSpec = GetOrCreateTypeSpec(property.Type);
                             if (propertyTypeSpec is null)
                             {
-                                _context.ReportDiagnostic(Diagnostic.Create(ParserDiagnostics.PropertyNotSupported, location, new string[] { propertyName, type.ToDisplayString() }));
+                                _context.ReportDiagnostic(Diagnostic.Create(Diagnostics.PropertyNotSupported, location, new string[] { propertyName, type.ToDisplayString() }));
                             }
                             else
                             {
@@ -914,7 +923,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
                     if (invalidParameters.Count > 0)
                     {
-                        objectSpec.InitExceptionMessage = string.Format(ExceptionMessages.CannotBindToConstructorParameter, typeName, FormatParams(invalidParameters));
+                        objectSpec.InitExceptionMessage = string.Format(Emitter.ExceptionMessages.CannotBindToConstructorParameter, typeName, FormatParams(invalidParameters));
                     }
                     else if (missingParameters.Count > 0)
                     {
@@ -924,7 +933,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                         }
                         else
                         {
-                            objectSpec.InitExceptionMessage = string.Format(ExceptionMessages.ConstructorParametersDoNotMatchProperties, typeName, FormatParams(missingParameters));
+                            objectSpec.InitExceptionMessage = string.Format(Emitter.ExceptionMessages.ConstructorParametersDoNotMatchProperties, typeName, FormatParams(missingParameters));
                         }
                     }
 
@@ -1021,16 +1030,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
                 return SymbolEqualityComparer.Default.Equals(type, @interface);
             }
 
-            public static bool ContainsGenericParameters(INamedTypeSymbol type)
+            public static bool ContainsGenericParameters(ITypeSymbol type)
             {
-                if (!type.IsGenericType)
+                if (type is not INamedTypeSymbol { IsGenericType: true } genericType)
                 {
                     return false;
                 }
 
-                foreach (ITypeSymbol typeArg in type.TypeArguments)
+                foreach (ITypeSymbol typeArg in genericType.TypeArguments)
                 {
-                    if (typeArg.TypeKind == TypeKind.TypeParameter)
+                    if (typeArg.TypeKind is TypeKind.TypeParameter or TypeKind.Error ||
+                        ContainsGenericParameters(typeArg))
                     {
                         return true;
                     }
index 37b2283..cc0787e 100644 (file)
@@ -54,7 +54,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
 
             if (compilationData?.LanguageVersionIsSupported != true)
             {
-                context.ReportDiagnostic(Diagnostic.Create(ParserDiagnostics.LanguageVersionNotSupported, location: null));
+                context.ReportDiagnostic(Diagnostic.Create(Parser.Diagnostics.LanguageVersionNotSupported, location: null));
                 return;
             }
 
diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter.ExceptionMessages.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter.ExceptionMessages.cs
new file mode 100644 (file)
index 0000000..696af27
--- /dev/null
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
+{
+    public sealed partial class ConfigurationBindingGenerator
+    {
+        private sealed partial class Emitter
+        {
+            // Runtime exception messages; not localized so we keep them in source.
+            internal static class ExceptionMessages
+            {
+                public const string CannotBindToConstructorParameter = "Cannot create instance of type '{0}' because one or more parameters cannot be bound to. Constructor parameters cannot be declared as in, out, or ref. Invalid parameters are: '{1}'";
+                public const string CannotSpecifyBindNonPublicProperties = "The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.";
+                public const string ConstructorParametersDoNotMatchProperties = "Cannot create instance of type '{0}' because one or more parameters cannot be bound to. Constructor parameters must have corresponding properties. Fields are not supported. Missing properties are: '{1}'";
+                public const string FailedBinding = "Failed to convert configuration value at '{0}' to type '{1}'.";
+                public const string MissingConfig = "'{0}' was set on the provided {1}, but the following properties were not found on the instance of {2}: {3}";
+                public const string MissingPublicInstanceConstructor = "Cannot create instance of type '{0}' because it is missing a public instance constructor.";
+                public const string MultipleParameterizedConstructors = "Cannot create instance of type '{0}' because it has multiple public parameterized constructors.";
+                public const string ParameterHasNoMatchingConfig = "Cannot create instance of type '{0}' because parameter '{1}' has no matching config. Each parameter in the constructor that does not have a default value must have a corresponding config entry.";
+                public const string TypeNotDetectedAsInput = "Unable to bind to type '{0}': generator did not detect the type as input.";
+            }
+        }
+    }
+}
diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/ExceptionMessages.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/ExceptionMessages.cs
deleted file mode 100644 (file)
index 223c19c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
-{
-    // Runtime exception messages; not localized so we keep them in source.
-    internal static class ExceptionMessages
-    {
-        public const string CannotBindToConstructorParameter = "Cannot create instance of type '{0}' because one or more parameters cannot be bound to. Constructor parameters cannot be declared as in, out, or ref. Invalid parameters are: '{1}'";
-        public const string CannotSpecifyBindNonPublicProperties = "The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.";
-        public const string ConstructorParametersDoNotMatchProperties = "Cannot create instance of type '{0}' because one or more parameters cannot be bound to. Constructor parameters must have corresponding properties. Fields are not supported. Missing properties are: '{1}'";
-        public const string FailedBinding = "Failed to convert configuration value at '{0}' to type '{1}'.";
-        public const string MissingConfig = "'{0}' was set on the provided {1}, but the following properties were not found on the instance of {2}: {3}";
-        public const string MissingPublicInstanceConstructor = "Cannot create instance of type '{0}' because it is missing a public instance constructor.";
-        public const string MultipleParameterizedConstructors = "Cannot create instance of type '{0}' because it has multiple public parameterized constructors.";
-        public const string ParameterBeingBoundToIsUnnamed = "Cannot create instance of type '{0}' because one or more parameters are unnamed.";
-        public const string ParameterHasNoMatchingConfig = "Cannot create instance of type '{0}' because parameter '{1}' has no matching config. Each parameter in the constructor that does not have a default value must have a corresponding config entry.";
-        public const string TypeNotDetectedAsInput = "Unable to bind to type '{0}': generator did not detect the type as input.";
-        public const string TypeNotSupportedAsInput = "Unable to bind to type '{0}': generator does not support this type as input to this method.";
-    }
-}
diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser.Diagnostics.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser.Diagnostics.cs
new file mode 100644 (file)
index 0000000..91944a3
--- /dev/null
@@ -0,0 +1,67 @@
+// 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 Microsoft.CodeAnalysis;
+
+namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
+{
+    public sealed partial class ConfigurationBindingGenerator
+    {
+        private sealed partial class Parser
+        {
+            internal static class Diagnostics
+            {
+                public static DiagnosticDescriptor TypeNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.TypeNotSupported));
+                public static DiagnosticDescriptor MissingPublicInstanceConstructor { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.MissingPublicInstanceConstructor));
+                public static DiagnosticDescriptor CollectionNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.CollectionNotSupported));
+                public static DiagnosticDescriptor DictionaryKeyNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.DictionaryKeyNotSupported));
+                public static DiagnosticDescriptor ElementTypeNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.ElementTypeNotSupported));
+                public static DiagnosticDescriptor MultipleParameterizedConstructors { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.MultipleParameterizedConstructors));
+                public static DiagnosticDescriptor MultiDimArraysNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.MultiDimArraysNotSupported));
+                public static DiagnosticDescriptor NullableUnderlyingTypeNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.NullableUnderlyingTypeNotSupported));
+
+                public static DiagnosticDescriptor PropertyNotSupported { get; } = new DiagnosticDescriptor(
+                    id: "SYSLIB1101",
+                    title: new LocalizableResourceString(nameof(SR.PropertyNotSupportedTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
+                    messageFormat: new LocalizableResourceString(nameof(SR.PropertyNotSupportedMessageFormat), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
+                    category: ProjectName,
+                    defaultSeverity: DiagnosticSeverity.Warning,
+                    isEnabledByDefault: true);
+
+                public static DiagnosticDescriptor LanguageVersionNotSupported { get; } = new DiagnosticDescriptor(
+                    id: "SYSLIB1102",
+                    title: new LocalizableResourceString(nameof(SR.LanguageVersionIsNotSupportedTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
+                    messageFormat: new LocalizableResourceString(nameof(SR.Language_VersionIsNotSupportedMessageFormat), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
+                    category: ProjectName,
+                    defaultSeverity: DiagnosticSeverity.Error,
+                    isEnabledByDefault: true);
+
+                public static DiagnosticDescriptor ValueTypesInvalidForBind { get; } = new DiagnosticDescriptor(
+                    id: "SYSLIB1103",
+                    title: new LocalizableResourceString(nameof(SR.ValueTypesInvalidForBindTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
+                    messageFormat: new LocalizableResourceString(nameof(SR.ValueTypesInvalidForBindMessageFormat), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
+                    category: ProjectName,
+                    defaultSeverity: DiagnosticSeverity.Warning,
+                    isEnabledByDefault: true);
+
+                public static DiagnosticDescriptor CouldNotDetermineTypeInfo { get; } = new DiagnosticDescriptor(
+                    id: "SYSLIB1104",
+                    title: new LocalizableResourceString(nameof(SR.CouldNotDetermineTypeInfoTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
+                    messageFormat: new LocalizableResourceString(nameof(SR.CouldNotDetermineTypeInfoMessageFormat), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
+                    category: ProjectName,
+                    defaultSeverity: DiagnosticSeverity.Warning,
+                    isEnabledByDefault: true);
+
+                private static DiagnosticDescriptor CreateTypeNotSupportedDescriptor(string nameofLocalizableMessageFormat) =>
+                    new DiagnosticDescriptor(
+                    id: "SYSLIB1100",
+                    title: new LocalizableResourceString(nameof(SR.TypeNotSupportedTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
+                    messageFormat: new LocalizableResourceString(nameofLocalizableMessageFormat, SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
+                    category: ProjectName,
+                    defaultSeverity: DiagnosticSeverity.Warning,
+                    isEnabledByDefault: true);
+            }
+        }
+    }
+}
diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/ParserDiagnostics.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/ParserDiagnostics.cs
deleted file mode 100644 (file)
index be26314..0000000
+++ /dev/null
@@ -1,45 +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 Microsoft.CodeAnalysis;
-
-namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
-{
-    internal static class ParserDiagnostics
-    {
-        public static DiagnosticDescriptor TypeNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.TypeNotSupported));
-        public static DiagnosticDescriptor MissingPublicInstanceConstructor { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.MissingPublicInstanceConstructor));
-        public static DiagnosticDescriptor CollectionNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.CollectionNotSupported));
-        public static DiagnosticDescriptor DictionaryKeyNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.DictionaryKeyNotSupported));
-        public static DiagnosticDescriptor ElementTypeNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.ElementTypeNotSupported));
-        public static DiagnosticDescriptor MultipleParameterizedConstructors { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.MultipleParameterizedConstructors));
-        public static DiagnosticDescriptor MultiDimArraysNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.MultiDimArraysNotSupported));
-        public static DiagnosticDescriptor NullableUnderlyingTypeNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.NullableUnderlyingTypeNotSupported));
-
-        public static DiagnosticDescriptor PropertyNotSupported { get; } = new DiagnosticDescriptor(
-            id: "SYSLIB1101",
-            title: new LocalizableResourceString(nameof(SR.PropertyNotSupportedTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
-            messageFormat: new LocalizableResourceString(nameof(SR.PropertyNotSupportedMessageFormat), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
-            category: ConfigurationBindingGenerator.ProjectName,
-            defaultSeverity: DiagnosticSeverity.Warning,
-            isEnabledByDefault: true);
-
-        public static DiagnosticDescriptor LanguageVersionNotSupported { get; } = new DiagnosticDescriptor(
-            id: "SYSLIB1102",
-            title: new LocalizableResourceString(nameof(SR.LanguageVersionIsNotSupportedTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
-            messageFormat: new LocalizableResourceString(nameof(SR.Language_VersionIsNotSupportedMessageFormat), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
-            category: ConfigurationBindingGenerator.ProjectName,
-            defaultSeverity: DiagnosticSeverity.Error,
-            isEnabledByDefault: true);
-
-        private static DiagnosticDescriptor CreateTypeNotSupportedDescriptor(string nameofLocalizableMessageFormat) =>
-            new DiagnosticDescriptor(
-            id: "SYSLIB1100",
-            title: new LocalizableResourceString(nameof(SR.TypeNotSupportedTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
-            messageFormat: new LocalizableResourceString(nameofLocalizableMessageFormat, SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
-            category: ConfigurationBindingGenerator.ProjectName,
-            defaultSeverity: DiagnosticSeverity.Warning,
-            isEnabledByDefault: true);
-    }
-}
index c3929ec..65150ea 100644 (file)
     <Compile Include="ConfigurationBindingGenerator.cs" />
     <Compile Include="ConfigurationBindingGenerator.Emitter.cs" />
     <Compile Include="ConfigurationBindingGenerator.Parser.cs" />
+    <Compile Include="Helpers\Emitter.ExceptionMessages.cs" />
     <Compile Include="Helpers\Emitter.Helpers.cs" />
-    <Compile Include="Helpers\ExceptionMessages.cs" />
-    <Compile Include="Helpers\KnownTypeSymbols.cs" />
-    <Compile Include="Helpers\ParserDiagnostics.cs" />
+    <Compile Include="Helpers\Parser.Diagnostics.cs" />
     <Compile Include="Helpers\SourceWriter.cs" />
     <Compile Include="Model\BinderInvocationOperation.cs" />
     <Compile Include="Model\BinderMethodSpecifier.cs" />
     <Compile Include="Model\CollectionSpec.cs" />
     <Compile Include="Model\ConfigurationSectionSpec.cs" />
     <Compile Include="Model\InitializationStrategy.cs" />
+    <Compile Include="Model\KnownTypeSymbols.cs" />
     <Compile Include="Model\NullableSpec.cs" />
     <Compile Include="Model\ObjectSpec.cs" />
     <Compile Include="Model\ParameterSpec.cs" />
index 9bf3877..3019139 100644 (file)
   <data name="CollectionNotSupported" xml:space="preserve">
     <value>The collection type is not supported: '{0}'.</value>
   </data>
+  <data name="CouldNotDetermineTypeInfoMessageFormat" xml:space="preserve">
+    <value>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</value>
+  </data>
+  <data name="CouldNotDetermineTypeInfoTitle" xml:space="preserve">
+    <value>The target type for a binder call could not be determined</value>
+  </data>
   <data name="DictionaryKeyNotSupported" xml:space="preserve">
     <value>The dictionary key type is not supported: '{0}'.</value>
   </data>
   <data name="TypeNotSupportedTitle" xml:space="preserve">
     <value>Did not generate binding logic for a type</value>
   </data>
+  <data name="ValueTypesInvalidForBindMessageFormat" xml:space="preserve">
+    <value>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</value>
+  </data>
+  <data name="ValueTypesInvalidForBindTitle" xml:space="preserve">
+    <value>Value types are invalid inputs to configuration 'Bind' methods</value>
+  </data>
 </root>
\ No newline at end of file
index 97ffb53..6134452 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">Typ kolekce se nepodporuje: „{0}“.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">Typ klíče slovníku se nepodporuje:„{0}“.</target>
         <target state="translated">Negenerovala se logika vazby pro typ</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index 1156ad0..dfd3bad 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">Der Sammlungstyp wird nicht unterstützt: "{0}".</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">Der Wörterbuchschlüsseltyp wird nicht unterstützt: "{0}".</target>
         <target state="translated">Für einen Typ wurde keine Bindungslogik generiert</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index fbd7d3f..9ac5323 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">No se admite el tipo de colección: "{0}".</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">No se admite el tipo de clave de diccionario: "{0}".</target>
         <target state="translated">No se ha generado la lógica de enlace para un tipo.</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index 98e5ada..6c91012 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">Le type de collection n‘est pas pris en charge : ‘{0}‘.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">Le type de clé du dictionnaire n’est pas pris en charge : ‘{0}‘.</target>
         <target state="translated">La logique de liaison n’a pas été générée pour un type</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index 11d35bf..5a3817f 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">Il tipo di raccolta non è supportato: '{0}'.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">Il tipo di chiave del dizionario non è supportato: '{0}'.</target>
         <target state="translated">Non è stata generata la logica di binding per un tipo.</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index ecce419..98de7b5 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">コレクション型はサポートされていません: '{0}'。</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">辞書キー型はサポートされていません: '{0}'。</target>
         <target state="translated">型のバインディング ロジックを生成しませんでした</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index f968f1b..ee50853 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">컬렉션 유형이 지원되지 않습니다: '{0}'.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">사전 키 유형이 지원되지 않습니다: '{0}'.</target>
         <target state="translated">형식에 대한 바인딩 논리를 생성하지 않았습니다.</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index e4fc199..d59f49b 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">Typ kolekcji nie jest obsługiwany: „{0}”.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">Typ klucza słownika nie jest obsługiwany: „{0}”.</target>
         <target state="translated">Nie wygenerowano logiki powiązania dla typu</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index 6ede0ed..022102b 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">O tipo de coleção não é compatível: '{0}'.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">O tipo de chave do dicionário não é suportado: '{0}'.</target>
         <target state="translated">Não gerou lógica de ligação para um tipo</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index ffe9f57..18fe55a 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">Тип коллекции не поддерживается: "{0}".</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">Тип ключа словаря не поддерживается: "{0}".</target>
         <target state="translated">Не создана логика привязки для типа</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index af63c73..9047cd4 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">Koleksiyon türü desteklenmiyor: '{0}'.</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">Sözlük anahtarı türü desteklenmiyor: '{0}'.</target>
         <target state="translated">Bir tür için bağlama mantığı oluşturulmadı</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index a6e243f..1d6e0a1 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">不支持此集合类型 '{0}'。</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">不支持此字典密钥类型: '{0}'。</target>
         <target state="translated">没有为类型生成绑定逻辑</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index 92a79c8..613219a 100644 (file)
@@ -7,6 +7,16 @@
         <target state="translated">不支援集合類型: '{0}'。</target>
         <note />
       </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoMessageFormat">
+        <source>Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</source>
+        <target state="new">Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="CouldNotDetermineTypeInfoTitle">
+        <source>The target type for a binder call could not be determined</source>
+        <target state="new">The target type for a binder call could not be determined</target>
+        <note />
+      </trans-unit>
       <trans-unit id="DictionaryKeyNotSupported">
         <source>The dictionary key type is not supported: '{0}'.</source>
         <target state="translated">不支援字典索引鍵類型: '{0}'。</target>
         <target state="translated">未產生類型的繫結邏輯</target>
         <note />
       </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindMessageFormat">
+        <source>Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</source>
+        <target state="new">Binding logic was not generated for a binder call with target type '{0}'. Value types are invalid inputs to configuration 'Bind' methods.</target>
+        <note />
+      </trans-unit>
+      <trans-unit id="ValueTypesInvalidForBindTitle">
+        <source>Value types are invalid inputs to configuration 'Bind' methods</source>
+        <target state="new">Value types are invalid inputs to configuration 'Bind' methods</target>
+        <note />
+      </trans-unit>
     </body>
   </file>
 </xliff>
\ No newline at end of file
index a184211..fadaa1c 100644 (file)
@@ -216,49 +216,57 @@ namespace Microsoft.Extensions
             Assert.Equal("val_3", options[KeyUintEnum.ghi]);
         }
 
-        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))] // Reflection fallback: generic type info not supported with source gen.
+        // Reflection fallback: generic type info not supported with source gen.
+        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))]
         public void GetSByteDictionary()
         {
             GetIntDictionaryT<sbyte>(0, 1, 2);
         }
 
-        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))] // Reflection fallback: generic type info not supported with source gen.
+        // Reflection fallback: generic type info not supported with source gen.
+        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))]
         public void GetByteDictionary()
         {
             GetIntDictionaryT<byte>(0, 1, 2);
         }
 
-        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))] // Reflection fallback: generic type info not supported with source gen.
+        // Reflection fallback: generic type info not supported with source gen.
+        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))]
         public void GetShortDictionary()
         {
             GetIntDictionaryT<short>(0, 1, 2);
         }
 
-        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))] // Reflection fallback: generic type info not supported with source gen.
+        // Reflection fallback: generic type info not supported with source gen.
+        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))]
         public void GetUShortDictionary()
         {
             GetIntDictionaryT<ushort>(0, 1, 2);
         }
 
-        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))] // Reflection fallback: generic type info not supported with source gen.
+        // Reflection fallback: generic type info not supported with source gen.
+        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))]
         public void GetIntDictionary()
         {
             GetIntDictionaryT<int>(0, 1, 2);
         }
 
-        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))] // Reflection fallback: generic type info not supported with source gen.
+        // Reflection fallback: generic type info not supported with source gen.
+        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))]
         public void GetUIntDictionary()
         {
             GetIntDictionaryT<uint>(0, 1, 2);
         }
 
-        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))] // Reflection fallback: generic type info not supported with source gen.
+        // Reflection fallback: generic type info not supported with source gen.
+        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))]
         public void GetLongDictionary()
         {
             GetIntDictionaryT<long>(0, 1, 2);
         }
 
-        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))] // Reflection fallback: generic type info not supported with source gen.
+        // Reflection fallback: generic type info not supported with source gen.
+        [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))]
         public void GetULongDictionary()
         {
             GetIntDictionaryT<ulong>(0, 1, 2);
index 6e30c74..c2068fe 100644 (file)
@@ -637,5 +637,23 @@ namespace Microsoft.Extensions
             public TimeOnly Prop22 { get; set; }
 #endif
         }
+
+        public class ClassWithParameterlessAndParameterizedCtor
+        {
+            public ClassWithParameterlessAndParameterizedCtor() => MyInt = 1;
+
+            public ClassWithParameterlessAndParameterizedCtor(int myInt) => MyInt = 10;
+
+            public int MyInt { get; }
+        }
+
+        public struct StructWithParameterlessAndParameterizedCtor
+        {
+            public StructWithParameterlessAndParameterizedCtor() => MyInt = 1;
+
+            public StructWithParameterlessAndParameterizedCtor(int myInt) => MyInt = 10;
+
+            public int MyInt { get; }
+        }
     }
 }
index ec29f21..7537749 100644 (file)
@@ -1855,22 +1855,20 @@ namespace Microsoft.Extensions
             Assert.Equal(1, obj.MyInt);
         }
 
-        public class ClassWithParameterlessAndParameterizedCtor
-        {
-            public ClassWithParameterlessAndParameterizedCtor() => MyInt = 1;
-
-            public ClassWithParameterlessAndParameterizedCtor(int myInt) => MyInt = 10;
-
-            public int MyInt { get; }
-        }
-
-        public struct StructWithParameterlessAndParameterizedCtor
+        [Fact]
+        public void BindRootStructIsNoOp()
         {
-            public StructWithParameterlessAndParameterizedCtor() => MyInt = 1;
-
-            public StructWithParameterlessAndParameterizedCtor(int myInt) => MyInt = 10;
+            var configuration = TestHelpers.GetConfigurationFromJsonString("""
+                {
+                    "Int32": 9,
+                    "Boolean": true,
+                }
+                """);
 
-            public int MyInt { get; }
+            StructWithNestedStructs.DeeplyNested obj = new();
+            configuration.Bind(obj);
+            Assert.Equal(0, obj.Int32);
+            Assert.False(obj.Boolean);
         }
     }
 }
index 1f878cf..8296ef6 100644 (file)
@@ -23,6 +23,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
     [ActiveIssue("https://github.com/dotnet/runtime/issues/52062", TestPlatforms.Browser)]
     public class ConfigurationBindingSourceGeneratorTests
     {
+        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 const string BindCallSampleCode = @"
 using System.Collections.Generic;
 using Microsoft.Extensions.Configuration;
@@ -301,8 +309,8 @@ public class Program
             await VerifyAgainstBaselineUsingFile("TestCollectionsGen.generated.txt", testSourceCode, assessDiagnostics: (d) =>
             {
                 Assert.Equal(6, d.Length);
-                Test(d.Where(diagnostic => diagnostic.Id is "SYSLIB1100"), "Did not generate binding logic for a type");
-                Test(d.Where(diagnostic => diagnostic.Id is "SYSLIB1101"), "Did not generate binding logic for a property on a type");
+                Test(d.Where(diagnostic => diagnostic.Id == Diagnostics.TypeNotSupported.Id), Diagnostics.TypeNotSupported.Title);
+                Test(d.Where(diagnostic => diagnostic.Id == Diagnostics.PropertyNotSupported.Id), Diagnostics.PropertyNotSupported.Title);
 
                 static void Test(IEnumerable<Diagnostic> d, string expectedTitle)
                 {
@@ -316,6 +324,146 @@ public class Program
             });
         }
 
+        [Fact]
+        public async Task ValueTypesAreInvalidAsBindInputs()
+        {
+            string source = """
+                using System;
+                using System.Collections.Generic;
+                using Microsoft.Extensions.Configuration;
+                
+                public class Program
+                {
+                       public static void Main()
+                       {
+                               ConfigurationBuilder configurationBuilder = new();
+                               IConfigurationRoot config = configurationBuilder.Build();
+
+                        int myInt = 1
+                               config.Bind(myInt);
+                        int? myNInt = 2;
+                        config.Bind(myNInt)
+
+                        var myStruct = new MyStruct()
+                        config.Bind(myStruct, options => { })
+                        MyStruct? myNStruct = new();
+                        config.Bind(myNStruct, options => { });
+
+                        var myRecordStruct = new MyRecordStruct();
+                        config.Bind("key", myRecordStruct);
+                        MyRecordStruct? myNRecordStruct = new();
+                        config.Bind("key", myNRecordStruct);
+
+                        Memory<int> memory = new(new int[] {1, 2, 3});
+                        config.Bind(memory);
+                       }
+
+                    public struct MyStruct { }
+                    public record struct MyRecordStruct { }
+                }
+                """;
+
+            var (d, r) = await RunGenerator(source);
+            Assert.Empty(r);
+            Assert.Equal(7, d.Count());
+
+            foreach (Diagnostic diagnostic in d)
+            {
+                Assert.True(diagnostic.Id == Diagnostics.ValueTypesInvalidForBind.Id);
+                Assert.Contains(Diagnostics.ValueTypesInvalidForBind.Title, diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture));
+                Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity);
+                Assert.NotNull(diagnostic.Location);
+            }
+        }
+
+        [Fact]
+        public async Task InvalidRootMethodInputTypes()
+        {
+            string source = """
+                using System.Collections.Generic;
+                using Microsoft.Extensions.Configuration;
+
+                public class Program
+                {
+                    public static void Main()
+                    {
+                        ConfigurationBuilder configurationBuilder = new();
+                        IConfigurationRoot config = configurationBuilder.Build();
+
+                        config.GetValue(typeof(int*), "");
+                        config.Get<Dictionary<string, T>>();
+                    }
+
+                    public struct MyStruct { }
+                    public record struct MyRecordStruct { }
+                }
+                """;
+
+            var (d, r) = await RunGenerator(source);
+            Assert.Empty(r);
+            Assert.Equal(2, d.Count());
+
+            foreach (Diagnostic diagnostic in d)
+            {
+                Assert.True(diagnostic.Id == Diagnostics.CouldNotDetermineTypeInfo.Id);
+                Assert.Contains(Diagnostics.CouldNotDetermineTypeInfo.Title, diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture));
+                Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity);
+                Assert.NotNull(diagnostic.Location);
+            }
+        }
+
+        [Fact]
+        public async Task CannotDetermineTypeInfo()
+        {
+            string source = """
+                using Microsoft.AspNetCore.Builder;
+                using Microsoft.Extensions.Configuration;
+                using Microsoft.Extensions.DependencyInjection;
+                
+                public class Program
+                {
+                       public static void Main()
+                       {
+                               ConfigurationBuilder configurationBuilder = new();
+                               IConfiguration config = configurationBuilder.Build();
+                
+                               PerformGenericBinderCalls<MyClass>(config);
+                       }
+
+                    public static void PerformGenericBinderCalls<T>(IConfiguration config) where T : class
+                    {
+                        config.Get<T>();
+                        config.Get<T>(binderOptions => { });
+                        config.GetValue<T>("key");
+                        config.GetValue<T>("key", default(T));
+
+                        IConfigurationSection section = config.GetSection("MySection");
+                               ServiceCollection services = new();
+                        services.Configure<T>(section);
+                    }
+
+                    private void BindOptions(IConfiguration config, object? instance)
+                    {
+                        config.Bind(instance);
+                    }
+
+                    public class MyClass { }
+                }
+                """;
+
+            var (d, r) = await RunGenerator(source);
+            Assert.Empty(r);
+            Assert.Equal(5, d.Count());
+
+            foreach (Diagnostic diagnostic in d)
+            {
+                Assert.True(diagnostic.Id == Diagnostics.CouldNotDetermineTypeInfo.Id);
+                Assert.Contains(Diagnostics.CouldNotDetermineTypeInfo.Title, diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture));
+                Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity);
+                Assert.NotNull(diagnostic.Location);
+            }
+        }
+
         private async Task VerifyAgainstBaselineUsingFile(
             string filename,
             string testSourceCode,
index 9eb0e60..99de2ce 100644 (file)
@@ -4,8 +4,8 @@
     <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
     <EnableDefaultItems>true</EnableDefaultItems>
     <DefineConstants>$(DefineConstants);BUILDING_SOURCE_GENERATOR_TESTS;ROSLYN4_0_OR_GREATER;ROSLYN4_4_OR_GREATER</DefineConstants>
-    <!-- Type not supported; property on type not suppported. -->
-    <NoWarn>SYSLIB1100,SYSLIB1101</NoWarn>
+    <!-- Type not supported; property on type not suppported; value types invalid for bind; generator could not parse target type -->
+    <NoWarn>SYSLIB1100,SYSLIB1101,SYSLIB1103,SYSLIB1104</NoWarn>
     <!-- The SDK disables the configuration binding generator by default no matter how it was referenced, so we need to enable it here for testing. -->
     <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
   </PropertyGroup>