Skip to content

Commit 02891ce

Browse files
authored
Merge pull request #1140 from CommunityToolkit/dev/partial-props-support
Fix C# language version checks for `[ObservableProperty]`
2 parents 67889e8 + 27d43c1 commit 02891ce

File tree

14 files changed

+258
-54
lines changed

14 files changed

+258
-54
lines changed

dotnet.slnx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
<Solution>
2-
<Configurations>
3-
<Platform Name="Any CPU" />
4-
</Configurations>
52
<Folder Name="/Solution Items/">
63
<File Path=".editorconfig" />
74
<File Path=".gitattributes" />
@@ -40,9 +37,11 @@
4037
<Project Path="tests/CommunityToolkit.Mvvm.Roslyn4001.UnitTests/CommunityToolkit.Mvvm.Roslyn4001.UnitTests.csproj" />
4138
<Project Path="tests/CommunityToolkit.Mvvm.Roslyn4031.UnitTests/CommunityToolkit.Mvvm.Roslyn4031.UnitTests.csproj" />
4239
<Project Path="tests/CommunityToolkit.Mvvm.Roslyn4120.UnitTests/CommunityToolkit.Mvvm.Roslyn4120.UnitTests.csproj" />
40+
<Project Path="tests/CommunityToolkit.Mvvm.Roslyn5000.UnitTests/CommunityToolkit.Mvvm.Roslyn5000.UnitTests.csproj" />
4341
<Project Path="tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001.UnitTests.csproj" />
4442
<Project Path="tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031.UnitTests.csproj" />
4543
<Project Path="tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120.UnitTests.csproj" />
44+
<Project Path="tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000.UnitTests.csproj" />
4645
<Project Path="tests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests.shproj" />
4746
<Project Path="tests/CommunityToolkit.Mvvm.UnitTests/CommunityToolkit.Mvvm.UnitTests.shproj" />
4847
</Folder>
@@ -58,6 +57,7 @@
5857
<Project Path="src/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001.csproj" />
5958
<Project Path="src/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031.csproj" />
6059
<Project Path="src/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120/CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120.csproj" />
60+
<Project Path="src/CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000/CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000.csproj" />
6161
<Project Path="src/CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.shproj" />
6262
<Project Path="src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.csproj" />
6363
</Solution>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<Import Project="..\CommunityToolkit.Mvvm.SourceGenerators\CommunityToolkit.Mvvm.SourceGenerators.props" />
4+
<Import Project="..\CommunityToolkit.Mvvm.SourceGenerators\CommunityToolkit.Mvvm.SourceGenerators.projitems" Label="Shared" />
5+
6+
</Project>

src/CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.projitems

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\FieldWithOrphanedDependentObservablePropertyAttributesAnalyzer.cs" />
5858
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\FieldReferenceForObservablePropertyFieldAnalyzer.cs" />
5959
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\UnsupportedRoslynVersionForPartialPropertyAnalyzer.cs" />
60-
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\RequiresCSharpLanguageVersionPreviewAnalyzer.cs" />
60+
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\RequiresCSharpLanguageVersion14OrPreviewAnalyzer.cs" />
6161
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\InvalidPropertyLevelObservablePropertyAttributeAnalyzer.cs" />
6262
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\UseObservablePropertyOnPartialPropertyAnalyzer.cs" />
6363
<Compile Include="$(MSBuildThisFileDirectory)Diagnostics\Analyzers\UnsupportedCSharpLanguageVersionAnalyzer.cs" />

src/CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.props

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@
4141
<!-- Also define "ROSLYN_<MAJOR>_<MINOR>_OR_GREATER" build constants, so the generator code can multi-target whenever needed and add any required polyfills -->
4242
<DefineConstants Condition="$([MSBuild]::VersionGreaterThanOrEquals($(MvvmToolkitSourceGeneratorRoslynVersion), 4.3.1))">$(DefineConstants);ROSLYN_4_3_1_OR_GREATER</DefineConstants>
4343
<DefineConstants Condition="$([MSBuild]::VersionGreaterThanOrEquals($(MvvmToolkitSourceGeneratorRoslynVersion), 4.12.0))">$(DefineConstants);ROSLYN_4_12_0_OR_GREATER</DefineConstants>
44+
<DefineConstants Condition="$([MSBuild]::VersionGreaterThanOrEquals($(MvvmToolkitSourceGeneratorRoslynVersion), 5.0.0))">$(DefineConstants);ROSLYN_5_0_0_OR_GREATER</DefineConstants>
4445

4546
<!-- Disable the removed rules analyzer for older Roslyn versions (as we might not support all diagnostics) -->
46-
<NoWarn Condition="$([MSBuild]::VersionLessThan($(MvvmToolkitSourceGeneratorRoslynVersion), 4.12.0))">$(NoWarn);RS2003</NoWarn>
47+
<NoWarn Condition="$([MSBuild]::VersionLessThan($(MvvmToolkitSourceGeneratorRoslynVersion), 5.0.0))">$(NoWarn);RS2003</NoWarn>
4748
</PropertyGroup>
4849

