Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set minimum language version allowed by config binding generator #83996

Merged
merged 2 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions docs/project/list-of-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,23 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL
| __`SYSLIB1099`__ | _`SYSLIB1092`-`SYSLIB1099` reserved for Microsoft.Interop.ComInteropGenerator._ |
| __`SYSLIB1100`__ | Configuration binding generator: type is not supported. |
| __`SYSLIB1101`__ | Configuration binding generator: property on type is not supported. |
| __`SYSLIB1102`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1103`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1104`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1105`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1106`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1107`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1108`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1109`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1110`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1111`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1112`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1113`__ | *_`SYSLIB1101`-`SYSLIB1113` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`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.* |
| __`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.* |
| __`SYSLIB1108`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1109`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1110`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1111`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1112`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1113`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1114`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1115`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1116`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1117`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1118`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |


### Diagnostic Suppressions (`SYSLIBSUPPRESS****`)
Expand Down
11 changes: 8 additions & 3 deletions src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ internal static class RoslynTestUtils
/// </summary>
/// <param name="references">Assembly references to include in the project.</param>
/// <param name="includeBaseReferences">Whether to include references to the BCL assemblies.</param>
public static Project CreateTestProject(IEnumerable<Assembly>? references, bool includeBaseReferences = true)
public static Project CreateTestProject(
IEnumerable<Assembly>? references,
bool includeBaseReferences = true,
LanguageVersion langVersion = LanguageVersion.Preview)
{
string corelib = Assembly.GetAssembly(typeof(object))!.Location;
string runtimeDir = Path.GetDirectoryName(corelib)!;
Expand All @@ -51,7 +54,8 @@ public static Project CreateTestProject(IEnumerable<Assembly>? references, bool
.AddSolution(SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create()))
.AddProject("Test", "test.dll", "C#")
.WithMetadataReferences(refs)
.WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Enable));
.WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Enable))
.WithParseOptions(new CSharpParseOptions(langVersion));
}

public static Task CommitChanges(this Project proj, params string[] ignorables)
Expand Down Expand Up @@ -149,9 +153,10 @@ public static TextSpan MakeSpan(string text, int spanNum)
IEnumerable<Assembly>? references,
IEnumerable<string> sources,
bool includeBaseReferences = true,
LanguageVersion langVersion = LanguageVersion.Preview,
CancellationToken cancellationToken = default)
{
Project proj = CreateTestProject(references, includeBaseReferences);
Project proj = CreateTestProject(references, includeBaseReferences, langVersion);
proj = proj.WithDocuments(sources);
Assert.True(proj.Solution.Workspace.TryApplyChanges(proj.Solution));
Compilation? comp = await proj!.GetCompilationAsync(CancellationToken.None).ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
Expand All @@ -18,15 +15,23 @@ public sealed partial class ConfigurationBindingSourceGenerator
title: new LocalizableResourceString(nameof(SR.TypeNotSupportedTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
messageFormat: new LocalizableResourceString(nameof(SR.TypeNotSupportedMessageFormat), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Configuration.Binder.SourceGeneration.SR)),
category: GeneratorProjectName,
defaultSeverity: DiagnosticSeverity.Info,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

private 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: GeneratorProjectName,
defaultSeverity: DiagnosticSeverity.Info,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

private 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: GeneratorProjectName,
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);

// Unlike sourcegen warnings, exception messages should not be localized so we keep them in source.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Immutable;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.DotnetRuntime.Extensions;
using Microsoft.CodeAnalysis.Operations;
Expand All @@ -19,23 +20,25 @@ public sealed partial class ConfigurationBindingSourceGenerator : IIncrementalGe
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
IncrementalValueProvider<KnownTypeData> compilationData =
IncrementalValueProvider<CompilationData?> compilationData =
context.CompilationProvider
.Select((compilation, _) => new KnownTypeData(compilation));
.Select((compilation, _) => compilation.Options is CSharpCompilationOptions options
? new CompilationData((CSharpCompilation)compilation)
: null);

IncrementalValuesProvider<BinderInvocationOperation> inputCalls = context.SyntaxProvider.CreateSyntaxProvider(
(node, _) => node is InvocationExpressionSyntax invocation,
(context, cancellationToken) => new BinderInvocationOperation(context, cancellationToken));

IncrementalValueProvider<(KnownTypeData, ImmutableArray<BinderInvocationOperation>)> inputData = compilationData.Combine(inputCalls.Collect());
IncrementalValueProvider<(CompilationData?, ImmutableArray<BinderInvocationOperation>)> inputData = compilationData.Combine(inputCalls.Collect());

context.RegisterSourceOutput(inputData, (spc, source) => Execute(source.Item1, source.Item2, spc));
}

/// <summary>
/// Generates source code to optimize binding with ConfigurationBinder.
/// </summary>
private static void Execute(KnownTypeData typeData, ImmutableArray<BinderInvocationOperation> inputCalls, SourceProductionContext context)
private static void Execute(CompilationData compilationData, ImmutableArray<BinderInvocationOperation> inputCalls, SourceProductionContext context)
{
#if LAUNCH_DEBUGGER
if (!System.Diagnostics.Debugger.IsAttached)
Expand All @@ -48,7 +51,13 @@ private static void Execute(KnownTypeData typeData, ImmutableArray<BinderInvocat
return;
}

Parser parser = new(context, typeData);
if (compilationData?.LanguageVersionIsSupported != true)
{
context.ReportDiagnostic(Diagnostic.Create(LanguageVersionNotSupported, location: null));
return;
}

Parser parser = new(context, compilationData.TypeData!);
SourceGenerationSpec? spec = parser.GetSourceGenerationSpec(inputCalls);
if (spec is not null)
{
Expand All @@ -57,6 +66,21 @@ private static void Execute(KnownTypeData typeData, ImmutableArray<BinderInvocat
}
}

private sealed record CompilationData
{
public bool LanguageVersionIsSupported { get; }
public KnownTypeData? TypeData { get; }

public CompilationData(CSharpCompilation compilation)
{
LanguageVersionIsSupported = compilation.LanguageVersion >= LanguageVersion.CSharp11;
if (LanguageVersionIsSupported)
{
TypeData = new KnownTypeData(compilation);
}
}
}

private sealed record KnownTypeData
{
public INamedTypeSymbol SymbolForGenericIList { get; }
Expand All @@ -75,7 +99,7 @@ private sealed record KnownTypeData
public INamedTypeSymbol? SymbolForISet { get; }
public INamedTypeSymbol? SymbolForList { get; }

public KnownTypeData(Compilation compilation)
public KnownTypeData(CSharpCompilation compilation)
{
SymbolForIEnumerable = compilation.GetSpecialType(SpecialType.System_Collections_IEnumerable);
SymbolForConfigurationKeyNameAttribute = compilation.GetBestTypeByMetadataName(TypeFullName.ConfigurationKeyNameAttribute);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,22 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Language VersionIsNotSupportedMessageFormat" xml:space="preserve">
<value>The project's language version has to be at least 'C# 11'.</value>
</data>
<data name="LanguageVersionIsNotSupportedTitle" xml:space="preserve">
<value>Language version is required to be at least C# 11</value>
</data>
<data name="PropertyNotSupportedMessageFormat" xml:space="preserve">
<value>Property '{0}' on type '{1}' is not supported.</value>
</data>
<data name="PropertyNotSupportedTitle" xml:space="preserve">
<value>Did not generate binding logic for a property on a type.</value>
<value>Did not generate binding logic for a property on a type</value>
</data>
<data name="TypeNotSupportedMessageFormat" xml:space="preserve">
<value>Type '{0}' is not supported: {1}.</value>
</data>
<data name="TypeNotSupportedTitle" xml:space="preserve">
<value>Did not generate binding logic for a type.</value>
<value>Did not generate binding logic for a type</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="cs" original="../Strings.resx">
<body>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="new">The project's language version has to be at least 'C# 11'.</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="new">Language version is required to be at least C# 11</target>
<note />
</trans-unit>
<trans-unit id="PropertyNotSupportedMessageFormat">
<source>Property '{0}' on type '{1}' is not supported.</source>
<target state="translated">Vlastnost „{0}“ u typu „{1}“ se nepodporuje.</target>
<note />
</trans-unit>
<trans-unit id="PropertyNotSupportedTitle">
<source>Did not generate binding logic for a property on a type.</source>
<target state="translated">Nevygenerovala se logika vazby pro vlastnost typu.</target>
<source>Did not generate binding logic for a property on a type</source>
<target state="needs-review-translation">Nevygenerovala se logika vazby pro vlastnost typu.</target>
<note />
</trans-unit>
<trans-unit id="TypeNotSupportedMessageFormat">
Expand All @@ -18,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="TypeNotSupportedTitle">
<source>Did not generate binding logic for a type.</source>
<target state="translated">Nevygenerovala se logika vazby pro typ.</target>
<source>Did not generate binding logic for a type</source>
<target state="needs-review-translation">Nevygenerovala se logika vazby pro typ.</target>
<note />
</trans-unit>
</body>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" source-language="en" target-language="de" original="../Strings.resx">
<body>
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
<source>The project's language version has to be at least 'C# 11'.</source>
<target state="new">The project's language version has to be at least 'C# 11'.</target>
<note />
</trans-unit>
<trans-unit id="LanguageVersionIsNotSupportedTitle">
<source>Language version is required to be at least C# 11</source>
<target state="new">Language version is required to be at least C# 11</target>
<note />
</trans-unit>
<trans-unit id="PropertyNotSupportedMessageFormat">
<source>Property '{0}' on type '{1}' is not supported.</source>
<target state="translated">Die Eigenschaft „{0}“ für den Typ „{1}“ wird nicht unterstützt.</target>
<note />
</trans-unit>
<trans-unit id="PropertyNotSupportedTitle">
<source>Did not generate binding logic for a property on a type.</source>
<target state="translated">Für eine Eigenschaft eines Typs wurde keine Bindungslogik generiert.</target>
<source>Did not generate binding logic for a property on a type</source>
<target state="needs-review-translation">Für eine Eigenschaft eines Typs wurde keine Bindungslogik generiert.</target>
<note />
</trans-unit>
<trans-unit id="TypeNotSupportedMessageFormat">
Expand All @@ -18,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="TypeNotSupportedTitle">
<source>Did not generate binding logic for a type.</source>
<target state="translated">Für einen Typ wurde keine Bindungslogik generiert.</target>
<source>Did not generate binding logic for a type</source>
<target state="needs-review-translation">Für einen Typ wurde keine Bindungslogik generiert.</target>
<note />
</trans-unit>
</body>
Expand Down
Loading