4950
<ItemGroup>

src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.Execute.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,18 @@ public static bool IsCandidateValidForCompilation(MemberDeclarationSyntax node,
8080
return false;
8181
}
8282

83-
// If the target is a property, we only support using C# preview.
84-
// This is because the generator is relying on the 'field' keyword.
85-
if (node is PropertyDeclarationSyntax && !semanticModel.Compilation.IsLanguageVersionPreview())
86-
{
83+
// If the target is a property, we must either be using C# preview, or C# 14 or above. When we're using
84+
// an older version of Roslyn, we know properties will never be supported anyway, so we have nothing to
85+
// check. When we add Roslyn 18.0 support, we can also update this check to check for at least C# 14.
86+
if (node is PropertyDeclarationSyntax)
87+
{
88+
#if ROSLYN_5_0_0_OR_GREATER
89+
return semanticModel.Compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp14);
90+
#elif ROSLYN_4_12_0_OR_GREATER
91+
return semanticModel.Compilation.IsLanguageVersionPreview();
92+
#else
8793
return false;
94+
#endif
8895
}
8996

9097
// All other cases are supported, the syntax filter is already validating that
Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
namespace CommunityToolkit.Mvvm.SourceGenerators;
1616

1717
/// <summary>
18-
/// A diagnostic analyzer that generates errors when a property using <c>[ObservableProperty]</c> on a partial property is in a project with the C# language version not set to preview.
18+
/// A diagnostic analyzer that generates errors when a property using <c>[ObservableProperty]</c> on a partial property is in a project with the C# language version not set to 14.0 or 'preview'.
1919
/// </summary>
2020
[DiagnosticAnalyzer(LanguageNames.CSharp)]
21-
public sealed class RequiresCSharpLanguageVersionPreviewAnalyzer : DiagnosticAnalyzer
21+
public sealed class RequiresCSharpLanguageVersion14OrPreviewAnalyzer : DiagnosticAnalyzer
2222
{
2323
/// <inheritdoc/>
24-
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [CSharpLanguageVersionIsNotPreviewForObservableProperty];
24+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [CSharpLanguageVersionIsNot14OrPreviewForObservableProperty];
2525

2626
/// <inheritdoc/>
2727
public override void Initialize(AnalysisContext context)
@@ -31,8 +31,12 @@ public override void Initialize(AnalysisContext context)
3131

3232
context.RegisterCompilationStartAction(static context =>
3333
{
34-
// If the language version is set to preview, we'll never emit diagnostics
34+
// If the language version is set to preview or if we are set to at least C# 14.0, we'll never emit diagnostics
35+
#if ROSLYN_5_0_0_OR_GREATER
36+
if (context.Compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp14))
37+
#else
3538
if (context.Compilation.IsLanguageVersionPreview())
39+
#endif
3640
{
3741
return;
3842
}
@@ -69,7 +73,7 @@ public override void Initialize(AnalysisContext context)
6973
if (context.Symbol.TryGetAttributeWithType(observablePropertySymbol, out AttributeData? observablePropertyAttribute))
7074
{
7175
context.ReportDiagnostic(Diagnostic.Create(
72-
CSharpLanguageVersionIsNotPreviewForObservableProperty,
76+
CSharpLanguageVersionIsNot14OrPreviewForObservableProperty,
7377
observablePropertyAttribute.GetLocation(),
7478
context.Symbol));
7579
}

src/CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -691,17 +691,17 @@ internal static class DiagnosticDescriptors
691691
/// <summary>
692692
/// Gets a <see cref="DiagnosticDescriptor"/> for the C# language version not being sufficient for <c>[ObservableProperty]</c> on partial properties.
693693
/// <para>
694-
/// Format: <c>"Using [ObservableProperty] on partial properties requires the C# language version to be set to 'preview', as support for the 'field' keyword is needed by the source generators to emit valid code (add <LangVersion>preview</LangVersion> to your .csproj/.props file)"</c>.
694+
/// Format: <c>"Using [ObservableProperty] on partial properties requires the C# language version to be set to at least 14.0 or 'preview', as support for the 'field' keyword is needed by the source generators to emit valid code (add <LangVersion>14.0</LangVersion> or <LangVersion>preview</LangVersion> to your .csproj/.props file)"</c>.
695695
/// </para>
696696
/// </summary>
697-
public static readonly DiagnosticDescriptor CSharpLanguageVersionIsNotPreviewForObservableProperty = new DiagnosticDescriptor(
697+
public static readonly DiagnosticDescriptor CSharpLanguageVersionIsNot14OrPreviewForObservableProperty = new DiagnosticDescriptor(
698698
id: "MVVMTK0041",
699-
title: "C# language version is not 'preview'",
700-
messageFormat: """Using [ObservableProperty] on partial properties requires the C# language version to be set to 'preview', as support for the 'field' keyword is needed by the source generators to emit valid code (add <LangVersion>preview</LangVersion> to your .csproj/.props file)""",
699+
title: "C# language version is not at least 14.0 or 'preview'",
700+
messageFormat: """Using [ObservableProperty] on partial properties requires the C# language version to be set to at least 14.0 or 'preview', as support for the 'field' keyword is needed by the source generators to emit valid code (add <LangVersion>14.0</LangVersion> or <LangVersion>preview</LangVersion> to your .csproj/.props file)""",
701701
category: typeof(ObservablePropertyGenerator).FullName,
702702
defaultSeverity: DiagnosticSeverity.Error,
703703
isEnabledByDefault: true,
704-
description: "The C# language version must be set to 'preview' when using [ObservableProperty] on partial properties for the source generators to emit valid code (the <LangVersion>preview</LangVersion> option must be set in the .csproj/.props file).",
704+
description: "The C# language version must be set to at least 14.0 or 'preview' when using [ObservableProperty] on partial properties for the source generators to emit valid code (the <LangVersion>14.0</LangVersion> or <LangVersion>preview</LangVersion> option must be set in the .csproj/.props file).",
705705
helpLinkUri: "https://aka.ms/mvvmtoolkit/errors/mvvmtk0041");
706706

707707
/// <summary>

src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/CompilationExtensions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ public static bool HasLanguageVersionAtLeastEqualTo(this Compilation compilation
2727
return ((CSharpCompilation)compilation).LanguageVersion >= languageVersion;
2828
}
2929

30+
/// <summary>
31+
/// Checks whether a given compilation (assumed to be for C#) is using a language version greater than a specified one.
32+
/// </summary>
33+
/// <param name="compilation">The <see cref="Compilation"/> to consider for analysis.</param>
34+
/// <param name="languageVersion">The minimum language version to check.</param>
35+
/// <returns>Whether <paramref name="compilation"/> is using a language version greater than the specified one.</returns>
36+
public static bool HasLanguageVersionGreaterThan(this Compilation compilation, LanguageVersion languageVersion)
37+
{
38+
return ((CSharpCompilation)compilation).LanguageVersion > languageVersion;
39+
}
40+
3041
/// <summary>
3142
/// Checks whether a given compilation (assumed to be for C#) is using the preview language version.
3243
/// </summary>

src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/DiagnosticsExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace CommunityToolkit.Mvvm.SourceGenerators.Extensions;
1313

1414
/// <summary>
15-
/// Extension methods for <see cref="GeneratorExecutionContext"/>, specifically for reporting diagnostics.
15+
/// Extension methods for working with diagnostics from incremental generator pipelines.
1616
/// </summary>
1717
internal static class DiagnosticsExtensions
1818
{

src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
<ProjectReference Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001.csproj" ReferenceOutputAssembly="false" />
7070
<ProjectReference Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031.csproj" ReferenceOutputAssembly="false" />
7171
<ProjectReference Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120.csproj" ReferenceOutputAssembly="false" />
72+
<ProjectReference Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000\CommunityToolkit.Mvvm.SourceGenerators.Roslyn5000.csproj" ReferenceOutputAssembly="false" />
7273
<ProjectReference Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4001\CommunityToolkit.Mvvm.CodeFixers.Roslyn4001.csproj" ReferenceOutputAssembly="false" />
7374
<ProjectReference Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4120\CommunityToolkit.Mvvm.CodeFixers.Roslyn4120.csproj" ReferenceOutputAssembly="false" />
7475
</ItemGroup>
@@ -123,9 +124,11 @@
123124
<None Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4001\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.SourceGenerators.dll" PackagePath="analyzers\dotnet\roslyn4.0\cs" Pack="true" Visible="false" />
124125
<None Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4031\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.SourceGenerators.dll" PackagePath="analyzers\dotnet\roslyn4.3\cs" Pack="true" Visible="false" />
125126
<None Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.SourceGenerators.dll" PackagePath="analyzers\dotnet\roslyn4.12\cs" Pack="true" Visible="false" />
127+
<None Include="..\CommunityToolkit.Mvvm.SourceGenerators.Roslyn4120\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.SourceGenerators.dll" PackagePath="analyzers\dotnet\roslyn5.0\cs" Pack="true" Visible="false" />
126128
<None Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4001\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.CodeFixers.dll" PackagePath="analyzers\dotnet\roslyn4.0\cs" Pack="true" Visible="false" />
127129
<None Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4001\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.CodeFixers.dll" PackagePath="analyzers\dotnet\roslyn4.3\cs" Pack="true" Visible="false" />
128130
<None Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4120\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.CodeFixers.dll" PackagePath="analyzers\dotnet\roslyn4.12\cs" Pack="true" Visible="false" />
131+
<None Include="..\CommunityToolkit.Mvvm.CodeFixers.Roslyn4120\bin\$(Configuration)\netstandard2.0\CommunityToolkit.Mvvm.CodeFixers.dll" PackagePath="analyzers\dotnet\roslyn5.0\cs" Pack="true" Visible="false" />
129132
</ItemGroup>
130133

131134
</Project>

0 commit comments

Comments
 (0)